--- /dev/null
+__pycache__/
--- /dev/null
+from django.contrib import admin
+
+# Register your models here.
+
+from .models import Report
+
+admin.site.register(Report)
--- /dev/null
+from django.apps import AppConfig
+
+
+class GeoreportConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'georeport'
--- /dev/null
+# 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)),
+ ],
+ ),
+ ]
--- /dev/null
+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"]
--- /dev/null
+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);
+
--- /dev/null
+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);
--- /dev/null
+var map = L.map("map").setView([51.7173, 8.753557], 15);
+L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
+ maxZoom: 19,
+ attribution: "© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a>"
+}).addTo(map);
--- /dev/null
+<!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>
--- /dev/null
+{% 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 %}
+
--- /dev/null
+{% 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 %}
--- /dev/null
+{% 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 %}
--- /dev/null
+from django.test import TestCase
+
+# Create your tests here.
--- /dev/null
+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"),
+]
--- /dev/null
+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})
--- /dev/null
+#!/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()
--- /dev/null
+"""
+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()
--- /dev/null
+"""
+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",
+]
--- /dev/null
+"""
+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()
--- /dev/null
+"""
+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()
--- /dev/null
+django
+django-debug-toolbar