From 4d33f49082064d7d9a7f43fd2c798b05cb03464f Mon Sep 17 00:00:00 2001 From: Domagoj Zecevic Date: Tue, 6 Jan 2026 12:55:31 +0100 Subject: [PATCH] first commit, basic working --- .gitignore | 72 ++++++++++++++++++++++++++++ core/__init__.py | 0 divebases/__init__.py | 0 divebases/admin.py | 6 +++ divebases/migrations/0001_initial.py | 22 +++++++++ divebases/migrations/__init__.py | 0 divebases/models.py | 6 +++ divemanager/__init__.py | 0 divemanager/settings.py | 59 +++++++++++++++++++++++ divemanager/urls.py | 7 +++ events/__init__.py | 0 events/admin.py | 7 +++ events/migrations/0001_initial.py | 23 +++++++++ events/migrations/0002_initial.py | 29 +++++++++++ events/migrations/__init__.py | 0 events/models.py | 26 ++++++++++ infos/__init__.py | 0 infos/admin.py | 8 ++++ infos/migrations/0001_initial.py | 24 ++++++++++ infos/migrations/0002_initial.py | 29 +++++++++++ infos/migrations/__init__.py | 0 infos/models.py | 28 +++++++++++ manage.py | 9 ++++ users/__init__.py | 1 + users/admin.py | 8 ++++ users/apps.py | 5 ++ users/migrations/0001_initial.py | 49 +++++++++++++++++++ users/migrations/__init__.py | 0 users/models.py | 9 ++++ 29 files changed, 427 insertions(+) create mode 100644 .gitignore create mode 100644 core/__init__.py create mode 100644 divebases/__init__.py create mode 100644 divebases/admin.py create mode 100644 divebases/migrations/0001_initial.py create mode 100644 divebases/migrations/__init__.py create mode 100644 divebases/models.py create mode 100644 divemanager/__init__.py create mode 100644 divemanager/settings.py create mode 100644 divemanager/urls.py create mode 100644 events/__init__.py create mode 100644 events/admin.py create mode 100644 events/migrations/0001_initial.py create mode 100644 events/migrations/0002_initial.py create mode 100644 events/migrations/__init__.py create mode 100644 events/models.py create mode 100644 infos/__init__.py create mode 100644 infos/admin.py create mode 100644 infos/migrations/0001_initial.py create mode 100644 infos/migrations/0002_initial.py create mode 100644 infos/migrations/__init__.py create mode 100644 infos/models.py create mode 100644 manage.py create mode 100644 users/__init__.py create mode 100644 users/admin.py create mode 100644 users/apps.py create mode 100644 users/migrations/0001_initial.py create mode 100644 users/migrations/__init__.py create mode 100644 users/models.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1e995a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,72 @@ +# Python compiled files +__pycache__/ +*.py[cod] +*$py.class + +# Django specific +*.log +*.pot +*.pyc +*.sqlite3 +db.sqlite3 +media/ +staticfiles/ +.env +.env.* + +# Distribution / packaging +*.egg +*.egg-info/ +dist/ +build/ +eggs/ +parts/ +bin/ +var/ +sdist/ +develop-eggs/ + +# PyInstaller +*.manifest +*.spec + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +local_settings.py +db.sqlite3 +media/ + +# IDEs and editors +.vscode/ +.idea/ +*.sublime-project +*.sublime-workspace +*.iml +*.ipr +*.iws + +# macOS +.DS_Store + +# Windows +Thumbs.db + +# Venv +venv/ \ No newline at end of file diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/divebases/__init__.py b/divebases/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/divebases/admin.py b/divebases/admin.py new file mode 100644 index 0000000..1766751 --- /dev/null +++ b/divebases/admin.py @@ -0,0 +1,6 @@ +from django.contrib import admin +from .models import DiveBase + +@admin.register(DiveBase) +class DiveBaseAdmin(admin.ModelAdmin): + list_display = ("name", "location") diff --git a/divebases/migrations/0001_initial.py b/divebases/migrations/0001_initial.py new file mode 100644 index 0000000..736ef3a --- /dev/null +++ b/divebases/migrations/0001_initial.py @@ -0,0 +1,22 @@ +# Generated by Django 5.2.9 on 2026-01-06 11:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='DiveBase', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('location', models.CharField(max_length=255)), + ], + ), + ] diff --git a/divebases/migrations/__init__.py b/divebases/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/divebases/models.py b/divebases/models.py new file mode 100644 index 0000000..e7583cd --- /dev/null +++ b/divebases/models.py @@ -0,0 +1,6 @@ + +from django.db import models + +class DiveBase(models.Model): + name = models.CharField(max_length=255) + location = models.CharField(max_length=255) diff --git a/divemanager/__init__.py b/divemanager/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/divemanager/settings.py b/divemanager/settings.py new file mode 100644 index 0000000..24dca2b --- /dev/null +++ b/divemanager/settings.py @@ -0,0 +1,59 @@ + +from pathlib import Path + +BASE_DIR = Path(__file__).resolve().parent.parent + +SECRET_KEY = 'dev-secret-key' +DEBUG = True +ALLOWED_HOSTS = [] + +INSTALLED_APPS = [ + 'users', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', + 'divebases', + 'events', + 'infos', +] + +AUTH_USER_MODEL = 'users.User' + +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', +] + +ROOT_URLCONF = 'divemanager.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [BASE_DIR / 'templates'], + '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', + ]}, + }, +] + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + +STATIC_URL = '/static/' +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/divemanager/urls.py b/divemanager/urls.py new file mode 100644 index 0000000..a3c4a89 --- /dev/null +++ b/divemanager/urls.py @@ -0,0 +1,7 @@ + +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] diff --git a/events/__init__.py b/events/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/events/admin.py b/events/admin.py new file mode 100644 index 0000000..d9abf6c --- /dev/null +++ b/events/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin +from .models import Event + +@admin.register(Event) +class EventAdmin(admin.ModelAdmin): + list_display = ("title", "start_datetime", "dive_base", "is_deleted") + list_filter = ("dive_base", "is_deleted") diff --git a/events/migrations/0001_initial.py b/events/migrations/0001_initial.py new file mode 100644 index 0000000..458129b --- /dev/null +++ b/events/migrations/0001_initial.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.9 on 2026-01-06 11:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('start_datetime', models.DateTimeField()), + ('is_deleted', models.BooleanField(default=False)), + ], + ), + ] diff --git a/events/migrations/0002_initial.py b/events/migrations/0002_initial.py new file mode 100644 index 0000000..6de2ac1 --- /dev/null +++ b/events/migrations/0002_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 5.2.9 on 2026-01-06 11:46 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('divebases', '0001_initial'), + ('events', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='event', + name='created_by', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='created_events', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='event', + name='dive_base', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='divebases.divebase'), + ), + ] diff --git a/events/migrations/__init__.py b/events/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/events/models.py b/events/models.py new file mode 100644 index 0000000..8a3d722 --- /dev/null +++ b/events/models.py @@ -0,0 +1,26 @@ +from django.db import models +from django.conf import settings + +User = settings.AUTH_USER_MODEL + + +class Event(models.Model): + title = models.CharField(max_length=255) + start_datetime = models.DateTimeField() + + dive_base = models.ForeignKey( + 'divebases.DiveBase', + on_delete=models.CASCADE, + related_name='events' + ) + + created_by = models.ForeignKey( + User, + on_delete=models.PROTECT, + related_name='created_events' + ) + + is_deleted = models.BooleanField(default=False) + + def __str__(self): + return self.title diff --git a/infos/__init__.py b/infos/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infos/admin.py b/infos/admin.py new file mode 100644 index 0000000..7aacebd --- /dev/null +++ b/infos/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin +from .models import InfoArticle + + +@admin.register(InfoArticle) +class InfoArticleAdmin(admin.ModelAdmin): + list_display = ("title", "dive_base", "created_at", "is_deleted") + list_filter = ("dive_base", "is_deleted") diff --git a/infos/migrations/0001_initial.py b/infos/migrations/0001_initial.py new file mode 100644 index 0000000..80064d8 --- /dev/null +++ b/infos/migrations/0001_initial.py @@ -0,0 +1,24 @@ +# Generated by Django 5.2.9 on 2026-01-06 11:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='InfoArticle', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('content', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('is_deleted', models.BooleanField(default=False)), + ], + ), + ] diff --git a/infos/migrations/0002_initial.py b/infos/migrations/0002_initial.py new file mode 100644 index 0000000..b1f32cd --- /dev/null +++ b/infos/migrations/0002_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 5.2.9 on 2026-01-06 11:46 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('divebases', '0001_initial'), + ('infos', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='infoarticle', + name='created_by', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='articles', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='infoarticle', + name='dive_base', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='articles', to='divebases.divebase'), + ), + ] diff --git a/infos/migrations/__init__.py b/infos/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/infos/models.py b/infos/models.py new file mode 100644 index 0000000..dcc1ac6 --- /dev/null +++ b/infos/models.py @@ -0,0 +1,28 @@ +from django.db import models +from django.conf import settings + +User = settings.AUTH_USER_MODEL + + +class InfoArticle(models.Model): + title = models.CharField(max_length=255) + content = models.TextField() + + dive_base = models.ForeignKey( + 'divebases.DiveBase', + on_delete=models.CASCADE, + related_name='articles' + ) + + created_by = models.ForeignKey( + User, + on_delete=models.PROTECT, + related_name='articles' + ) + + created_at = models.DateTimeField(auto_now_add=True) + + is_deleted = models.BooleanField(default=False) + + def __str__(self): + return self.title diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..5d12103 --- /dev/null +++ b/manage.py @@ -0,0 +1,9 @@ + +#!/usr/bin/env python +import os, sys +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'divemanager.settings') + from django.core.management import execute_from_command_line + execute_from_command_line(sys.argv) +if __name__ == '__main__': + main() diff --git a/users/__init__.py b/users/__init__.py new file mode 100644 index 0000000..5d64f7e --- /dev/null +++ b/users/__init__.py @@ -0,0 +1 @@ +default_app_config = "users.apps.UsersConfig" \ No newline at end of file diff --git a/users/admin.py b/users/admin.py new file mode 100644 index 0000000..515aecf --- /dev/null +++ b/users/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin +from .models import User + +@admin.register(User) +class UserAdmin(admin.ModelAdmin): + list_display = ("username", "email", "role", "dive_base", "is_staff") + list_filter = ("role", "dive_base") + search_fields = ("username", "email") diff --git a/users/apps.py b/users/apps.py new file mode 100644 index 0000000..00b38e2 --- /dev/null +++ b/users/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + +class UsersConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "users" \ No newline at end of file diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py new file mode 100644 index 0000000..c8526a0 --- /dev/null +++ b/users/migrations/0001_initial.py @@ -0,0 +1,49 @@ +# Generated by Django 5.2.9 on 2026-01-06 11:46 + +import django.contrib.auth.models +import django.contrib.auth.validators +import django.db.models.deletion +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ('divebases', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('role', models.CharField(choices=[('USER', 'User'), ('ADMIN', 'Admin')], default='USER', max_length=10)), + ('dive_certificate', models.CharField(blank=True, max_length=255)), + ('dive_base', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='divebases.divebase')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/users/models.py b/users/models.py new file mode 100644 index 0000000..03f4224 --- /dev/null +++ b/users/models.py @@ -0,0 +1,9 @@ + +from django.contrib.auth.models import AbstractUser +from django.db import models + +class User(AbstractUser): + ROLE_CHOICES = [('USER','User'), ('ADMIN','Admin')] + role = models.CharField(max_length=10, choices=ROLE_CHOICES, default='USER') + dive_certificate = models.CharField(max_length=255, blank=True) + dive_base = models.ForeignKey('divebases.DiveBase', null=True, blank=True, on_delete=models.SET_NULL)