diff --git a/aleksis/core/admin.py b/aleksis/core/admin.py index 106da0677831f722aefa1d28d23dde9fea838b06..0725c0aa5545797317a3bfac955cd854d28f227e 100644 --- a/aleksis/core/admin.py +++ b/aleksis/core/admin.py @@ -1,8 +1,10 @@ from django.contrib import admin -from .models import Group, Person, School, SchoolTerm +from .models import Group, Person, School, SchoolTerm, Activity, Notification admin.site.register(Person) admin.site.register(Group) admin.site.register(School) admin.site.register(SchoolTerm) +admin.site.register(Activity) +admin.site.register(Notification) diff --git a/aleksis/core/dashboard/__init__.py b/aleksis/core/dashboard/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/aleksis/core/dashboard/admin.py b/aleksis/core/dashboard/admin.py deleted file mode 100644 index a9286d91effa36ce9fdb9e4cc020c2a3506da854..0000000000000000000000000000000000000000 --- a/aleksis/core/dashboard/admin.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.contrib import admin -from .models import Activity, Notification, Cache - - -class CacheAdmin(admin.ModelAdmin): - readonly_fields = ["id", "site_cache", "last_time_updated"] - - -admin.site.register(Activity) -admin.site.register(Notification) -admin.site.register(Cache, CacheAdmin) diff --git a/aleksis/core/dashboard/apps.py b/aleksis/core/dashboard/apps.py deleted file mode 100644 index bc6084702acf8de9b788588f5813d689a8bd82bf..0000000000000000000000000000000000000000 --- a/aleksis/core/dashboard/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class DashboardConfig(AppConfig): - name = 'dashboard' - verbose_name = "Dashboard" diff --git a/aleksis/core/dashboard/migrations/__init__.py b/aleksis/core/dashboard/migrations/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/aleksis/core/dashboard/models.py b/aleksis/core/dashboard/models.py deleted file mode 100644 index e9b8e8467ec9ad44bb0de41205277022a97a1ec8..0000000000000000000000000000000000000000 --- a/aleksis/core/dashboard/models.py +++ /dev/null @@ -1,44 +0,0 @@ -import datetime - -from django.core.cache import cache -from django.db import models -from django.contrib.auth.models import User -from django.utils import timezone - -from mailer import send_mail_with_template - - -class Activity(models.Model): - user = models.ForeignKey(to=User, on_delete=models.CASCADE) - - title = models.CharField(max_length=150) - description = models.TextField(max_length=500) - - app = models.CharField(max_length=100) - - created_at = models.DateTimeField(default=timezone.now) - - def __str__(self): - return self.title - - -class Notification(models.Model): - user = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name="notifications") - title = models.CharField(max_length=150) - description = models.TextField(max_length=500) - link = models.URLField(blank=True) - - app = models.CharField(max_length=100) - - read = models.BooleanField(default=False) - mailed = models.BooleanField(default=False) - created_at = models.DateTimeField(default=timezone.now) - - def __str__(self): - return self.title - - def save(self): - super().save() - if not self.mailed: - send_mail_with_template(title, [user.email], "mail/notification.txt", "mail/notification.html", context) - self.mailed = True diff --git a/aleksis/core/migrations/0001_initial.py b/aleksis/core/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..f8cc0d4d5294f0ca7b9243a3ce704d94169d855c --- /dev/null +++ b/aleksis/core/migrations/0001_initial.py @@ -0,0 +1,119 @@ +# Generated by Django 3.0.2 on 2020-01-03 19:18 + +import aleksis.core.mixins +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import image_cropping.fields +import phonenumber_field.modelfields + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Group', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=60, unique=True, verbose_name='Long name of group')), + ('short_name', models.CharField(max_length=16, unique=True, verbose_name='Short name of group')), + ], + options={ + 'ordering': ['short_name', 'name'], + }, + bases=(models.Model, aleksis.core.mixins.ExtensibleModel), + ), + migrations.CreateModel( + name='School', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30, verbose_name='Name')), + ('name_official', + models.CharField(help_text='Official name of the school, e.g. as given by supervisory authority', + max_length=200, verbose_name='Official name')), + ('logo', + image_cropping.fields.ImageCropField(blank=True, null=True, upload_to='', verbose_name='School logo')), + ('logo_cropping', + image_cropping.fields.ImageRatioField('logo', '600x600', adapt_rotation=False, allow_fullsize=False, + free_crop=False, help_text=None, hide_image_field=False, + size_warning=True, verbose_name='logo cropping')), + ], + options={ + 'ordering': ['name', 'name_official'], + }, + ), + migrations.CreateModel( + name='SchoolTerm', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('caption', models.CharField(max_length=30, verbose_name='Visible caption of the term')), + ('date_start', models.DateField(null=True, verbose_name='Effective start date of term')), + ('date_end', models.DateField(null=True, verbose_name='Effective end date of term')), + ('current', models.NullBooleanField(default=None, unique=True)), + ], + ), + migrations.CreateModel( + name='Person', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_active', models.BooleanField(default=True, verbose_name='Is person active?')), + ('first_name', models.CharField(max_length=30, verbose_name='First name')), + ('last_name', models.CharField(max_length=30, verbose_name='Last name')), + ('additional_name', models.CharField(blank=True, max_length=30, verbose_name='Additional name(s)')), + ('short_name', + models.CharField(blank=True, max_length=5, null=True, unique=True, verbose_name='Short name')), + ('street', models.CharField(blank=True, max_length=30, verbose_name='Street')), + ('housenumber', models.CharField(blank=True, max_length=10, verbose_name='Street number')), + ('postal_code', models.CharField(blank=True, max_length=5, verbose_name='Postal code')), + ('place', models.CharField(blank=True, max_length=30, verbose_name='Place')), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, region=None, + verbose_name='Home phone')), + ('mobile_number', + phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, region=None, + verbose_name='Mobile phone')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='E-mail address')), + ('date_of_birth', models.DateField(blank=True, null=True, verbose_name='Date of birth')), + ('sex', models.CharField(blank=True, choices=[('f', 'female'), ('m', 'male')], max_length=1, + verbose_name='Sex')), + ('photo', + image_cropping.fields.ImageCropField(blank=True, null=True, upload_to='', verbose_name='Photo')), + ('photo_cropping', + image_cropping.fields.ImageRatioField('photo', '600x800', adapt_rotation=False, allow_fullsize=False, + free_crop=False, help_text=None, hide_image_field=False, + size_warning=True, verbose_name='photo cropping')), + ('import_ref', models.CharField(blank=True, editable=False, max_length=64, null=True, unique=True, + verbose_name='Reference ID of import source')), + ('guardians', models.ManyToManyField(blank=True, related_name='children', to='core.Person', + verbose_name='Guardians / Parents')), + ('primary_group', + models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.Group')), + ('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, + related_name='person', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['last_name', 'first_name'], + }, + bases=(models.Model, aleksis.core.mixins.ExtensibleModel), + ), + migrations.AddField( + model_name='group', + name='members', + field=models.ManyToManyField(blank=True, related_name='member_of', to='core.Person'), + ), + migrations.AddField( + model_name='group', + name='owners', + field=models.ManyToManyField(blank=True, related_name='owner_of', to='core.Person'), + ), + migrations.AddField( + model_name='group', + name='parent_groups', + field=models.ManyToManyField(blank=True, related_name='child_groups', to='core.Group', + verbose_name='Parent groups'), + ), + ] diff --git a/aleksis/core/migrations/0002_activity_notification.py b/aleksis/core/migrations/0002_activity_notification.py new file mode 100644 index 0000000000000000000000000000000000000000..9679e4707063223fbc5fe5f9fdc5bcf926566874 --- /dev/null +++ b/aleksis/core/migrations/0002_activity_notification.py @@ -0,0 +1,42 @@ +# Generated by Django 3.0.2 on 2020-01-03 19:19 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('core', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Notification', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=150)), + ('description', models.TextField(max_length=500)), + ('link', models.URLField(blank=True)), + ('app', models.CharField(max_length=100)), + ('read', models.BooleanField(default=False)), + ('mailed', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', + to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Activity', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=150)), + ('description', models.TextField(max_length=500)), + ('app', models.CharField(max_length=100)), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/aleksis/core/models.py b/aleksis/core/models.py index ab347b7e3451a5aacb7d34976b758ae968b7e600..811cfaeb03c17393a95668abce719e4e7470544c 100644 --- a/aleksis/core/models.py +++ b/aleksis/core/models.py @@ -1,13 +1,16 @@ from typing import Optional from django.contrib.auth import get_user_model +from django.contrib.auth.models import User from django.db import models +from django.utils import timezone from django.utils.translation import ugettext_lazy as _ import dbsettings from image_cropping import ImageCropField, ImageRatioField from phonenumber_field.modelfields import PhoneNumberField +from .mailer import send_mail_with_template from .mixins import ExtensibleModel @@ -170,3 +173,40 @@ class Group(models.Model, ExtensibleModel): def __str__(self) -> str: return "%s (%s)" % (self.name, self.short_name) + + +class Activity(models.Model): + user = models.ForeignKey(to=User, on_delete=models.CASCADE) + + title = models.CharField(max_length=150) + description = models.TextField(max_length=500) + + app = models.CharField(max_length=100) + + created_at = models.DateTimeField(default=timezone.now) + + def __str__(self): + return self.title + + +class Notification(models.Model): + user = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name="notifications") + title = models.CharField(max_length=150) + description = models.TextField(max_length=500) + link = models.URLField(blank=True) + + app = models.CharField(max_length=100) + + read = models.BooleanField(default=False) + mailed = models.BooleanField(default=False) + created_at = models.DateTimeField(default=timezone.now) + + def __str__(self): + return self.title + + def save(self, **kwargs): + super().save(**kwargs) + if not self.mailed: + send_mail_with_template(self.title, [self.user.email], "mail/notification.txt", "mail/notification.html", + {"notification": self}) + self.mailed = True