]> git.menne-pb.de Git - pinpoint.git/commitdiff
Add possibility to mark a location.
authorJörn Menne <jmenne@fedora.de>
Sat, 30 Nov 2024 21:43:48 +0000 (22:43 +0100)
committerJörn Menne <jmenne@fedora.de>
Sat, 30 Nov 2024 21:43:48 +0000 (22:43 +0100)
The location can chosen by either clicking on a map,
or by writing the lat/lng values by hand.
Eitherway a marker is added to the map, where the report is located.

The marker is also always shown, where the report is listed.

24 files changed:
.gitignore [new file with mode: 0644]
georeport/__init__.py [new file with mode: 0644]
georeport/admin.py [new file with mode: 0644]
georeport/apps.py [new file with mode: 0644]
georeport/migrations/0001_initial.py [new file with mode: 0644]
georeport/migrations/__init__.py [new file with mode: 0644]
georeport/models.py [new file with mode: 0644]
georeport/static/georeport/create_Report.js [new file with mode: 0644]
georeport/static/georeport/details.js [new file with mode: 0644]
georeport/static/georeport/mapsetup.js [new file with mode: 0644]
georeport/templates/georeport/base.html [new file with mode: 0644]
georeport/templates/georeport/create.html [new file with mode: 0644]
georeport/templates/georeport/detail.html [new file with mode: 0644]
georeport/templates/georeport/index.html [new file with mode: 0644]
georeport/tests.py [new file with mode: 0644]
georeport/urls.py [new file with mode: 0644]
georeport/views.py [new file with mode: 0644]
manage.py [new file with mode: 0755]
pinpoint/__init__.py [new file with mode: 0644]
pinpoint/asgi.py [new file with mode: 0644]
pinpoint/settings.py [new file with mode: 0644]
pinpoint/urls.py [new file with mode: 0644]
pinpoint/wsgi.py [new file with mode: 0644]
requirements.txt [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c18dd8d
--- /dev/null
@@ -0,0 +1 @@
+__pycache__/
diff --git a/georeport/__init__.py b/georeport/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/georeport/admin.py b/georeport/admin.py
new file mode 100644 (file)
index 0000000..2a218a2
--- /dev/null
@@ -0,0 +1,7 @@
+from django.contrib import admin
+
+# Register your models here.
+
+from .models import Report
+
+admin.site.register(Report)
diff --git a/georeport/apps.py b/georeport/apps.py
new file mode 100644 (file)
index 0000000..6bc8889
--- /dev/null
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class GeoreportConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'georeport'
diff --git a/georeport/migrations/0001_initial.py b/georeport/migrations/0001_initial.py
new file mode 100644 (file)
index 0000000..1fd09d0
--- /dev/null
@@ -0,0 +1,26 @@
+# Generated by Django 5.1.3 on 2024-11-30 14:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Report',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('title', models.CharField(max_length=80)),
+                ('creation_time', models.DateTimeField(auto_now_add=True)),
+                ('last_change', models.DateTimeField(auto_now=True)),
+                ('description', models.CharField(max_length=255, null=True)),
+                ('latitude', models.DecimalField(decimal_places=6, max_digits=8)),
+                ('longitude', models.DecimalField(decimal_places=6, max_digits=9)),
+            ],
+        ),
+    ]
diff --git a/georeport/migrations/__init__.py b/georeport/migrations/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/georeport/models.py b/georeport/models.py
new file mode 100644 (file)
index 0000000..bc83acf
--- /dev/null
@@ -0,0 +1,26 @@
+from django.db import models
+
+from django.forms import ModelForm
+# Create your models here.
+
+
+class Report(models.Model):
+    title = models.CharField(max_length=80)
+    creation_time = models.DateTimeField(auto_now_add=True)
+    # TODO last change shall be set to creation_time at creation_time
+    last_change = models.DateTimeField(auto_now=True)
+    description = models.CharField(max_length=255, null=True)
+
+    latitude = models.DecimalField(max_digits=8, decimal_places=6)
+    longitude = models.DecimalField(max_digits=9, decimal_places=6)
+
+    # TODO add status
+    #
+    def __str__(self):
+        return self.title
+
+
+class ReportForm(ModelForm):
+    class Meta:
+        model = Report
+        fields = ["title", "description", "latitude", "longitude"]
diff --git a/georeport/static/georeport/create_Report.js b/georeport/static/georeport/create_Report.js
new file mode 100644 (file)
index 0000000..275be7d
--- /dev/null
@@ -0,0 +1,27 @@
+var lat_input = document.getElementById("id_latitude");
+var lng_input = document.getElementById("id_longitude");
+let marker = L.marker();
+
+
+lat_input.addEventListener("change", () => {
+    marker.setLatLng([lat_input.value, lng_input.value])
+    i.addTo(map);
+
+});
+lng_input.addEventListener("change", () => {
+    marker.setLatLng([lat_input.value, lng_input.value])
+        .addTo(map);
+
+});
+
+function onMapClick(e) {
+    marker.setLatLng(e.latlng)
+        .addTo(map);
+
+    lat_input.value = e.latlng.lat.toFixed(6);
+    lng_input.value = e.latlng.lng.toFixed(6);
+
+}
+
+map.on("click", onMapClick);
+
diff --git a/georeport/static/georeport/details.js b/georeport/static/georeport/details.js
new file mode 100644 (file)
index 0000000..ac48319
--- /dev/null
@@ -0,0 +1,7 @@
+var marker = L.marker();
+
+var lat = document.getElementById("p-lat").dataset.lat;
+var lng = document.getElementById("p-lng").dataset.lng;
+
+marker.setLatLng([lat, lng])
+    .addTo(map);
diff --git a/georeport/static/georeport/mapsetup.js b/georeport/static/georeport/mapsetup.js
new file mode 100644 (file)
index 0000000..1ffa1af
--- /dev/null
@@ -0,0 +1,5 @@
+var map = L.map("map").setView([51.7173, 8.753557], 15);
+L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
+    maxZoom: 19,
+    attribution: "&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a>"
+}).addTo(map);
diff --git a/georeport/templates/georeport/base.html b/georeport/templates/georeport/base.html
new file mode 100644 (file)
index 0000000..d589de1
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+{% load static %}
+<html>
+    <head>
+        <title>{% block title %}Georeport{% endblock %}</title>
+        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
+            integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
+            crossorigin=""/>
+
+        <!-- Make sure you put this AFTER Leaflet's CSS -->
+        <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
+            integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
+            crossorigin="">
+        </script>
+
+        <style>
+            #map { height: 500px;}
+        </style>
+
+    </head>
+
+    <body>
+
+        <div id="map"></div>
+        <script src="{% static 'georeport/mapsetup.js' %}"></script>
+        {% block body %}
+        {% endblock %}
+    </body>
+</html>
diff --git a/georeport/templates/georeport/create.html b/georeport/templates/georeport/create.html
new file mode 100644 (file)
index 0000000..b2ec8aa
--- /dev/null
@@ -0,0 +1,15 @@
+{% extends "georeport/base.html" %}
+{% load static %}
+{% block title %}New report {% endblock %}
+{% block body %} 
+<form method="post">
+    {% csrf_token %}
+    {{ reportForm }}
+    <input type="submit"/>
+</form>
+<script src="{% static 'georeport/create_Report.js' %}"></script>
+
+<!-- TODO better URLS -->
+<a href="/georeport">Cancel</a>
+{% endblock %}
+
diff --git a/georeport/templates/georeport/detail.html b/georeport/templates/georeport/detail.html
new file mode 100644 (file)
index 0000000..adeeea2
--- /dev/null
@@ -0,0 +1,13 @@
+{% extends "georeport/base.html" %}
+{% load static %}
+{% block title %}Detail {{ report.id }} {% endblock %} 
+{% block body %} 
+    <h1>Report {{ report.id }}</h1>
+    <p>Title: {{ report.title }}</p>
+    <p>Erstellt am : {{ report.creation_time }}</p>
+    <p>Geändert: {{ report.last_changed  }}</p>
+    <p id="p-lat" data-lat="{{ report.latitude }}">Latitude: {{ report.latitude }}</p>
+    <p id="p-lng" data-lng="{{ report.longitude }}">Longitude: {{ report.longitude }}</p>
+    <a href="{% url 'index' %}">Back</a>
+    <script src="{% static 'georeport/details.js' %}"></script>
+{% endblock %} 
diff --git a/georeport/templates/georeport/index.html b/georeport/templates/georeport/index.html
new file mode 100644 (file)
index 0000000..2e3af8c
--- /dev/null
@@ -0,0 +1,14 @@
+{% extends "georeport/base.html" %}
+{% load static %}
+{% block title %}Index{% endblock %}
+
+{% block body %}
+<h1>Reports </h1>
+<a href="create">New Report</a>
+<ul>
+    {% for report in report_list %}
+        <li><a href="{{ report.id }}">{{ report.title }}</a></li>
+    {% endfor %}
+</ul>
+
+{% endblock %}
diff --git a/georeport/tests.py b/georeport/tests.py
new file mode 100644 (file)
index 0000000..7ce503c
--- /dev/null
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/georeport/urls.py b/georeport/urls.py
new file mode 100644 (file)
index 0000000..14e2230
--- /dev/null
@@ -0,0 +1,9 @@
+from django.urls import path
+
+from . import views
+
+urlpatterns = [
+    path("", views.index, name="index"),
+    path("<int:id>", views.details, name="detail"),
+    path("create", views.create, name="create"),
+]
diff --git a/georeport/views.py b/georeport/views.py
new file mode 100644 (file)
index 0000000..68b92cd
--- /dev/null
@@ -0,0 +1,27 @@
+from django.shortcuts import get_object_or_404, render, redirect
+
+# Create your views here.
+
+from .models import Report, ReportForm
+
+
+def index(request):
+    reports = Report.objects.all()
+    return render(request, "georeport/index.html", context={"report_list": reports})
+
+
+def details(request, id):
+    report = get_object_or_404(Report, pk=id)
+    return render(request, "georeport/detail.html", context={"report": report})
+
+
+def create(request):
+    if request.method == "POST":
+        reportForm = ReportForm(request.POST)
+        # TOOD Inputvalidations
+        reportForm.save()
+        return redirect("index")
+    else:
+        reportForm = ReportForm()
+
+    return render(request, "georeport/create.html", context={"reportForm": reportForm})
diff --git a/manage.py b/manage.py
new file mode 100755 (executable)
index 0000000..52c4ff2
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+    """Run administrative tasks."""
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pinpoint.settings')
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/pinpoint/__init__.py b/pinpoint/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pinpoint/asgi.py b/pinpoint/asgi.py
new file mode 100644 (file)
index 0000000..2b72c59
--- /dev/null
@@ -0,0 +1,16 @@
+"""
+ASGI config for pinpoint project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pinpoint.settings')
+
+application = get_asgi_application()
diff --git a/pinpoint/settings.py b/pinpoint/settings.py
new file mode 100644 (file)
index 0000000..418743b
--- /dev/null
@@ -0,0 +1,130 @@
+"""
+Django settings for pinpoint project.
+
+Generated by 'django-admin startproject' using Django 5.1.3.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/5.1/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = "django-insecure-&7#5doz#@q$^jtjn!^*fmta$=eaqjd@8mtf(1=^=lt8*xen(+g"
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    "georeport.apps.GeoreportConfig",
+    "django.contrib.admin",
+    "django.contrib.auth",
+    "django.contrib.contenttypes",
+    "django.contrib.sessions",
+    "django.contrib.messages",
+    "django.contrib.staticfiles",
+    "debug_toolbar",
+]
+
+MIDDLEWARE = [
+    "django.middleware.security.SecurityMiddleware",
+    "django.contrib.sessions.middleware.SessionMiddleware",
+    "django.middleware.common.CommonMiddleware",
+    "django.middleware.csrf.CsrfViewMiddleware",
+    "django.contrib.auth.middleware.AuthenticationMiddleware",
+    "django.contrib.messages.middleware.MessageMiddleware",
+    "django.middleware.clickjacking.XFrameOptionsMiddleware",
+    "debug_toolbar.middleware.DebugToolbarMiddleware",
+]
+
+ROOT_URLCONF = "pinpoint.urls"
+
+TEMPLATES = [
+    {
+        "BACKEND": "django.template.backends.django.DjangoTemplates",
+        "DIRS": [],
+        "APP_DIRS": True,
+        "OPTIONS": {
+            "context_processors": [
+                "django.template.context_processors.debug",
+                "django.template.context_processors.request",
+                "django.contrib.auth.context_processors.auth",
+                "django.contrib.messages.context_processors.messages",
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = "pinpoint.wsgi.application"
+
+
+# Database
+# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
+
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.sqlite3",
+        "NAME": BASE_DIR / "db.sqlite3",
+    }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/5.1/topics/i18n/
+
+LANGUAGE_CODE = "en-us"
+
+TIME_ZONE = "UTC"
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/5.1/howto/static-files/
+
+STATIC_URL = "static/"
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
+
+INTERNAL_IPS = [
+    "127.0.0.1",
+]
diff --git a/pinpoint/urls.py b/pinpoint/urls.py
new file mode 100644 (file)
index 0000000..9f6c87f
--- /dev/null
@@ -0,0 +1,25 @@
+"""
+URL configuration for pinpoint project.
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/5.1/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+
+from django.contrib import admin
+from django.urls import path, include
+from debug_toolbar.toolbar import debug_toolbar_urls
+
+urlpatterns = [
+    path("admin/", admin.site.urls),
+    path("georeport/", include("georeport.urls")),
+] + debug_toolbar_urls()
diff --git a/pinpoint/wsgi.py b/pinpoint/wsgi.py
new file mode 100644 (file)
index 0000000..77a0b83
--- /dev/null
@@ -0,0 +1,16 @@
+"""
+WSGI config for pinpoint project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pinpoint.settings')
+
+application = get_wsgi_application()
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..3b8d0ff
--- /dev/null
@@ -0,0 +1,2 @@
+django 
+django-debug-toolbar