From 9f60e733dae145b2a824cfe20f15efe1a00deef5 Mon Sep 17 00:00:00 2001 From: Freddy Date: Mon, 25 Nov 2024 18:57:54 +0100 Subject: [PATCH 01/11] Basic api draft. --- backendapi/admin.py | 8 ++- backendapi/exceptions.py | 3 + backendapi/migrations/0001_initial.py | 31 ++++++++++ backendapi/models.py | 14 +++++ backendapi/serializers.py | 88 +++++++++++++++++++++++++++ backendapi/urls.py | 1 + backendapi/views.py | 87 +++++++++++++++++++++++++- config/settings.py | 1 + requirements.txt | 2 + 9 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 backendapi/exceptions.py create mode 100644 backendapi/migrations/0001_initial.py create mode 100644 backendapi/serializers.py diff --git a/backendapi/admin.py b/backendapi/admin.py index 8c38f3f..ab8fb6b 100644 --- a/backendapi/admin.py +++ b/backendapi/admin.py @@ -1,3 +1,9 @@ from django.contrib import admin +from .models import Attendant -# Register your models here. + +class AttendantAdmin(admin.ModelAdmin): + list_display = ["first_name", "last_name", "email", "phone_number"] + + +admin.site.register(Attendant, AttendantAdmin) diff --git a/backendapi/exceptions.py b/backendapi/exceptions.py new file mode 100644 index 0000000..bec4070 --- /dev/null +++ b/backendapi/exceptions.py @@ -0,0 +1,3 @@ +from rest_framework.exceptions import APIException + +# write your custm exceptions here if we need it later. diff --git a/backendapi/migrations/0001_initial.py b/backendapi/migrations/0001_initial.py new file mode 100644 index 0000000..0df89ab --- /dev/null +++ b/backendapi/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 5.1.3 on 2024-11-25 08:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Attendant", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("first_name", models.CharField(max_length=30)), + ("last_name", models.CharField(max_length=30)), + ("email", models.EmailField(max_length=100)), + ("phone_number", models.CharField(max_length=12)), + ], + ), + ] diff --git a/backendapi/models.py b/backendapi/models.py index 71a8362..0e85128 100644 --- a/backendapi/models.py +++ b/backendapi/models.py @@ -1,3 +1,17 @@ from django.db import models +from rest_framework import serializers +from django.contrib.auth.models import User + + +# this is the Attendant model, im unsure if we need more data? Maby date of birth? => 18 years maby? +class Attendant(models.Model): + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) + email = models.EmailField(max_length=100) + phone_number = models.CharField(max_length=12) + + def __str__(self): + return f"{self.first_name} {self.last_name}" + # Create your models here. diff --git a/backendapi/serializers.py b/backendapi/serializers.py new file mode 100644 index 0000000..852a20c --- /dev/null +++ b/backendapi/serializers.py @@ -0,0 +1,88 @@ +import re +from rest_framework import serializers +from django.conf import settings +from .models import Attendant + +# Serializer for the Attendant model: handles validation, serialization, and desersialization of data. +# Change the model later depending on requirements. Please tell me what, and il remake the model later to fit requirements. + + +class AttendantAdmin(serializers.ModelSerializer): # defined a serialiser class + first_name = serializers.CharField( + label=("First Name* "), # Labels for the field + required=True, # This makes the fields required. + max_length=100, + style={ + "input_type": "text", + "autofocus": False, + "autocomplete": "off", + "required": True, + }, + error_messages={ + "required": "This field is required.", + "blank": "First Name is required.", + }, + ) + + last_name = serializers.CharField( + label=("Last Name* "), # Label for the field + required=True, # This makes the fields required. + max_length=100, + style={ + "input_type": "text", + "autofocus": False, + "autocomplete": "off", + "required": True, + }, + error_messages={ + "required": "This field is required.", + "blank": "Last Name is required.", + "invalid": "Last Name can only contain characters.", + }, + ) + + email = serializers.EmailField( + label=("Email* "), # Label for the field + required=True, # Field is required + max_length=100, + style={ + "input_type": "email", + "autofocus": False, + "autocomplete": "off", + "required": True, + }, + error_messages={ + "required": "This field is required.", + "blank": "Email is required.", + }, + ) + phone_number = serializers.CharField( + label="Phone Number* ", # Label for the field + max_length=14, + min_length=10, + required=True, # Field is required + error_messages={ + "required": "This field is required .", + "blank": "Phone number is required.", + }, + ) + + class Meta: + model = Attendant + fields = ["first_name", "last_name", "email", "phone_number"] + + +def validate_first_name(value): + # Check if the first name contains only characters or letters with spaces and letters from a-Z + if not re.match(r"^[a-zA-Zå-öÅ-Ö ]*$", value): + raise serializers.ValidationError( + "First Name can only contain letters and spaces." + ) + + +def validate_last_name(value): + # Check if the first name contains only characters + if not re.match(r"^[a-zA-Zå-öÅ-Ö ]*$", value): + raise serializers.ValidationError( + "Last Name can only contain letters and spaces." + ) diff --git a/backendapi/urls.py b/backendapi/urls.py index 692238f..d78b803 100644 --- a/backendapi/urls.py +++ b/backendapi/urls.py @@ -6,4 +6,5 @@ urlpatterns = [ path("nfctag/", views.scanned), + path("test", views.api_get, name="api_get"), ] diff --git a/backendapi/views.py b/backendapi/views.py index 9222937..9894a8a 100644 --- a/backendapi/views.py +++ b/backendapi/views.py @@ -3,9 +3,14 @@ from django.views.decorators.http import require_POST from django.views.decorators.cache import never_cache from django.http import JsonResponse - from database.models import Attendant +from rest_framework.decorators import api_view +from rest_framework.response import Response +from rest_framework import status +from backendapi import exceptions +from .serializers import AttendantAdmin + @csrf_exempt @require_POST @@ -18,3 +23,83 @@ def scanned(request, tag: bytes): except Attendant.DoesNotExist: return JsonResponse({"error": "No such tag", "valid": False}, status=404) + + +@api_view(["GET", "POST", "PUT", "PATCH", "DELETE"]) +def api_get(request, pk=None): + if request.method == "GET": + # If there's no 'pk' parameter, return all attendants + if pk is None: + attendants = Attendant.objects.all() + serializer = AttendantAdmin(attendants, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + # Otherwise, return a single attendant + try: + attendant = Attendant.objects.get(pk=pk) + serializer = AttendantAdmin(attendant) + return Response(serializer.data, status=status.HTTP_200_OK) + except Attendant.DoesNotExist: + return Response( + {"detail": "Attendant not found."}, status=status.HTTP_404_NOT_FOUND + ) + + elif request.method == "POST": + # Create a new attendant + serializer = AttendantAdmin(data=request.data) + if serializer.is_valid(): + serializer.save() # Save the new attendant to the database + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + elif request.method == "PUT": + # Full update of an existing attendant + try: + attendant = Attendant.objects.get(pk=pk) + except Attendant.DoesNotExist: + return Response( + {"detail": "Attendant not found."}, status=status.HTTP_404_NOT_FOUND + ) + + serializer = AttendantAdmin(attendant, data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + elif request.method == "PATCH": + # Partial update of an existing attendant + try: + attendant = Attendant.objects.get(pk=pk) + except Attendant.DoesNotExist: + return Response( + {"detail": "Attendant not found."}, status=status.HTTP_404_NOT_FOUND + ) + + serializer = AttendantAdmin(attendant, data=request.data, partial=True) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + elif request.method == "DELETE": + # Delete an existing attendant + try: + attendant = Attendant.objects.get(pk=pk) + except Attendant.DoesNotExist: + return Response( + {"detail": "Attendant not found."}, status=status.HTTP_404_NOT_FOUND + ) + + attendant.delete() + return Response( + {"detail": "Attendant deleted successfully."}, + status=status.HTTP_204_NO_CONTENT, + ) + + +""" +def api_get(request): + if request.method == "GET": + return Response({"message": "GET request received"}, status=202) + elif request.method == "POST": + return Response({"message": "POST request received"}, status=405) """ diff --git a/config/settings.py b/config/settings.py index 0764513..0461969 100644 --- a/config/settings.py +++ b/config/settings.py @@ -44,6 +44,7 @@ # --- "database", "backendapi", + "rest_framework", ] MIDDLEWARE = [ diff --git a/requirements.txt b/requirements.txt index edb6592..dfdad0a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,5 @@ Django[all]==5.1.3 django-urlconfchecks==0.11.0 # TODO: Add to CI daphne==4.1.2 psycopg2-binary==2.9.10 +djangorestframework==3.15.2 + From 56a9678800018aae59fa64f86ab67d6368c2ec6d Mon Sep 17 00:00:00 2001 From: Freddy Date: Fri, 14 Feb 2025 14:01:13 +0100 Subject: [PATCH 02/11] Basic_Django_setup --- .../migrations/0002_delete_attendant.py | 16 +++++ backendapi/urls.py | 1 - backendapi/views.py | 6 ++ config/settings.py | 11 ++++ config/urls.py | 4 +- database | 2 +- requirements.txt | 1 + theme/__init__.py | 0 theme/apps.py | 5 ++ theme/static_src/.gitignore | 1 + theme/static_src/package.json | 29 ++++++++++ theme/static_src/postcss.config.js | 7 +++ theme/static_src/src/styles.css | 3 + theme/static_src/tailwind.config.js | 58 +++++++++++++++++++ theme/templates/base.html | 19 ++++++ theme/templates/registration.html | 8 +++ 16 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 backendapi/migrations/0002_delete_attendant.py create mode 100644 theme/__init__.py create mode 100644 theme/apps.py create mode 100644 theme/static_src/.gitignore create mode 100644 theme/static_src/package.json create mode 100644 theme/static_src/postcss.config.js create mode 100644 theme/static_src/src/styles.css create mode 100644 theme/static_src/tailwind.config.js create mode 100644 theme/templates/base.html create mode 100644 theme/templates/registration.html diff --git a/backendapi/migrations/0002_delete_attendant.py b/backendapi/migrations/0002_delete_attendant.py new file mode 100644 index 0000000..9b6c35f --- /dev/null +++ b/backendapi/migrations/0002_delete_attendant.py @@ -0,0 +1,16 @@ +# Generated by Django 5.1.3 on 2025-01-06 22:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('backendapi', '0001_initial'), + ] + + operations = [ + migrations.DeleteModel( + name='Attendant', + ), + ] diff --git a/backendapi/urls.py b/backendapi/urls.py index d78b803..ae64679 100644 --- a/backendapi/urls.py +++ b/backendapi/urls.py @@ -1,5 +1,4 @@ from django.urls import path, register_converter - from . import views, converters register_converter(converters.BinaryHexConverter, "hex") diff --git a/backendapi/views.py b/backendapi/views.py index 9894a8a..495400c 100644 --- a/backendapi/views.py +++ b/backendapi/views.py @@ -103,3 +103,9 @@ def api_get(request): return Response({"message": "GET request received"}, status=202) elif request.method == "POST": return Response({"message": "POST request received"}, status=405) """ + +def base_view(request): #basic frontend registration view. + return render(request, "base.html") + +def registration_view(request): + return render(request, "registration.html") diff --git a/config/settings.py b/config/settings.py index 0461969..304a139 100644 --- a/config/settings.py +++ b/config/settings.py @@ -13,6 +13,7 @@ import os from pathlib import Path + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -45,6 +46,8 @@ "database", "backendapi", "rest_framework", + "tailwind", + "theme", ] MIDDLEWARE = [ @@ -130,8 +133,16 @@ STATIC_URL = "static/" STATIC_ROOT = os.getenv("DJANGO_STATIC_ROOT") +TAILWIND_APP_NAME = 'theme' # Default primary key field type # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +INTERNAL_IPS = [ + "127.0.0.1", +] + + +NPM_BIN_PATH = os.getenv("NPM_BIN_PATH", "/default/path/to/npm") diff --git a/config/urls.py b/config/urls.py index 282345a..a98325b 100644 --- a/config/urls.py +++ b/config/urls.py @@ -17,10 +17,12 @@ from django.contrib import admin from django.urls import include, path - import backendapi.urls +from backendapi import views urlpatterns = [ path("admin/", admin.site.urls), path("api/", include(backendapi.urls)), + path("",views.base_view, name="base"), + path("Registration",views.registration_view, name="registration") ] diff --git a/database b/database index 18800c3..09dd476 160000 --- a/database +++ b/database @@ -1 +1 @@ -Subproject commit 18800c34545d9b030c4af7d1e3923248e0a43b64 +Subproject commit 09dd47637a9a7ff4ea39a59778e9eb808f8eed7d diff --git a/requirements.txt b/requirements.txt index dfdad0a..52c8a92 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ django-urlconfchecks==0.11.0 # TODO: Add to CI daphne==4.1.2 psycopg2-binary==2.9.10 djangorestframework==3.15.2 +django-tailwind>=3.6.0 diff --git a/theme/__init__.py b/theme/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/theme/apps.py b/theme/apps.py new file mode 100644 index 0000000..bec7464 --- /dev/null +++ b/theme/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ThemeConfig(AppConfig): + name = 'theme' diff --git a/theme/static_src/.gitignore b/theme/static_src/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/theme/static_src/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/theme/static_src/package.json b/theme/static_src/package.json new file mode 100644 index 0000000..55ac6e0 --- /dev/null +++ b/theme/static_src/package.json @@ -0,0 +1,29 @@ +{ + "name": "theme", + "version": "3.6.0", + "description": "", + "scripts": { + "start": "npm run dev", + "build": "npm run build:clean && npm run build:tailwind", + "build:clean": "rimraf ../static/css/dist", + "build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css --minify", + "dev": "cross-env NODE_ENV=development tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css -w", + "tailwindcss": "node ./node_modules/tailwindcss/lib/cli.js" + }, + "keywords": [], + "author": "", + "license": "MIT", + "devDependencies": { + "@tailwindcss/aspect-ratio": "^0.4.2", + "@tailwindcss/forms": "^0.5.3", + "@tailwindcss/line-clamp": "^0.4.4", + "@tailwindcss/typography": "^0.5.9", + "cross-env": "^7.0.3", + "postcss": "^8.4.24", + "postcss-import": "^15.1.0", + "postcss-nested": "^6.0.1", + "postcss-simple-vars": "^7.0.1", + "rimraf": "^5.0.1", + "tailwindcss": "^3.3.2" + } +} diff --git a/theme/static_src/postcss.config.js b/theme/static_src/postcss.config.js new file mode 100644 index 0000000..0b09b34 --- /dev/null +++ b/theme/static_src/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: { + "postcss-import": {}, + "postcss-simple-vars": {}, + "postcss-nested": {} + }, +} diff --git a/theme/static_src/src/styles.css b/theme/static_src/src/styles.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/theme/static_src/src/styles.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/theme/static_src/tailwind.config.js b/theme/static_src/tailwind.config.js new file mode 100644 index 0000000..28f3b7b --- /dev/null +++ b/theme/static_src/tailwind.config.js @@ -0,0 +1,58 @@ +/** + * This is a minimal config. + * + * If you need the full config, get it from here: + * https://unpkg.com/browse/tailwindcss@latest/stubs/defaultConfig.stub.js + */ + +module.exports = { + content: [ + /** + * HTML. Paths to Django template files that will contain Tailwind CSS classes. + */ + + /* Templates within theme app (/templates), e.g. base.html. */ + '../templates/**/*.html', + + /* + * Main templates directory of the project (BASE_DIR/templates). + * Adjust the following line to match your project structure. + */ + '../../templates/**/*.html', + + /* + * Templates in other django apps (BASE_DIR//templates). + * Adjust the following line to match your project structure. + */ + '../../**/templates/**/*.html', + + /** + * JS: If you use Tailwind CSS in JavaScript, uncomment the following lines and make sure + * patterns match your project structure. + */ + /* JS 1: Ignore any JavaScript in node_modules folder. */ + // '!../../**/node_modules', + /* JS 2: Process all JavaScript files in the project. */ + // '../../**/*.js', + + /** + * Python: If you use Tailwind CSS classes in Python, uncomment the following line + * and make sure the pattern below matches your project structure. + */ + // '../../**/*.py' + ], + theme: { + extend: {}, + }, + plugins: [ + /** + * '@tailwindcss/forms' is the forms plugin that provides a minimal styling + * for forms. If you don't like it or have own styling for forms, + * comment the line below to disable '@tailwindcss/forms'. + */ + require('@tailwindcss/forms'), + require('@tailwindcss/typography'), + require('@tailwindcss/line-clamp'), + require('@tailwindcss/aspect-ratio'), + ], +} diff --git a/theme/templates/base.html b/theme/templates/base.html new file mode 100644 index 0000000..0c40aeb --- /dev/null +++ b/theme/templates/base.html @@ -0,0 +1,19 @@ +{% load static tailwind_tags %} + + + + Django Tailwind + + + + {% tailwind_css %} + + + +
+
+

Django + Tailwind = ❤️

+
+
+ + diff --git a/theme/templates/registration.html b/theme/templates/registration.html new file mode 100644 index 0000000..751812c --- /dev/null +++ b/theme/templates/registration.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% block title %}Home - MySite{% endblock %} + +{% block content %} +

Welcome to MySite!

+

This is the home page.

+{% endblock %} From ee280840bd9f437f04e5d31dacefec5ac1f3afd0 Mon Sep 17 00:00:00 2001 From: Freddy Date: Sat, 15 Feb 2025 01:06:03 +0100 Subject: [PATCH 03/11] Savepoint_commit. Add_Registration_skeleton --- backendapi/forms.py | 11 +++++++++++ backendapi/migrations/0003_initial.py | 25 +++++++++++++++++++++++++ backendapi/views.py | 6 +++++- config/settings.py | 3 +++ requirements.txt | 1 + theme/templates/base.html | 5 ++--- theme/templates/registration.html | 12 +++++++++--- 7 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 backendapi/forms.py create mode 100644 backendapi/migrations/0003_initial.py diff --git a/backendapi/forms.py b/backendapi/forms.py new file mode 100644 index 0000000..15ac170 --- /dev/null +++ b/backendapi/forms.py @@ -0,0 +1,11 @@ +from django import forms + + + +class RegistrationForm(forms.Form): + name = forms.CharField(label="Enter your name", max_length=100, required=True) + surname = forms.CharField(label="Surname", max_length=100, required=True) + discord = forms.CharField(label="Discord", max_length=100, required=True) + phone = forms.CharField(label="Phone", max_length=100, required=True) + crew = forms.CharField(label="Crew", max_length=100, required=True) + diff --git a/backendapi/migrations/0003_initial.py b/backendapi/migrations/0003_initial.py new file mode 100644 index 0000000..683e095 --- /dev/null +++ b/backendapi/migrations/0003_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.7 on 2025-02-14 20:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('backendapi', '0002_delete_attendant'), + ] + + operations = [ + migrations.CreateModel( + name='Attendant', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=30)), + ('last_name', models.CharField(max_length=30)), + ('email', models.EmailField(max_length=100)), + ('phone_number', models.CharField(max_length=12)), + ], + ), + ] diff --git a/backendapi/views.py b/backendapi/views.py index 495400c..1a26e54 100644 --- a/backendapi/views.py +++ b/backendapi/views.py @@ -11,6 +11,8 @@ from backendapi import exceptions from .serializers import AttendantAdmin +from backendapi.forms import RegistrationForm + @csrf_exempt @require_POST @@ -107,5 +109,7 @@ def api_get(request): def base_view(request): #basic frontend registration view. return render(request, "base.html") + def registration_view(request): - return render(request, "registration.html") + context = {'form' : RegistrationForm()} + return render(request, "registration.html", context) diff --git a/config/settings.py b/config/settings.py index 304a139..5888798 100644 --- a/config/settings.py +++ b/config/settings.py @@ -48,6 +48,7 @@ "rest_framework", "tailwind", "theme", + "crispy_forms", ] MIDDLEWARE = [ @@ -146,3 +147,5 @@ NPM_BIN_PATH = os.getenv("NPM_BIN_PATH", "/default/path/to/npm") +CRISPY_TEMPLATE_PACK = 'uni_form' + diff --git a/requirements.txt b/requirements.txt index 52c8a92..00bdf58 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ daphne==4.1.2 psycopg2-binary==2.9.10 djangorestframework==3.15.2 django-tailwind>=3.6.0 +django-crispy-forms==2.3 diff --git a/theme/templates/base.html b/theme/templates/base.html index 0c40aeb..fb504b3 100644 --- a/theme/templates/base.html +++ b/theme/templates/base.html @@ -11,9 +11,8 @@
-
-

Django + Tailwind = ❤️

-
+ {% block content %} + {% endblock %}
diff --git a/theme/templates/registration.html b/theme/templates/registration.html index 751812c..794d26c 100644 --- a/theme/templates/registration.html +++ b/theme/templates/registration.html @@ -1,8 +1,14 @@ {% extends "base.html" %} +{% load crispy_forms_tags %} -{% block title %}Home - MySite{% endblock %} +{% block title %}registration{% endblock %} {% block content %} -

Welcome to MySite!

-

This is the home page.

+

foo

+
+ {% csrf_token %} + {{ form }} + + asdasd +
{% endblock %} From 83bb112554ea3f36889ef36e3af39ea57376586c Mon Sep 17 00:00:00 2001 From: Freddy Date: Sun, 16 Feb 2025 17:13:18 +0100 Subject: [PATCH 04/11] add_automatic_reload --- config/settings.py | 10 ++++++---- requirements.txt | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/config/settings.py b/config/settings.py index 5888798..7c79fba 100644 --- a/config/settings.py +++ b/config/settings.py @@ -48,7 +48,8 @@ "rest_framework", "tailwind", "theme", - "crispy_forms", + "django_browser_reload", + ] MIDDLEWARE = [ @@ -59,6 +60,8 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django_browser_reload.middleware.BrowserReloadMiddleware", + ] ROOT_URLCONF = "config.urls" @@ -144,8 +147,7 @@ INTERNAL_IPS = [ "127.0.0.1", ] +TAILWIND_APP_NAME = 'theme' - -NPM_BIN_PATH = os.getenv("NPM_BIN_PATH", "/default/path/to/npm") -CRISPY_TEMPLATE_PACK = 'uni_form' +NPM_BIN_PATH = os.getenv("NPM_BIN_PATH") diff --git a/requirements.txt b/requirements.txt index 00bdf58..9a88eae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,6 @@ daphne==4.1.2 psycopg2-binary==2.9.10 djangorestframework==3.15.2 django-tailwind>=3.6.0 -django-crispy-forms==2.3 +django-browser-reload==1.13.0 + From a10343b18041bd23e0678e3321bf66199679ed89 Mon Sep 17 00:00:00 2001 From: Freddy Date: Sun, 16 Feb 2025 17:14:01 +0100 Subject: [PATCH 05/11] add_tailwindcss, Removed crispyforms --- config/urls.py | 4 +++- theme/templates/base.html | 3 ++- theme/templates/registration.html | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config/urls.py b/config/urls.py index a98325b..36b86fe 100644 --- a/config/urls.py +++ b/config/urls.py @@ -20,9 +20,11 @@ import backendapi.urls from backendapi import views + urlpatterns = [ path("admin/", admin.site.urls), path("api/", include(backendapi.urls)), path("",views.base_view, name="base"), - path("Registration",views.registration_view, name="registration") + path("Registration",views.registration_view, name="registration"), + path("__reload__/", include("django_browser_reload.urls")), ] diff --git a/theme/templates/base.html b/theme/templates/base.html index fb504b3..53dc63e 100644 --- a/theme/templates/base.html +++ b/theme/templates/base.html @@ -1,4 +1,5 @@ -{% load static tailwind_tags %} +{% load tailwind_tags %} + diff --git a/theme/templates/registration.html b/theme/templates/registration.html index 794d26c..fcc4c0a 100644 --- a/theme/templates/registration.html +++ b/theme/templates/registration.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load crispy_forms_tags %} + {% block title %}registration{% endblock %} From b94656f2b5a1d0de6f42c1fdbfad798110285ee7 Mon Sep 17 00:00:00 2001 From: Freddy Date: Mon, 17 Feb 2025 17:31:58 +0100 Subject: [PATCH 06/11] add_tailwindcss, crispy_forms --- backendapi/forms.py | 9 ++++----- config/settings.py | 6 +++++- requirements.txt | 1 + theme/templates/registration.html | 24 +++++++++++++++++------- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/backendapi/forms.py b/backendapi/forms.py index 15ac170..b3c7abb 100644 --- a/backendapi/forms.py +++ b/backendapi/forms.py @@ -3,9 +3,8 @@ class RegistrationForm(forms.Form): - name = forms.CharField(label="Enter your name", max_length=100, required=True) - surname = forms.CharField(label="Surname", max_length=100, required=True) - discord = forms.CharField(label="Discord", max_length=100, required=True) - phone = forms.CharField(label="Phone", max_length=100, required=True) + first_name = forms.CharField(label="Enter your name", max_length=100, required=True) + last_name = forms.CharField(label="Last Name", max_length=100, required=True) + email = forms.CharField(label="Discord", max_length=100, required=True) + phone_number = forms.CharField(label="Phone", max_length=100, required=True) crew = forms.CharField(label="Crew", max_length=100, required=True) - diff --git a/config/settings.py b/config/settings.py index 7c79fba..45b704e 100644 --- a/config/settings.py +++ b/config/settings.py @@ -49,7 +49,8 @@ "tailwind", "theme", "django_browser_reload", - + "crispy_forms", + "crispy_tailwind", ] MIDDLEWARE = [ @@ -151,3 +152,6 @@ NPM_BIN_PATH = os.getenv("NPM_BIN_PATH") +CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind" + +CRISPY_TEMPLATE_PACK = "tailwind" diff --git a/requirements.txt b/requirements.txt index 9a88eae..7820ace 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,6 @@ psycopg2-binary==2.9.10 djangorestframework==3.15.2 django-tailwind>=3.6.0 django-browser-reload==1.13.0 +crispy-tailwind==0.5.0 diff --git a/theme/templates/registration.html b/theme/templates/registration.html index fcc4c0a..d1df4b9 100644 --- a/theme/templates/registration.html +++ b/theme/templates/registration.html @@ -1,14 +1,24 @@ {% extends "base.html" %} +{% load tailwind_filters %} {% block title %}registration{% endblock %} {% block content %} -

foo

-
- {% csrf_token %} - {{ form }} - - asdasd -
+
+

Registration Form

+ +
+ {% csrf_token %} + + + {{ form|crispy }} + + + +
+
{% endblock %} From 25c7b455fff9c244a29350e3a82aa7fbfe3095b6 Mon Sep 17 00:00:00 2001 From: Freddy Date: Mon, 17 Feb 2025 18:47:00 +0100 Subject: [PATCH 07/11] I HAVE TO USE VANILLA CSS, God give me strenght --- config/settings.py | 14 -------------- config/urls.py | 1 - requirements.txt | 3 --- theme/templates/base.html | 7 ++----- theme/templates/registration.html | 12 ++++-------- 5 files changed, 6 insertions(+), 31 deletions(-) diff --git a/config/settings.py b/config/settings.py index 45b704e..078664b 100644 --- a/config/settings.py +++ b/config/settings.py @@ -46,11 +46,7 @@ "database", "backendapi", "rest_framework", - "tailwind", "theme", - "django_browser_reload", - "crispy_forms", - "crispy_tailwind", ] MIDDLEWARE = [ @@ -61,7 +57,6 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - "django_browser_reload.middleware.BrowserReloadMiddleware", ] @@ -145,13 +140,4 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -INTERNAL_IPS = [ - "127.0.0.1", -] -TAILWIND_APP_NAME = 'theme' - -NPM_BIN_PATH = os.getenv("NPM_BIN_PATH") - -CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind" -CRISPY_TEMPLATE_PACK = "tailwind" diff --git a/config/urls.py b/config/urls.py index 36b86fe..4b6cae3 100644 --- a/config/urls.py +++ b/config/urls.py @@ -26,5 +26,4 @@ path("api/", include(backendapi.urls)), path("",views.base_view, name="base"), path("Registration",views.registration_view, name="registration"), - path("__reload__/", include("django_browser_reload.urls")), ] diff --git a/requirements.txt b/requirements.txt index 7820ace..e6a6dd2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,8 +3,5 @@ django-urlconfchecks==0.11.0 # TODO: Add to CI daphne==4.1.2 psycopg2-binary==2.9.10 djangorestframework==3.15.2 -django-tailwind>=3.6.0 -django-browser-reload==1.13.0 -crispy-tailwind==0.5.0 diff --git a/theme/templates/base.html b/theme/templates/base.html index 53dc63e..0b061eb 100644 --- a/theme/templates/base.html +++ b/theme/templates/base.html @@ -1,5 +1,3 @@ -{% load tailwind_tags %} - @@ -7,11 +5,10 @@ - {% tailwind_css %} - -
+ +
{% block content %} {% endblock %}
diff --git a/theme/templates/registration.html b/theme/templates/registration.html index d1df4b9..a43d48f 100644 --- a/theme/templates/registration.html +++ b/theme/templates/registration.html @@ -1,22 +1,18 @@ {% extends "base.html" %} -{% load tailwind_filters %} {% block title %}registration{% endblock %} {% block content %} -
-

Registration Form

- -
+
+ {% csrf_token %} - {{ form|crispy }} + {{ form.as_p }} - From c6dcd3efd3b4e04419075020ba3467443d70b6ed Mon Sep 17 00:00:00 2001 From: Freddy Date: Mon, 17 Feb 2025 19:00:35 +0100 Subject: [PATCH 08/11] CODE_cleanup --- theme/static_src/.gitignore | 1 - theme/static_src/package.json | 29 --------------- theme/static_src/postcss.config.js | 7 ---- theme/static_src/src/styles.css | 3 -- theme/static_src/tailwind.config.js | 58 ----------------------------- 5 files changed, 98 deletions(-) delete mode 100644 theme/static_src/.gitignore delete mode 100644 theme/static_src/package.json delete mode 100644 theme/static_src/postcss.config.js delete mode 100644 theme/static_src/src/styles.css delete mode 100644 theme/static_src/tailwind.config.js diff --git a/theme/static_src/.gitignore b/theme/static_src/.gitignore deleted file mode 100644 index 3c3629e..0000000 --- a/theme/static_src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/theme/static_src/package.json b/theme/static_src/package.json deleted file mode 100644 index 55ac6e0..0000000 --- a/theme/static_src/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "theme", - "version": "3.6.0", - "description": "", - "scripts": { - "start": "npm run dev", - "build": "npm run build:clean && npm run build:tailwind", - "build:clean": "rimraf ../static/css/dist", - "build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css --minify", - "dev": "cross-env NODE_ENV=development tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css -w", - "tailwindcss": "node ./node_modules/tailwindcss/lib/cli.js" - }, - "keywords": [], - "author": "", - "license": "MIT", - "devDependencies": { - "@tailwindcss/aspect-ratio": "^0.4.2", - "@tailwindcss/forms": "^0.5.3", - "@tailwindcss/line-clamp": "^0.4.4", - "@tailwindcss/typography": "^0.5.9", - "cross-env": "^7.0.3", - "postcss": "^8.4.24", - "postcss-import": "^15.1.0", - "postcss-nested": "^6.0.1", - "postcss-simple-vars": "^7.0.1", - "rimraf": "^5.0.1", - "tailwindcss": "^3.3.2" - } -} diff --git a/theme/static_src/postcss.config.js b/theme/static_src/postcss.config.js deleted file mode 100644 index 0b09b34..0000000 --- a/theme/static_src/postcss.config.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - plugins: { - "postcss-import": {}, - "postcss-simple-vars": {}, - "postcss-nested": {} - }, -} diff --git a/theme/static_src/src/styles.css b/theme/static_src/src/styles.css deleted file mode 100644 index b5c61c9..0000000 --- a/theme/static_src/src/styles.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/theme/static_src/tailwind.config.js b/theme/static_src/tailwind.config.js deleted file mode 100644 index 28f3b7b..0000000 --- a/theme/static_src/tailwind.config.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * This is a minimal config. - * - * If you need the full config, get it from here: - * https://unpkg.com/browse/tailwindcss@latest/stubs/defaultConfig.stub.js - */ - -module.exports = { - content: [ - /** - * HTML. Paths to Django template files that will contain Tailwind CSS classes. - */ - - /* Templates within theme app (/templates), e.g. base.html. */ - '../templates/**/*.html', - - /* - * Main templates directory of the project (BASE_DIR/templates). - * Adjust the following line to match your project structure. - */ - '../../templates/**/*.html', - - /* - * Templates in other django apps (BASE_DIR//templates). - * Adjust the following line to match your project structure. - */ - '../../**/templates/**/*.html', - - /** - * JS: If you use Tailwind CSS in JavaScript, uncomment the following lines and make sure - * patterns match your project structure. - */ - /* JS 1: Ignore any JavaScript in node_modules folder. */ - // '!../../**/node_modules', - /* JS 2: Process all JavaScript files in the project. */ - // '../../**/*.js', - - /** - * Python: If you use Tailwind CSS classes in Python, uncomment the following line - * and make sure the pattern below matches your project structure. - */ - // '../../**/*.py' - ], - theme: { - extend: {}, - }, - plugins: [ - /** - * '@tailwindcss/forms' is the forms plugin that provides a minimal styling - * for forms. If you don't like it or have own styling for forms, - * comment the line below to disable '@tailwindcss/forms'. - */ - require('@tailwindcss/forms'), - require('@tailwindcss/typography'), - require('@tailwindcss/line-clamp'), - require('@tailwindcss/aspect-ratio'), - ], -} From ed78ca17ee1a3665448313415616ac2a01e8539c Mon Sep 17 00:00:00 2001 From: Freddy Date: Wed, 19 Feb 2025 22:25:25 +0100 Subject: [PATCH 09/11] =?UTF-8?q?Biggest-yolo=20Co-authored-by:=20Odd=20St?= =?UTF-8?q?r=C3=A5b=C3=B8=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backendapi/forms.py | 31 ++++- ...tendant_crew_attendant_discord_and_more.py | 55 ++++++++ ...ndant_crew_alter_attendant_ticketcrewid.py | 23 ++++ backendapi/models.py | 15 ++- backendapi/views.py | 12 +- config/settings.py | 6 +- requirements.txt | 1 + theme/styles.css | 125 ++++++++++++++++++ theme/templates/base.html | 49 ++++++- theme/templates/registration.html | 22 +-- 10 files changed, 309 insertions(+), 30 deletions(-) create mode 100644 backendapi/migrations/0004_attendant_crew_attendant_discord_and_more.py create mode 100644 backendapi/migrations/0005_alter_attendant_crew_alter_attendant_ticketcrewid.py create mode 100644 theme/styles.css diff --git a/backendapi/forms.py b/backendapi/forms.py index b3c7abb..bf94cba 100644 --- a/backendapi/forms.py +++ b/backendapi/forms.py @@ -1,10 +1,29 @@ from django import forms +from .models import Attendant # Import your model + +class RegistrationForm(forms.ModelForm): + class Meta: + model = Attendant # Link the form to the Attendant model + fields = [ + 'first_name', + 'last_name', + 'email', + 'discord', + 'phone_number', + 'crew', + 'ticketCrewID', + 'profile_image' + ] + widgets = { + 'first_name': forms.TextInput(attrs={"class": "form-input", "placeholder": "Ola"}), + 'last_name': forms.TextInput(attrs={"class": "form-input", "placeholder": "Nordmann"}), + 'email': forms.EmailInput(attrs={"class": "form-input", "placeholder": "example@email.com"}), + 'discord': forms.TextInput(attrs={"class": "form-input", "placeholder": "Discord#1234"}), + 'phone_number': forms.TextInput(attrs={"class": "form-input", "placeholder": "+123456789"}), + 'crew': forms.TextInput(attrs={"class": "form-input", "placeholder": "Enter your crew name"}), + 'ticketCrewID': forms.TextInput(attrs={"class": "form-input", "placeholder": "Ticket ID", "disabled": True}), +} + ticketCrewID = forms.CharField(required=False) -class RegistrationForm(forms.Form): - first_name = forms.CharField(label="Enter your name", max_length=100, required=True) - last_name = forms.CharField(label="Last Name", max_length=100, required=True) - email = forms.CharField(label="Discord", max_length=100, required=True) - phone_number = forms.CharField(label="Phone", max_length=100, required=True) - crew = forms.CharField(label="Crew", max_length=100, required=True) diff --git a/backendapi/migrations/0004_attendant_crew_attendant_discord_and_more.py b/backendapi/migrations/0004_attendant_crew_attendant_discord_and_more.py new file mode 100644 index 0000000..6622eba --- /dev/null +++ b/backendapi/migrations/0004_attendant_crew_attendant_discord_and_more.py @@ -0,0 +1,55 @@ +# Generated by Django 4.2.7 on 2025-02-19 18:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backendapi', '0003_initial'), + ] + + operations = [ + migrations.AddField( + model_name='attendant', + name='crew', + field=models.CharField(default='Undefined crew', max_length=100), + ), + migrations.AddField( + model_name='attendant', + name='discord', + field=models.CharField(default=False, max_length=100), + preserve_default=False, + ), + migrations.AddField( + model_name='attendant', + name='profile_image', + field=models.ImageField(blank=True, null=True, upload_to='profile_images/'), + ), + migrations.AddField( + model_name='attendant', + name='ticketCrewID', + field=models.CharField(default=False, max_length=100), + preserve_default=False, + ), + migrations.AlterField( + model_name='attendant', + name='email', + field=models.EmailField(max_length=200), + ), + migrations.AlterField( + model_name='attendant', + name='first_name', + field=models.CharField(max_length=100), + ), + migrations.AlterField( + model_name='attendant', + name='last_name', + field=models.CharField(max_length=100), + ), + migrations.AlterField( + model_name='attendant', + name='phone_number', + field=models.CharField(max_length=15), + ), + ] diff --git a/backendapi/migrations/0005_alter_attendant_crew_alter_attendant_ticketcrewid.py b/backendapi/migrations/0005_alter_attendant_crew_alter_attendant_ticketcrewid.py new file mode 100644 index 0000000..3f4c9b6 --- /dev/null +++ b/backendapi/migrations/0005_alter_attendant_crew_alter_attendant_ticketcrewid.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2025-02-19 18:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backendapi', '0004_attendant_crew_attendant_discord_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='attendant', + name='crew', + field=models.CharField(max_length=100), + ), + migrations.AlterField( + model_name='attendant', + name='ticketCrewID', + field=models.CharField(max_length=100, null=True), + ), + ] diff --git a/backendapi/models.py b/backendapi/models.py index 0e85128..ee60343 100644 --- a/backendapi/models.py +++ b/backendapi/models.py @@ -3,15 +3,18 @@ from django.contrib.auth.models import User -# this is the Attendant model, im unsure if we need more data? Maby date of birth? => 18 years maby? + class Attendant(models.Model): - first_name = models.CharField(max_length=30) - last_name = models.CharField(max_length=30) - email = models.EmailField(max_length=100) - phone_number = models.CharField(max_length=12) + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + email = models.EmailField(max_length=200) + discord = models.CharField(max_length=100) + phone_number = models.CharField(max_length=15) + crew = models.CharField(max_length=100) + ticketCrewID = models.CharField(max_length=100, null=True) + profile_image = models.ImageField(upload_to='profile_images/', blank=True, null=True) def __str__(self): return f"{self.first_name} {self.last_name}" - # Create your models here. diff --git a/backendapi/views.py b/backendapi/views.py index 1a26e54..0c0cc22 100644 --- a/backendapi/views.py +++ b/backendapi/views.py @@ -111,5 +111,15 @@ def base_view(request): #basic frontend registration view. def registration_view(request): - context = {'form' : RegistrationForm()} + context = {"form" : RegistrationForm(), + "success" : True, + } + if request.method == 'POST': + form = RegistrationForm(request.POST, request.FILES) + if form.is_valid(): + form.save() + context["success"] = True + else: + context["success"] = False + return render(request, "registration.html", context) diff --git a/config/settings.py b/config/settings.py index 078664b..723feee 100644 --- a/config/settings.py +++ b/config/settings.py @@ -131,9 +131,11 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ -STATIC_URL = "static/" +STATIC_URL = "/static/" STATIC_ROOT = os.getenv("DJANGO_STATIC_ROOT") -TAILWIND_APP_NAME = 'theme' +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "theme"), +] # Default primary key field type # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field diff --git a/requirements.txt b/requirements.txt index e6a6dd2..96a8cbc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,5 +3,6 @@ django-urlconfchecks==0.11.0 # TODO: Add to CI daphne==4.1.2 psycopg2-binary==2.9.10 djangorestframework==3.15.2 +pillow==11.1.0 diff --git a/theme/styles.css b/theme/styles.css new file mode 100644 index 0000000..195e76a --- /dev/null +++ b/theme/styles.css @@ -0,0 +1,125 @@ +/* General body styles */ +body { + font-family: Arial, sans-serif; + background-color: #f0f0f5; + margin: 0; + padding: 20px; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} + +.container { + max-width: 600px; + width: 100%; + padding: 20px; + box-sizing: border-box; +} + +.form-container { + background-color: #ffffff; + padding: 20px; + border-radius: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + width: 100%; + max-width: 400px; + margin: 0 auto; + box-sizing: border-box; +} + +label { + font-weight: bold; + margin-bottom: 5px; + display: block; +} + +input[type="text"], +input[type="email"] { + width: 100%; + padding: 10px; + margin-bottom: 15px; + font-size: 16px; + border: 1px solid #ccc; + border-radius: 5px; + box-sizing: border-box; +} + +.submit-btn { + background-color: #007bff; + color: white; + padding: 12px; + border: none; + border-radius: 5px; + font-size: 16px; + cursor: pointer; + width: 100%; +} + +.submit-btn:hover { + background-color: #0056b3; +} + +/* Responsive Design */ +@media (max-width: 600px) { + .form-container { + padding: 15px; + } + + input[type="text"], + input[type="email"] { + font-size: 14px; + } + + .submit-btn { + font-size: 14px; + padding: 10px; + } +} + +/* Toast message styles */ +.toast { + visibility: hidden; + max-width: 50px; + height: 50px; + margin-left: -125px; + margin-bottom: 50px; + background-color: #4CAF50; + color: white; + text-align: center; + border-radius: 2px; + padding: 16px; + position: fixed; + z-index: 1; + left: 50%; + bottom: 30px; + font-size: 17px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.toast.show { + visibility: visible; + animation: fadein 0.5s, fadeout 1.5s 4s; +} + +@keyframes fadein { + from { + bottom: 0; + opacity: 0; + } + + to { + bottom: 30px; + opacity: 1; + } +} + +@keyframes fadeout { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} \ No newline at end of file diff --git a/theme/templates/base.html b/theme/templates/base.html index 0b061eb..46f4f84 100644 --- a/theme/templates/base.html +++ b/theme/templates/base.html @@ -1,16 +1,57 @@ +{% load static %} - Django Tailwind + Django Form + -
- {% block content %} - {% endblock %} +
+ {% block toast %} + {% endblock %} +
+
+ {% block content %} + {% endblock %}
+ diff --git a/theme/templates/registration.html b/theme/templates/registration.html index a43d48f..535e3ff 100644 --- a/theme/templates/registration.html +++ b/theme/templates/registration.html @@ -1,20 +1,20 @@ {% extends "base.html" %} - -{% block title %}registration{% endblock %} +{% block title %}User Registration{% endblock %} {% block content %} -
-
+
+ {% csrf_token %} - - {{ form.as_p }} - - - + +
{% endblock %} + +{% block toast %} +{% if success %} +Saved! +{% endif %} +{% endblock %} From c497de6e36be5862aeee731cb89ed32fc6b4dd9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Thu, 20 Feb 2025 11:46:39 +0100 Subject: [PATCH 10/11] Restore database submodule --- database | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database b/database index 09dd476..2bbe058 160000 --- a/database +++ b/database @@ -1 +1 @@ -Subproject commit 09dd47637a9a7ff4ea39a59778e9eb808f8eed7d +Subproject commit 2bbe058ea8287b9db6509d561ec05ec78a9127ad From a33ad33e1ef2da082f5072a4eb7b8763083ed8f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Thu, 27 Feb 2025 12:59:28 +0100 Subject: [PATCH 11/11] Move model to database --- backendapi/admin.py | 8 --- backendapi/converters.py | 4 +- backendapi/forms.py | 71 +++++++++++++------ .../migrations/0002_delete_attendant.py | 4 +- backendapi/migrations/0003_initial.py | 22 ++++-- ...tendant_crew_attendant_discord_and_more.py | 38 +++++----- ...ndant_crew_alter_attendant_ticketcrewid.py | 10 +-- .../migrations/0006_delete_attendant.py | 16 +++++ backendapi/models.py | 15 ---- backendapi/serializers.py | 6 +- backendapi/views.py | 51 +++++++------ config/settings.py | 3 - config/urls.py | 4 +- theme/apps.py | 2 +- theme/{ => static/theme}/styles.css | 0 theme/templates/base.html | 2 +- theme/templates/registration.html | 3 +- 17 files changed, 149 insertions(+), 110 deletions(-) create mode 100644 backendapi/migrations/0006_delete_attendant.py rename theme/{ => static/theme}/styles.css (100%) diff --git a/backendapi/admin.py b/backendapi/admin.py index ab8fb6b..694323f 100644 --- a/backendapi/admin.py +++ b/backendapi/admin.py @@ -1,9 +1 @@ from django.contrib import admin -from .models import Attendant - - -class AttendantAdmin(admin.ModelAdmin): - list_display = ["first_name", "last_name", "email", "phone_number"] - - -admin.site.register(Attendant, AttendantAdmin) diff --git a/backendapi/converters.py b/backendapi/converters.py index 0876959..bf228a7 100644 --- a/backendapi/converters.py +++ b/backendapi/converters.py @@ -5,7 +5,7 @@ class BinaryHexConverter: regex = "(?:[0-9a-fA-F]{2})+" def to_python(self, value: str) -> bytes: - return b16decode(value, casefold=True) + return b16encode(b16decode(value, casefold=True)).decode def to_url(self, value: bytes) -> str: - return b16encode(value).decode() + return value diff --git a/backendapi/forms.py b/backendapi/forms.py index bf94cba..a809537 100644 --- a/backendapi/forms.py +++ b/backendapi/forms.py @@ -1,29 +1,60 @@ from django import forms -from .models import Attendant # Import your model +from database.models import Attendant, Crewmember, Crews + + +class AttendantNFCForm(forms.ModelForm): + prefix = "attendant" -class RegistrationForm(forms.ModelForm): class Meta: - model = Attendant # Link the form to the Attendant model + model = Attendant fields = [ - 'first_name', - 'last_name', - 'email', - 'discord', - 'phone_number', - 'crew', - 'ticketCrewID', - 'profile_image' + "nfc_id", ] widgets = { - 'first_name': forms.TextInput(attrs={"class": "form-input", "placeholder": "Ola"}), - 'last_name': forms.TextInput(attrs={"class": "form-input", "placeholder": "Nordmann"}), - 'email': forms.EmailInput(attrs={"class": "form-input", "placeholder": "example@email.com"}), - 'discord': forms.TextInput(attrs={"class": "form-input", "placeholder": "Discord#1234"}), - 'phone_number': forms.TextInput(attrs={"class": "form-input", "placeholder": "+123456789"}), - 'crew': forms.TextInput(attrs={"class": "form-input", "placeholder": "Enter your crew name"}), - 'ticketCrewID': forms.TextInput(attrs={"class": "form-input", "placeholder": "Ticket ID", "disabled": True}), -} - ticketCrewID = forms.CharField(required=False) + "nfc_id": forms.TextInput( + attrs={ + "class": "form-input", + "placeholder": "Scan NFC tag...", + # "disabled": True, + } + ), + } +class CrewmemberForm(forms.ModelForm): + # Allow multiple (different) forms in single page + # Can also be specified as an argument to the class init + prefix = "crewmember" + class Meta: + model = Crewmember # Link the form to the Attendant model + fields = [ + "first_name", + "last_name", + "email", + "discord", + "phone_number", + "crew", + "profile_image", + ] + widgets = { + "first_name": forms.TextInput( + attrs={"class": "form-input", "placeholder": "Ola"} + ), + "last_name": forms.TextInput( + attrs={"class": "form-input", "placeholder": "Nordmann"} + ), + "email": forms.EmailInput( + attrs={"class": "form-input", "placeholder": "email@example.com"} + ), + "discord": forms.TextInput( + attrs={"class": "form-input", "placeholder": "Discord#1234"} + ), + "phone_number": forms.TextInput( + attrs={"class": "form-input", "placeholder": "+47012345678"} + ), + "crew": forms.TextInput( + # Crews.objects.all(), + attrs={"class": "form-input", "placeholder": "Select crew..."}, + ), + } diff --git a/backendapi/migrations/0002_delete_attendant.py b/backendapi/migrations/0002_delete_attendant.py index 9b6c35f..5bcfc37 100644 --- a/backendapi/migrations/0002_delete_attendant.py +++ b/backendapi/migrations/0002_delete_attendant.py @@ -6,11 +6,11 @@ class Migration(migrations.Migration): dependencies = [ - ('backendapi', '0001_initial'), + ("backendapi", "0001_initial"), ] operations = [ migrations.DeleteModel( - name='Attendant', + name="Attendant", ), ] diff --git a/backendapi/migrations/0003_initial.py b/backendapi/migrations/0003_initial.py index 683e095..641a31e 100644 --- a/backendapi/migrations/0003_initial.py +++ b/backendapi/migrations/0003_initial.py @@ -8,18 +8,26 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('backendapi', '0002_delete_attendant'), + ("backendapi", "0002_delete_attendant"), ] operations = [ migrations.CreateModel( - name='Attendant', + name="Attendant", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('first_name', models.CharField(max_length=30)), - ('last_name', models.CharField(max_length=30)), - ('email', models.EmailField(max_length=100)), - ('phone_number', models.CharField(max_length=12)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("first_name", models.CharField(max_length=30)), + ("last_name", models.CharField(max_length=30)), + ("email", models.EmailField(max_length=100)), + ("phone_number", models.CharField(max_length=12)), ], ), ] diff --git a/backendapi/migrations/0004_attendant_crew_attendant_discord_and_more.py b/backendapi/migrations/0004_attendant_crew_attendant_discord_and_more.py index 6622eba..a1546d2 100644 --- a/backendapi/migrations/0004_attendant_crew_attendant_discord_and_more.py +++ b/backendapi/migrations/0004_attendant_crew_attendant_discord_and_more.py @@ -6,50 +6,50 @@ class Migration(migrations.Migration): dependencies = [ - ('backendapi', '0003_initial'), + ("backendapi", "0003_initial"), ] operations = [ migrations.AddField( - model_name='attendant', - name='crew', - field=models.CharField(default='Undefined crew', max_length=100), + model_name="attendant", + name="crew", + field=models.CharField(default="Undefined crew", max_length=100), ), migrations.AddField( - model_name='attendant', - name='discord', + model_name="attendant", + name="discord", field=models.CharField(default=False, max_length=100), preserve_default=False, ), migrations.AddField( - model_name='attendant', - name='profile_image', - field=models.ImageField(blank=True, null=True, upload_to='profile_images/'), + model_name="attendant", + name="profile_image", + field=models.ImageField(blank=True, null=True, upload_to="profile_images/"), ), migrations.AddField( - model_name='attendant', - name='ticketCrewID', + model_name="attendant", + name="ticketCrewID", field=models.CharField(default=False, max_length=100), preserve_default=False, ), migrations.AlterField( - model_name='attendant', - name='email', + model_name="attendant", + name="email", field=models.EmailField(max_length=200), ), migrations.AlterField( - model_name='attendant', - name='first_name', + model_name="attendant", + name="first_name", field=models.CharField(max_length=100), ), migrations.AlterField( - model_name='attendant', - name='last_name', + model_name="attendant", + name="last_name", field=models.CharField(max_length=100), ), migrations.AlterField( - model_name='attendant', - name='phone_number', + model_name="attendant", + name="phone_number", field=models.CharField(max_length=15), ), ] diff --git a/backendapi/migrations/0005_alter_attendant_crew_alter_attendant_ticketcrewid.py b/backendapi/migrations/0005_alter_attendant_crew_alter_attendant_ticketcrewid.py index 3f4c9b6..86a83e8 100644 --- a/backendapi/migrations/0005_alter_attendant_crew_alter_attendant_ticketcrewid.py +++ b/backendapi/migrations/0005_alter_attendant_crew_alter_attendant_ticketcrewid.py @@ -6,18 +6,18 @@ class Migration(migrations.Migration): dependencies = [ - ('backendapi', '0004_attendant_crew_attendant_discord_and_more'), + ("backendapi", "0004_attendant_crew_attendant_discord_and_more"), ] operations = [ migrations.AlterField( - model_name='attendant', - name='crew', + model_name="attendant", + name="crew", field=models.CharField(max_length=100), ), migrations.AlterField( - model_name='attendant', - name='ticketCrewID', + model_name="attendant", + name="ticketCrewID", field=models.CharField(max_length=100, null=True), ), ] diff --git a/backendapi/migrations/0006_delete_attendant.py b/backendapi/migrations/0006_delete_attendant.py new file mode 100644 index 0000000..2e0e2fc --- /dev/null +++ b/backendapi/migrations/0006_delete_attendant.py @@ -0,0 +1,16 @@ +# Generated by Django 5.1.5 on 2025-02-20 14:45 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("backendapi", "0005_alter_attendant_crew_alter_attendant_ticketcrewid"), + ] + + operations = [ + migrations.DeleteModel( + name="Attendant", + ), + ] diff --git a/backendapi/models.py b/backendapi/models.py index ee60343..4548db2 100644 --- a/backendapi/models.py +++ b/backendapi/models.py @@ -2,19 +2,4 @@ from rest_framework import serializers from django.contrib.auth.models import User - - -class Attendant(models.Model): - first_name = models.CharField(max_length=100) - last_name = models.CharField(max_length=100) - email = models.EmailField(max_length=200) - discord = models.CharField(max_length=100) - phone_number = models.CharField(max_length=15) - crew = models.CharField(max_length=100) - ticketCrewID = models.CharField(max_length=100, null=True) - profile_image = models.ImageField(upload_to='profile_images/', blank=True, null=True) - - def __str__(self): - return f"{self.first_name} {self.last_name}" - # Create your models here. diff --git a/backendapi/serializers.py b/backendapi/serializers.py index 852a20c..149a578 100644 --- a/backendapi/serializers.py +++ b/backendapi/serializers.py @@ -1,13 +1,13 @@ import re from rest_framework import serializers from django.conf import settings -from .models import Attendant +from database.models import Crewmember # Serializer for the Attendant model: handles validation, serialization, and desersialization of data. # Change the model later depending on requirements. Please tell me what, and il remake the model later to fit requirements. -class AttendantAdmin(serializers.ModelSerializer): # defined a serialiser class +class CrewmemberAdmin(serializers.ModelSerializer): # defined a serialiser class first_name = serializers.CharField( label=("First Name* "), # Labels for the field required=True, # This makes the fields required. @@ -68,7 +68,7 @@ class AttendantAdmin(serializers.ModelSerializer): # defined a serialiser class ) class Meta: - model = Attendant + model = Crewmember fields = ["first_name", "last_name", "email", "phone_number"] diff --git a/backendapi/views.py b/backendapi/views.py index 0c0cc22..00debcf 100644 --- a/backendapi/views.py +++ b/backendapi/views.py @@ -3,21 +3,22 @@ from django.views.decorators.http import require_POST from django.views.decorators.cache import never_cache from django.http import JsonResponse -from database.models import Attendant from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status -from backendapi import exceptions -from .serializers import AttendantAdmin -from backendapi.forms import RegistrationForm +from database.models import Attendant, Crewmember + +from . import exceptions +from .serializers import CrewmemberAdmin +from .forms import CrewmemberForm, AttendantNFCForm @csrf_exempt @require_POST @never_cache -def scanned(request, tag: bytes): +def scanned(request, tag: str): try: attendant = Attendant.objects.get(nfc_id=tag) # TODO: Queue event @@ -33,12 +34,12 @@ def api_get(request, pk=None): # If there's no 'pk' parameter, return all attendants if pk is None: attendants = Attendant.objects.all() - serializer = AttendantAdmin(attendants, many=True) + serializer = CrewmemberAdmin(attendants, many=True) return Response(serializer.data, status=status.HTTP_200_OK) # Otherwise, return a single attendant try: attendant = Attendant.objects.get(pk=pk) - serializer = AttendantAdmin(attendant) + serializer = CrewmemberAdmin(attendant) return Response(serializer.data, status=status.HTTP_200_OK) except Attendant.DoesNotExist: return Response( @@ -47,7 +48,7 @@ def api_get(request, pk=None): elif request.method == "POST": # Create a new attendant - serializer = AttendantAdmin(data=request.data) + serializer = CrewmemberAdmin(data=request.data) if serializer.is_valid(): serializer.save() # Save the new attendant to the database return Response(serializer.data, status=status.HTTP_201_CREATED) @@ -62,7 +63,7 @@ def api_get(request, pk=None): {"detail": "Attendant not found."}, status=status.HTTP_404_NOT_FOUND ) - serializer = AttendantAdmin(attendant, data=request.data) + serializer = CrewmemberAdmin(attendant, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) @@ -77,7 +78,7 @@ def api_get(request, pk=None): {"detail": "Attendant not found."}, status=status.HTTP_404_NOT_FOUND ) - serializer = AttendantAdmin(attendant, data=request.data, partial=True) + serializer = CrewmemberAdmin(attendant, data=request.data, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) @@ -106,20 +107,28 @@ def api_get(request): elif request.method == "POST": return Response({"message": "POST request received"}, status=405) """ -def base_view(request): #basic frontend registration view. + +def base_view(request): # basic frontend registration view. return render(request, "base.html") def registration_view(request): - context = {"form" : RegistrationForm(), - "success" : True, - } - if request.method == 'POST': - form = RegistrationForm(request.POST, request.FILES) - if form.is_valid(): - form.save() - context["success"] = True + success = None + if request.method == "POST": + cmform = CrewmemberForm(request.POST, request.FILES) + nfcform = AttendantNFCForm(request.POST, request.FILES) + if cmform.is_valid(): + cmform.save() + success = True else: - context["success"] = False - + success = False + else: + cmform = CrewmemberForm() + nfcform = AttendantNFCForm() + + context = { + "cmform": cmform, + "nfcform": nfcform, + "success": success, + } return render(request, "registration.html", context) diff --git a/config/settings.py b/config/settings.py index 723feee..6400c24 100644 --- a/config/settings.py +++ b/config/settings.py @@ -57,7 +57,6 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - ] ROOT_URLCONF = "config.urls" @@ -141,5 +140,3 @@ # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" - - diff --git a/config/urls.py b/config/urls.py index 4b6cae3..42b5903 100644 --- a/config/urls.py +++ b/config/urls.py @@ -24,6 +24,6 @@ urlpatterns = [ path("admin/", admin.site.urls), path("api/", include(backendapi.urls)), - path("",views.base_view, name="base"), - path("Registration",views.registration_view, name="registration"), + path("", views.base_view, name="base"), + path("registration", views.registration_view, name="registration"), ] diff --git a/theme/apps.py b/theme/apps.py index bec7464..dd24136 100644 --- a/theme/apps.py +++ b/theme/apps.py @@ -2,4 +2,4 @@ class ThemeConfig(AppConfig): - name = 'theme' + name = "theme" diff --git a/theme/styles.css b/theme/static/theme/styles.css similarity index 100% rename from theme/styles.css rename to theme/static/theme/styles.css diff --git a/theme/templates/base.html b/theme/templates/base.html index 46f4f84..930abca 100644 --- a/theme/templates/base.html +++ b/theme/templates/base.html @@ -6,7 +6,7 @@ - + diff --git a/theme/templates/registration.html b/theme/templates/registration.html index 535e3ff..f00c71b 100644 --- a/theme/templates/registration.html +++ b/theme/templates/registration.html @@ -6,7 +6,8 @@
{% csrf_token %} - {{ form.as_p }} + {{ cmform.as_p }} + {{ nfcform.as_p }}