__pycache__/
db.sqlite3
+
+
+doc/_build
+doc/build
--- /dev/null
+sphinx
+sphinxcontrib-plantuml
+-r requirements.txt
project = "Pinpoint-Report"
copyright = "2025, Jörn Menne"
author = "Jörn Menne"
-release = "0.1"
+release = "0.1.5"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
"sphinx.ext.napoleon",
"sphinxcontrib.plantuml",
"sphinx.ext.mathjax",
+ "myst_parser",
+ "sphinx.ext.todo",
]
templates_path = ["_templates"]
html_theme = "alabaster"
html_static_path = ["_static"]
+
+
+# Options for todo
+todo_include_todos = True
Models
======
-Here are the models used in Pinpoint-Report
+.. todo::
+ Split into 2 files. 1 to read and one for the autodoc
+
+The models represent the structure in the datebase as such, that each model
+is a table in the database.
+The translation from the *models.py* file to the specifc tables is done by
+django with the help of migrations.
+
+After each alteration of a model-class the following two scripts have to be run.
+.. code::
+
+ python manage migrations
+ python manage migrate
+
+The first command creates a migration file, while the second one applies the migration to the database.
+
+The following models are used:
+
+* Category
+* Report
+
+Categories are used to group reports and assing the corresponding staff. This is done by preventing access to users,
+which have not authority about the category
+
+.. automodule:: georeport.models
+ :members:
+ :undoc-members:
:caption: Contents:
georeport/models
+
+
+.. todolist::
--- /dev/null
+# Generated by Django 5.1.5 on 2025-02-05 10:09
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ initial = True
+
+ dependencies = [
+ ("auth", "0012_alter_user_first_name_max_length"),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Category",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=100)),
+ (
+ "groups",
+ models.ManyToManyField(
+ blank=True, related_name="group_owner", to="auth.group"
+ ),
+ ),
+ (
+ "parent",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="subcategories",
+ to="georeport.category",
+ ),
+ ),
+ (
+ "user",
+ models.ManyToManyField(
+ blank=True, related_name="owner", to=settings.AUTH_USER_MODEL
+ ),
+ ),
+ ],
+ options={
+ "verbose_name_plural": "Categories",
+ },
+ ),
+ migrations.CreateModel(
+ name="Report",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("created_at", models.DateTimeField(auto_now=True)),
+ ("updated_at", models.DateTimeField(auto_now_add=True)),
+ ("title", models.CharField(max_length=100, unique=True)),
+ ("descrption", models.TextField(blank=True, null=True)),
+ ("email", models.EmailField(max_length=254)),
+ (
+ "state",
+ models.IntegerField(
+ choices=[
+ (0, "New"),
+ (1, "In Progess"),
+ (2, "Finished"),
+ (3, "Archive"),
+ ],
+ default=0,
+ ),
+ ),
+ (
+ "_oldState",
+ models.IntegerField(
+ choices=[
+ (0, "New"),
+ (1, "In Progess"),
+ (2, "Finished"),
+ (3, "Archive"),
+ ],
+ default=0,
+ ),
+ ),
+ ("published", models.BooleanField(default=False)),
+ (
+ "category",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.RESTRICT,
+ related_name="reports",
+ to="georeport.category",
+ ),
+ ),
+ ],
+ ),
+ ]
+# Copyright: (c) 2025, Jörn Menne <jmenne@posteo.de>
+# GNU General Public License v3.0 (see LICSENE or https://www.gnu.org/license/gpl-3.0.md)
+"""
+Module which contains classes representing the database structure
+of the project.
+"""
+
from django.db import models
+from django.contrib.auth.models import Group, User
+from typing import override
# Create your models here.
+
+
+class Category(models.Model):
+ """
+ A class representing a Category in the database.
+ """
+
+ # TODO: Prevent circles
+ name = models.CharField(max_length=100)
+ parent = models.ForeignKey(
+ "self",
+ on_delete=models.CASCADE,
+ related_name="subcategories",
+ null=True,
+ blank=True,
+ )
+
+ user = models.ManyToManyField(User, related_name="owner", blank=True)
+ groups = models.ManyToManyField(Group, related_name="group_owner", blank=True)
+
+ class Meta:
+ verbose_name_plural = "Categories"
+
+ @override
+ def __str__(self) -> str:
+ return str(self.name)
+
+
+class Report(models.Model):
+ """
+ A class representing a Report in the database.
+ """
+
+ class State(models.IntegerChoices):
+ """
+ A small class, which provide the possible states of a report
+ """
+
+ NEW = 0
+ IN_PROGESS = 1
+ FINISHED = 2
+ ARCHIVE = 3
+
+ # Timebased autofields
+ created_at = models.DateTimeField(auto_now=True)
+ updated_at = models.DateTimeField(auto_now_add=True)
+
+ # Fields to be filled at creation time
+ category = models.ForeignKey(
+ Category, on_delete=models.RESTRICT, related_name="reports"
+ )
+ title = models.CharField(max_length=100, unique=True)
+ descrption = models.TextField(blank=True, null=True)
+ email = models.EmailField()
+ # TODO: Images
+
+ # Fields set at creation
+ state = models.IntegerField(choices=State, default=0) # type: ignore Correct type can not be dtermined
+ _oldState = models.IntegerField(choices=State, default=0) # type: ignore Correct type can not be dtermined
+
+ """
+ The old statevariable is neede to determine, if the state was changed.
+ """
+ published = models.BooleanField(default=False) # type: ignore Correct type can not be dtermined
+
+ @override
+ def __str__(self) -> str:
+ return str(self.title)
+
+
+# TODO: Location
+
+# TODO: Image
+# Copyright: (c) 2025, Jörn Menne <jmenne@posteo.de>
+# GNU General Public License v3.0 (see LICSENE or https://www.gnu.org/license/gpl-3.0.md)
+
from django.test import TestCase
-# Create your tests here.
+from .models import Category, Report
+
+
+class ReportTestCase(TestCase):
+ def setUp(self):
+ Category.objects.create(name="Cat1") # type:ignore Attribute object is unknown
+ Report.objects.create( # type:ignore Attribute object is unknown
+ title="Test",
+ email="test@test.de",
+ category=Category.objects.first(), # type:ignore Attribute object is unknown
+ )
+
+ def test_unpulished_as_default(self):
+ report = Report.objects.get(title="Test") # type:ignore Attribute object is unknown
+ self.assertEqual(report.published, False)