Skip to content

Commit

Permalink
Merge pull request #364 from localcontexts/develop
Browse files Browse the repository at this point in the history
Update to fix NDL and some misc GIS errors
  • Loading branch information
birbjam authored Oct 10, 2024
2 parents 07f70b1 + 09dc3ae commit 529dfa3
Show file tree
Hide file tree
Showing 21 changed files with 811 additions and 87 deletions.
Empty file added api/templatetags/__init__.py
Empty file.
33 changes: 33 additions & 0 deletions api/templatetags/custom_api_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import os
from urllib.parse import urlparse
from urllib.parse import urljoin

from django import template


register = template.Library()


@register.simple_tag
def external_api(external_url: str) -> str:
"""
Tag converts an external_url into an internal_url
so the response can be mocked with a fixture.
Args:
external_url: Url to an external API resource.
Returns:
When TEST_LIVE_SERVER_DOMAIN is available, the url is transformed so
the external domain is swapped with the TEST_LIVE_SERVER_DOMAIN.
"""
test_live_server_domain = os.environ.get('TEST_LIVE_SERVER_DOMAIN')
if not test_live_server_domain:
return external_url
url_components = urlparse(external_url)

try:
# return the internal_url formed by the domain and url_components.path
return urljoin(test_live_server_domain, url_components.path)
except Exception:
return external_url
5 changes: 3 additions & 2 deletions helpers/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
path('download/community/support-letter/', views.download_community_support_letter, name="download-community-support-letter"),
path('community-boundary-view/<int:community_id>', views.community_boundary_view, name="community-boundary-view"),
path('project-boundary-view/<int:project_id>', views.project_boundary_view, name="project-boundary-view"),
path('boundary-view/', views.boundary_view, name="boundary-view"),
]
path('boundary-preview/', views.boundary_preview, name="boundary-preview"),
path('nld-data/', views.native_land_data, name="nld-data"),
]
16 changes: 15 additions & 1 deletion helpers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ def create_or_update_boundary(

raw_boundary_payload = post_data.get('boundary-payload')

if raw_boundary_payload in ['', None]:
if raw_boundary_payload in ['', '{}', None]:
return

data = json.loads(raw_boundary_payload)
Expand All @@ -479,3 +479,17 @@ def create_or_update_boundary(
# create boundary when it does not exist
entity.boundary = Boundary(coordinates=boundary_coordinates)
entity.boundary.save()


def retrieve_native_land_all_slug_data() -> dict:
"""
Does request to obtain all NLD slug data list
which includes the groups of coordinates for each slug
"""
url = (
'https://raw.githubusercontent.com/biocodellc/'
'localcontexts_json/refs/heads/main/data/'
'nativeland_slug_coordinates_description_dict.json'
)
response = requests.get(url)
return response.json()
81 changes: 57 additions & 24 deletions helpers/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import json

from django.core.cache import cache
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, Http404
from django.http import HttpResponse, Http404, JsonResponse
from django.conf import settings
from django.views.decorators.clickjacking import xframe_options_sameorigin

Expand All @@ -15,10 +16,13 @@
from .models import NoticeDownloadTracker
from institutions.models import Institution
from researchers.models import Researcher
from .utils import retrieve_native_land_all_slug_data


def restricted_view(request, exception=None):
return render(request, '403.html', status=403)


@login_required(login_url='login')
def delete_member_invite(request, pk):
invite = InviteMember.objects.get(id=pk)
Expand Down Expand Up @@ -53,6 +57,7 @@ def download_open_collaborate_notice(request, perm, researcher_id=None, institut

return download_otc_notice(request)


@login_required(login_url='login')
def download_collections_care_notices(request, institution_id, perm):
# perm will be a 1 or 0
Expand All @@ -63,6 +68,7 @@ def download_collections_care_notices(request, institution_id, perm):
NoticeDownloadTracker.objects.create(institution=Institution.objects.get(id=institution_id), user=request.user, collections_care_notices=True)
return download_cc_notices(request)


@login_required(login_url='login')
def download_community_support_letter(request):
try:
Expand All @@ -80,6 +86,9 @@ def download_community_support_letter(request):

@xframe_options_sameorigin
def community_boundary_view(request, community_id):
"""
Uses boundary in community for view
"""
community = Community.objects.filter(id=community_id).first()
if not community:
message = 'Community Does Not Exist'
Expand All @@ -92,32 +101,14 @@ def community_boundary_view(request, community_id):
context = {
'boundary': boundary
}
return render(request, 'boundary/boundary-view.html', context)


@login_required(login_url='login')
def boundary_view(request):
try:
boundary = request.GET.get('boundary')
if boundary:
boundary = json.loads(
boundary.replace('(', '[').replace(')', ']')
)
else:
boundary = []

context = {
'boundary': boundary
}
return render(request, 'boundary/boundary-view.html', context)
except Exception as e:
message = 'Invalid Boundary Format'
print(f'{message}: {e}')
raise Exception(message)
return render(request, 'boundary/boundary-preview.html', context)


@xframe_options_sameorigin
def project_boundary_view(request, project_id):
"""
Uses boundary in project for view
"""
project = Project.objects.filter(id=project_id).first()
if not project:
message = 'Project Does Not Exist'
Expand All @@ -130,4 +121,46 @@ def project_boundary_view(request, project_id):
context = {
'boundary': boundary
}
return render(request, 'boundary/boundary-view.html', context)
return render(request, 'boundary/boundary-preview.html', context)


@login_required(login_url='login')
def boundary_preview(request):
"""
Uses boundary in local storage for preview
"""
context = {
'preview_boundary': True,
}
return render(request, 'boundary/boundary-preview.html', context)


@login_required(login_url='login')
def native_land_data(request):
"""
Returns data associated with particular slug
"""
slug = request.GET.get('slug')
if slug is None:
return Http404('Slug Variable Is Not Defined In Request')

# get all slug data from cache
all_slug_data = cache.get('all_slug_data')

# when cache doesn't exist, then retrieve actual data and cache it
if all_slug_data is None:
try:
all_slug_data = retrieve_native_land_all_slug_data()
except (
requests.exceptions.Timeout,
requests.exceptions.ConnectionError,
requests.exceptions.HTTPError
):
return Http404('Unable to Retrieve All NLD Slug Data')
cache.set('all_slug_data', all_slug_data)

slug_data = all_slug_data.get(slug)
if slug_data is None:
return Http404(f'Unable to Retrieve Specific NLD Slug Data for {slug}')

return JsonResponse(slug_data)
6 changes: 6 additions & 0 deletions localcontexts/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,12 @@
}
}

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
}
}

SITE_ID = 1

SOCIALACCOUNT_LOGIN_ON_GET=True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,53 @@
margin-top: 50px;
padding: 36px;
}
.invisible {
display: none
}
</style>
</head>
<body>
<div id="map"></div>

{% if boundary|length == 0 %}
<div id="no-boundary-container">
<div id="no-boundary">
No boundary Present
</div>
<div id="no-boundary-container">
<div id="no-boundary">
No boundary Present
</div>
</div>

<script>
// when boundary is not present, set default
let boundary = [
[[8.7832, 34.5085]]
]
let setInitialZoom = true

function boundaryExists() {
// when boundary exists, this is run to modify
// the settings
setInitialZoom = false
document.querySelector('#no-boundary').classList.add('invisible')
}
</script>

{% if preview_boundary %}
<script>
// when boundary are not present, set default
const boundary = [
[[8.7832, 34.5085]]
]
const setInitialZoom = true
// get boundary data from Local Storage
if (localStorage.hasOwnProperty('boundary_preview')) {
boundary = JSON.parse(
localStorage.getItem('boundary_preview')
)
boundaryExists()
}
</script>
{% else %}
{% elif boundary|length > 0 %}
<script>
const boundary = {{ boundary }}
const setInitialZoom = false
// Get boundary data from backend
boundary = {{ boundary }}
boundaryExists()
</script>
{% endif %}


<script>
// define map and its initial boundary
const map = L.map('map')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% load static %}
{% load static %} {% load custom_api_tags %}
<style>
.region-container{
margin-top: 20px;
Expand Down Expand Up @@ -255,18 +255,19 @@
let BoundaryPayLoad = {}
let InitialShareBoundaryPublicly = {% if entity.share_boundary_publicly %}true{% else %}false{% endif %}

fetch('https://native-land.ca/wp-json/nativeland/v1/map-list').then(resp => resp.json()).then(response => {
fetch('{% external_api "https://raw.githubusercontent.com/biocodellc/localcontexts_json/main/data/nativeland_slug_name_list.json" %}').
then(resp => resp.json()).then(response => {

document.querySelector('.region-container input.search').addEventListener("keyup", (event) => {
let html = ''
const textInput = event.target.value
const inputLength = textInput.length
if (inputLength >= 3) {
var results = response.filter(item => item.post_title.toLowerCase().indexOf(textInput.toLowerCase()) > -1);
var results = response.filter(item => item.name.toLowerCase().indexOf(textInput.toLowerCase()) > -1);
results.forEach(result => {
html += `
<div class="result-item" data-slug="${result.slug}" data-title="${result.post_title}" onclick="selectSlug(this)">
${result.post_title}</br />
<div class="result-item" data-slug="${result.slug}" data-title="${result.name}" onclick="selectSlug(this)">
${result.name}</br />
</div>
`
})
Expand Down Expand Up @@ -351,27 +352,26 @@
* */
try {
// do post call to get boundary
const url = `https://native-land.ca/wp-json/nativeland/v1/api/index.php?maps=territories&name=${slug}`
const url = `{% url 'nld-data' %}?slug=${slug}`
showSpinner()
const boundaryResponse = await fetch(url)
const boundaryData = await boundaryResponse.json()
hideSpinner()

if (boundaryData.length === 0) {
if (!boundaryData.coordinates[0].length) {
const errorMessage = 'Selected location does not have any Native Land boundary'
raiseError(selectionUnit, errorMessage)
throw new Error(errorMessage)
}

const boundary = boundaryData[0]
const boundaryCoordinates = boundary.geometry.coordinates[0]

const boundaryCoordinates = boundaryData.coordinates[0][0]
// reorder so (lon, lat)'s become (lat, lon)'s
boundaryCoordinates.map(row=>row.reverse())

// set Boundary with payload
BoundaryPayLoad = {
source: boundary.properties.description,
name: boundary.properties.Name,
source: boundaryData.description,
name: slug,
boundary: boundaryCoordinates,
should_update_coordinates: true,
}
Expand All @@ -389,8 +389,11 @@
}

function setViewLocationsHref(selectionUnit, boundary) {
// set boundary-preview value in localStorage
localStorage.setItem('boundary_preview', JSON.stringify(boundary))

// set href for view-boundary-location
const href = `{% url 'boundary-view' %}?boundary=${JSON.stringify(boundary)}`
const href = "{% url 'boundary-preview' %}"
selectionUnit.querySelector('.view-boundary-link').setAttribute('href', href)
}

Expand Down Expand Up @@ -553,6 +556,8 @@
clearShapeFileInput(selectionUnit)
selectInitialShareBoundaryPublicly()
disableContinueButton()
BoundaryPayLoad = {}
setBoundaryPayloadForInputElement()
}
</script>
<script src="{% static 'javascript/shpjs.js' %}"></script>
Loading

0 comments on commit 529dfa3

Please sign in to comment.