Skip to content

Commit

Permalink
Merge pull request #32 from animorphcoop/add/map
Browse files Browse the repository at this point in the history
Add map view
  • Loading branch information
nicksellen authored Jan 19, 2024
2 parents a6ee9af + 9bdbc94 commit 7b26d85
Show file tree
Hide file tree
Showing 41 changed files with 1,586 additions and 55 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/.build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

services:
postgres:
image: postgres:12.8-alpine
image: postgis/postgis:12-3.4-alpine
env:
POSTGRES_PASSWORD: postgres
options: >-
Expand Down Expand Up @@ -41,8 +41,8 @@ jobs:
with:
python-version: 3.9

- name: Install redis
run: sudo apt-get install -y redis-tools redis-server
- name: Install packages
run: sudo apt-get install -y redis-tools redis-server binutils libproj-dev gdal-bin

- name: Verify that redis is up
run: redis-cli ping
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ENV PYTHONUNBUFFERED 1

# install node
RUN apt-get update \
&& apt-get install -y ca-certificates curl gnupg \
&& apt-get install -y ca-certificates curl gnupg binutils libproj-dev gdal-bin geos-bin \
&& mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg

Expand Down
5 changes: 5 additions & 0 deletions ansible/playbooks/base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
name:
- vim
- git
# TODO: ensure there is a postgis version of postgres installed
- postgresql
- redis-server
- python3.9
Expand All @@ -21,6 +22,10 @@
- libpq-dev
- gcc
- python3-psycopg2
# geolibs https://docs.djangoproject.com/en/dev/ref/contrib/gis/install/geolibs/
- binutils
- libproj-dev
- gdal-bin
state: present

# node.js and npm
Expand Down
6 changes: 6 additions & 0 deletions apps/core/migrations/0001_add_postgis_extension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.contrib.postgres.operations import CreateExtension
from django.db import migrations


class Migration(migrations.Migration):
operations = [CreateExtension("postgis")]
17 changes: 16 additions & 1 deletion apps/core/templatetags/custom_filters.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import json
from typing import Iterable, List, TypeVar
from typing import Iterable, List, TypeVar, Optional

from django import template
from django.utils.safestring import SafeString, mark_safe
from django.utils.timesince import timesince, timeuntil

from river.models import River
from river.util import river_marker

register = template.Library()

T = TypeVar("T")
Expand All @@ -26,3 +29,15 @@ def strcat(value, arg):
@register.filter(name="to_range")
def to_range(number: int):
return range(number)


@register.filter(name="to_json")
def to_json(value):
return json.dumps(value)


@register.filter(name="to_marker_json")
def to_marker_json(river: Optional[River]):
if not river:
return json.dumps(None)
return json.dumps(river_marker(river))
5 changes: 5 additions & 0 deletions apps/core/templatetags/custom_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ def generate_id(*args):
return uuid.uuid4()


@register.simple_tag
def maptiler_api_key(*args):
return settings.MAPTILER_API_KEY


@register.simple_tag(takes_context=True)
def active_link(context, text, *view_names, **view_params):
"""Use to output text when the specified view is active
Expand Down
2 changes: 1 addition & 1 deletion apps/landing/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def privacy(request: HttpRequest) -> HttpResponse:
return render(request, "landing/privacy.html")


def handle_404(request: HttpRequest, exception: Exception) -> HttpResponse:
def handle_404(request: HttpRequest, exception: Exception = None) -> HttpResponse:
return render(request, "404.html", status=404)


Expand Down
Empty file added apps/remix/__init__.py
Empty file.
14 changes: 14 additions & 0 deletions apps/remix/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from typing import List, Union

from django.urls import URLPattern, URLResolver, path

from .views import RemixMapView

urlpatterns: List[Union[URLResolver, URLPattern]] = [
path(
"map/",
RemixMapView.as_view(),
name="remix_map",
),
]

20 changes: 20 additions & 0 deletions apps/remix/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django.views.generic import TemplateView

from river.models import River
from river.util import river_marker


class RemixMapView(TemplateView):
template_name = "remix/remix_map.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
rivers = River.objects.exclude(location=None)
context["rivers"] = rivers
markers = []
for river in rivers:
marker = river_marker(river)
if marker:
markers.append(marker)
context["markers"] = markers
return context
12 changes: 11 additions & 1 deletion apps/river/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
from typing import Any, Dict, List, Optional, Type

from django import forms
from django.contrib.gis.forms import PointField
from django.contrib.gis.geos import GEOSGeometry

from .models import River


class CreateRiverForm(forms.ModelForm):
class Meta:
model: Type[River] = River
fields: List[str] = ["title", "description", "tags", "image"]
fields: List[str] = ["title", "description", "tags", "image", "location"]
widgets = {
"description": forms.Textarea(),
}
Expand All @@ -34,6 +36,14 @@ class Meta:
}


class RiverLocationUpdateForm(forms.ModelForm):
location = PointField(srid=4326)

class Meta:
model: Type[River] = River
fields: List[str] = ["location"]


class RiverImageUpdateForm(forms.ModelForm):
ALLOWED_IMAGE_TYPES = ["jpg", "jpeg", "png", "webp"]

Expand Down
20 changes: 20 additions & 0 deletions apps/river/migrations/0007_river_location.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.3 on 2023-12-20 19:13

import django.contrib.gis.db.models.fields
from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("river", "0006_alter_river_current_stage"),
]

operations = [
migrations.AddField(
model_name="river",
name="location",
field=django.contrib.gis.db.models.fields.PointField(
geography=True, null=True, srid=4326
),
),
]
17 changes: 17 additions & 0 deletions apps/river/migrations/0008_river_location_exact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.3 on 2024-01-18 16:36

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("river", "0007_river_location"),
]

operations = [
migrations.AddField(
model_name="river",
name="location_exact",
field=models.BooleanField(default=True),
),
]
12 changes: 12 additions & 0 deletions apps/river/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
from typing import Any, Dict, List
from urllib.parse import quote

from django.contrib.gis.db.models import PointField

from area.models import Area
from django.db import models
from django.utils import timezone
from django.utils.text import slugify

from core.utils.tags_declusterer import tag_cluster_to_list
from messaging.models import Chat
from messaging.util import send_system_message
from modelcluster.contrib.taggit import ClusterTaggableManager
Expand Down Expand Up @@ -238,6 +242,8 @@ class Stage(models.TextChoices):
description: models.CharField = models.CharField(max_length=2000)
tags = ClusterTaggableManager(through=RiverTag, blank=True)
image: models.ImageField = models.ImageField(upload_to="rivers/images/", blank=True)
location = PointField(geography=True, srid=4326, null=True)
location_exact = models.BooleanField(default=True)
area: models.ForeignKey = models.ForeignKey(
Area, on_delete=models.CASCADE, default=get_default_other_area
) # this is a bad default but can't really be replaced because it's used in every river creation, just immediately replaced, and it's a pain to change
Expand Down Expand Up @@ -272,6 +278,12 @@ def get_current_stage_string(self) -> str:
def get_started_months_ago(self) -> int:
return timezone.now().month - self.started_on.month

@property
def tag_list(self):
if not hasattr(self.tags, "all"):
return self.tags
return tag_cluster_to_list(self.tags)

def save(self, *args: List[Any], **kwargs: Dict[str, Any]) -> None:
super().save(*args, **kwargs) # save first or we won't have an id
if self.slug == "":
Expand Down
19 changes: 19 additions & 0 deletions apps/river/util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import random
from typing import Optional

from django.db.models import Q
from django.template.loader import render_to_string

from messaging.models import Chat

from .models import ActStage, EnvisionStage, PlanStage, ReflectStage, River
Expand Down Expand Up @@ -31,3 +34,19 @@ def get_chat_containing_river(chat: Chat) -> Optional[River]:
if len(reflect) != 0:
return River.objects.get(reflect_stage=reflect[0])
return None


def river_marker(river: River) -> Optional[dict]:
if not river.location:
return None
return {
"slug": river.slug,
"name": river.title,
"icon": "pin",
"coordinates": river.location.coords,
"html": render_to_string(
"river/river_card.html",
{"river": river, "close_button": True, "view_button": True},
),
"htmlMini": render_to_string("river/river_card_mini.html", {"river": river}),
}
12 changes: 12 additions & 0 deletions apps/river/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView

from core.views import HTMXMixin
from messaging.forms import ChatForm
from messaging.util import send_system_message
from messaging.views import ChatUpdateCheck, ChatView
Expand All @@ -31,6 +33,7 @@
RiverDescriptionUpdateForm,
RiverImageUpdateForm,
RiverTitleUpdateForm,
RiverLocationUpdateForm,
)
from .models import River, RiverMembership

Expand Down Expand Up @@ -186,6 +189,15 @@ def put(
return HttpResponse(
"Sorry, your description could not be processed, please refresh the page"
)
elif data.get("location"):
form = RiverLocationUpdateForm(data, instance=river)
if form.is_valid():
river.location = form.cleaned_data.get("location")
river.save()
return HttpResponse(river.location)
return HttpResponse(
"Sorry, your location could not be processed, please refresh the page"
)

else:
return HttpResponse(
Expand Down
44 changes: 20 additions & 24 deletions apps/spring/views.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
from typing import Any, Dict, List, Union
from django.http import Http404

from area.models import Area
from core.utils.tags_declusterer import tag_cluster_to_list
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView
from river.models import River, RiverMembership

# from river.util import get_current_stage_string, get_started_months_ago

class SpringView(DetailView):
model = Area
template_name = "spring/spring_area.html"

class SpringView(TemplateView):
def get(
self, request: HttpRequest, *args: List[Any], **kwargs: Dict[str, str]
) -> Union[HttpResponse, HttpResponseRedirect]:
# RETURN URL PATH
slug = str(kwargs["slug"])
print(slug)
def get_object(self):
slug = self.kwargs.get("slug")
if "-" in slug:
name = slug.replace("-", " ")
elif slug == "derrylondonderry":
name = "derry~londonderry"
else:
name = slug

if Area.objects.filter(name__iexact=name).exists():
area = Area.objects.get(name__iexact=name)
else:
return HttpResponseRedirect(reverse("404"))

try:
return Area.objects.get(name__iexact=name)
except Area.DoesNotExist:
raise Http404()

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
area = self.object
rivers = River.objects.filter(area=area)
for river in rivers:
river.tags = tag_cluster_to_list(river.tags)

river.us = RiverMembership.objects.filter(river=river)
river.swimmers = RiverMembership.objects.filter(river=river).values_list(
"user", flat=True
Expand All @@ -56,11 +51,12 @@ def get(
.count()
)

context = {"area": area, "rivers": rivers, "num_swimmers": num_swimmers}
context["area"] = area
context["rivers"] = rivers
context["num_swimmers"] = num_swimmers

return render(request, "spring/spring_area.html", context)
return context


class EstuaryView(TemplateView):
def get(self, request, *args, **kwargs):
return render(request, "spring/spring_estuary.html")
template_name = "spring/spring_estuary.html"
5 changes: 3 additions & 2 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ services:
- db_pg

db_pg:
image: postgres:12.8-alpine
#image: postgres:12.8-alpine
image: postgis/postgis:12-3.4-alpine
volumes:
- dbdata:/var/lib/postgres
- dbdata:/var/lib/postgresql/data
restart: always
ports:
- "5432:5432"
Expand Down
Loading

0 comments on commit 7b26d85

Please sign in to comment.