diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/azube/__init__.py b/azube/__init__.py old mode 100644 new mode 100755 diff --git a/azube/asgi.py b/azube/asgi.py old mode 100644 new mode 100755 diff --git a/azube/settings.py b/azube/settings.py old mode 100644 new mode 100755 index fbe6678..f990dc2 --- a/azube/settings.py +++ b/azube/settings.py @@ -37,6 +37,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + "core" ] MIDDLEWARE = [ diff --git a/azube/urls.py b/azube/urls.py old mode 100644 new mode 100755 index 2b30f1a..0b36a09 --- a/azube/urls.py +++ b/azube/urls.py @@ -15,8 +15,9 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), + path('', include('core.urls')) ] diff --git a/azube/wsgi.py b/azube/wsgi.py old mode 100644 new mode 100755 diff --git a/core/__init__.py b/core/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/core/admin.py b/core/admin.py new file mode 100755 index 0000000..8c38f3f --- /dev/null +++ b/core/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/core/apps.py b/core/apps.py new file mode 100755 index 0000000..0e27c08 --- /dev/null +++ b/core/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MainAppConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'core' diff --git a/core/azure_auth.py b/core/azure_auth.py new file mode 100755 index 0000000..90eeb01 --- /dev/null +++ b/core/azure_auth.py @@ -0,0 +1,28 @@ +import json +import base64 + +class AzureUser: + display_name: str + id: str + claims: list + + def __init__(self, request): + try: + # X-MS-CLIENT-PRINCIPAL-ID + self.id = request.headers["X-MS-CLIENT-PRINCIPAL-ID"] + + # X-MS-CLIENT-PRINCIPAL-NAME + self.id = request.headers["X-MS-CLIENT-PRINCIPAL-NAME"] + + # X-MS-CLIENT-PRINCIPAL + claims_json = json.loads(base64.decode(request.headers["X-MS-CLIENT-PRINCIPAL"])) + claims = {} + + for claim in claims_json["claims"]: + claims[claim["typ"]] = claim["val"] + + self.claims = claims + except: + self.display_name = "Anon" + self.id = "anon" + diff --git a/core/doc_gen.py b/core/doc_gen.py new file mode 100755 index 0000000..b5f6bb6 --- /dev/null +++ b/core/doc_gen.py @@ -0,0 +1,11 @@ +import json + +def gen_doc(template: str, vars: dict) -> str: + definition = json.loads(open(f"{template}.json").read()) + content = open(f"{template}.html").read() + + for var in definition["vars"]: + var_r = var["name"].upper() + content = content.replace(f"[[{var_r}]]", vars[var["name"]]) + + return content \ No newline at end of file diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100755 index 0000000..5d758e6 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.16 on 2024-12-02 12:55 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Berichtsheft', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('year', models.PositiveIntegerField()), + ('week', models.PositiveSmallIntegerField()), + ('content', models.JSONField()), + ('approved_by', models.JSONField()), + ('created', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='berichtshefte', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/core/migrations/0002_alter_berichtsheft_id.py b/core/migrations/0002_alter_berichtsheft_id.py new file mode 100755 index 0000000..be15824 --- /dev/null +++ b/core/migrations/0002_alter_berichtsheft_id.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2024-12-02 13:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='berichtsheft', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + ] diff --git a/core/migrations/0003_group_azureuser_alter_berichtsheft_user.py b/core/migrations/0003_group_azureuser_alter_berichtsheft_user.py new file mode 100755 index 0000000..794c758 --- /dev/null +++ b/core/migrations/0003_group_azureuser_alter_berichtsheft_user.py @@ -0,0 +1,63 @@ +# Generated by Django 4.2.16 on 2024-12-02 14:28 + +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ('core', '0002_alter_berichtsheft_id'), + ] + + operations = [ + migrations.CreateModel( + name='Group', + fields=[ + ], + options={ + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('auth.group',), + managers=[ + ('objects', django.contrib.auth.models.GroupManager()), + ], + ), + migrations.CreateModel( + name='AzureUser', + 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')), + ('groups', models.ManyToManyField(blank=True, related_name='azure_user_groups', to='auth.group')), + ('user_permissions', models.ManyToManyField(blank=True, related_name='azure_user_permissions', to='auth.permission')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.AlterField( + model_name='berichtsheft', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='berichtshefte', to='core.azureuser'), + ), + ] diff --git a/core/migrations/0004_remove_berichtsheft_approved_by.py b/core/migrations/0004_remove_berichtsheft_approved_by.py new file mode 100755 index 0000000..27beaa4 --- /dev/null +++ b/core/migrations/0004_remove_berichtsheft_approved_by.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.16 on 2024-12-02 14:33 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0003_group_azureuser_alter_berichtsheft_user'), + ] + + operations = [ + migrations.RemoveField( + model_name='berichtsheft', + name='approved_by', + ), + ] diff --git a/core/migrations/0005_user_alter_berichtsheft_user_delete_azureuser.py b/core/migrations/0005_user_alter_berichtsheft_user_delete_azureuser.py new file mode 100755 index 0000000..cd0eac0 --- /dev/null +++ b/core/migrations/0005_user_alter_berichtsheft_user_delete_azureuser.py @@ -0,0 +1,51 @@ +# Generated by Django 4.2.16 on 2024-12-02 14:46 + +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ('core', '0004_remove_berichtsheft_approved_by'), + ] + + 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')), + ('groups', models.ManyToManyField(blank=True, related_name='user_groups', to='auth.group')), + ('user_permissions', models.ManyToManyField(blank=True, related_name='user_permissions', to='auth.permission')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.AlterField( + model_name='berichtsheft', + name='user', + field=models.TextField(), + ), + migrations.DeleteModel( + name='AzureUser', + ), + ] diff --git a/core/migrations/__init__.py b/core/migrations/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/core/models.py b/core/models.py new file mode 100755 index 0000000..6dbd6ec --- /dev/null +++ b/core/models.py @@ -0,0 +1,36 @@ +from django.db import models +from django.contrib.auth.models import AbstractUser +from django.contrib.auth.models import Group as BuiltinGroup + +class User(AbstractUser): + groups = models.ManyToManyField( + 'auth.Group', + related_name='user_groups', + blank=True, + ) + user_permissions = models.ManyToManyField( + 'auth.Permission', + related_name='user_permissions', + blank=True, + ) + +class Group(BuiltinGroup): + class Meta: + proxy = True + +class Berichtsheft(models.Model): + id = models.AutoField(primary_key=True) + user = models.TextField() + year = models.PositiveIntegerField() + week = models.PositiveSmallIntegerField() + content = models.JSONField() + created = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Berichtsheft: {self.user.username}, Year: {self.year}, Week: {self.week}" + +class Approval: + id = models.AutoField(primary_key=True) + user = models.TextField() + report = models.ForeignKey(Berichtsheft, on_delete=models.CASCADE, related_name="report") + diff --git a/core/templates/index.html b/core/templates/index.html new file mode 100755 index 0000000..ab7cf7f --- /dev/null +++ b/core/templates/index.html @@ -0,0 +1,34 @@ + +
+{{ report }}
+Berichtsheft {{ year }} / {{ week }}
+ + + + + diff --git a/core/tests.py b/core/tests.py new file mode 100755 index 0000000..7ce503c --- /dev/null +++ b/core/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/core/urls.py b/core/urls.py new file mode 100755 index 0000000..0740e2c --- /dev/null +++ b/core/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('', views.index, name='index'), + path('write', views.write_new_report, name='write'), + path("test", views.test, name="test") +] \ No newline at end of file diff --git a/core/views.py b/core/views.py new file mode 100755 index 0000000..8323879 --- /dev/null +++ b/core/views.py @@ -0,0 +1,47 @@ +from django.shortcuts import render +from .azure_auth import AzureUser +from .models import Berichtsheft +import datetime +import json + +# Create your views here. + +def next_date(year: int, week: int) -> (int, int): + if week >= 52: + return (year + 1, 1) + else: + return (year, week + 1) + +def write_new_report(request): + user = AzureUser(request) + + # TODO : Get template for user + definition = json.loads(open("report_weekly.json").read()) + + # Get the latest year and week + latest = Berichtsheft.objects.filter(user=user).order_by('-year', '-week').first() + if latest is not None: + current_year, current_week = next_date(latest.year, latest.week) + else: + current_year, current_week, _ = datetime.datetime.today().isocalendar() + + # Get cookies for persistent saves + + + return render(request, "write.html", { + "user": user, + "year": current_year, + "week": current_week, + "definition": definition + }) + +def index(request): + user = AzureUser(request) + + # Get all berichtshefte + all_reports = Berichtsheft.objects.filter(user=user) + + return render(request, "index.html", {"user": user, "reports": all_reports}) + +def test(request): + return render(request, "test.html", {}) \ No newline at end of file diff --git a/report_weekly.json b/report_weekly.json new file mode 100755 index 0000000..23702ae --- /dev/null +++ b/report_weekly.json @@ -0,0 +1,44 @@ +{ + "vars": [ + { + "name": "name", + "display_name": "Name" + }, + { + "name": "num_doc", + "display_name": "Berichtsheft Nummer" + }, + { + "name": "year", + "display_name": "Jahr" + }, + { + "name": "week", + "display_name": "Kalenderwoche" + }, + { + "name": "start_date", + "display_name": "Von" + }, + { + "name": "end_date", + "display_name": "bis" + }, + { + "name": "department", + "display_name": "Abteilung" + }, + { + "name": "company_text", + "display_name": "Betriebliche Tätigkeiten" + }, + { + "name": "week_topic", + "display_name": "Thema der Woche" + }, + { + "name": "school_text", + "display_name": "Berufsschule" + } + ] +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt old mode 100644 new mode 100755 index d0e93e4..7a4844b --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ Django~=4.2.11 +psycopg2 \ No newline at end of file