WIP: Services #25

Draft
valberg wants to merge 8 commits from services into main
13 changed files with 152 additions and 0 deletions
Showing only changes of commit 3d1b51f99b - Show all commits

View file

@ -4,6 +4,7 @@ from django.contrib import admin
from .models import Membership from .models import Membership
from .models import MembershipType from .models import MembershipType
from .models import ServiceAccess
from .models import SubscriptionPeriod from .models import SubscriptionPeriod
@ -20,3 +21,9 @@ class MembershipTypeAdmin(admin.ModelAdmin):
@admin.register(SubscriptionPeriod) @admin.register(SubscriptionPeriod)
class SubscriptionPeriodAdmin(admin.ModelAdmin): class SubscriptionPeriodAdmin(admin.ModelAdmin):
"""Admin for SubscriptionPeriod model.""" """Admin for SubscriptionPeriod model."""
@admin.register(ServiceAccess)
class ServiceAccessAdmin(admin.ModelAdmin):
"""Admin for ServiceAccess model."""
pass

View file

@ -0,0 +1,64 @@
# Generated by Django 5.0.1 on 2024-01-13 19:20
import django.db.models.deletion
import django_registries.registry
import services.registry
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("membership", "0005_member"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="ServiceAccess",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
(
"service",
django_registries.registry.ChoicesField(
choices=[],
registry=services.registry.ServiceRegistry,
verbose_name="service",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "service access",
"verbose_name_plural": "service accesses",
},
),
migrations.AddConstraint(
model_name="serviceaccess",
constraint=models.UniqueConstraint(
fields=("user", "service"), name="unique_user_service"
),
),
]

View file

@ -10,6 +10,8 @@ from django.contrib.postgres.fields import RangeOperators
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from services.registry import ServiceRegistry
from utils.mixins import CreatedModifiedAbstract from utils.mixins import CreatedModifiedAbstract
@ -139,3 +141,22 @@ class MembershipType(CreatedModifiedAbstract):
def __str__(self) -> str: def __str__(self) -> str:
return self.name return self.name
class ServiceAccess(CreatedModifiedAbstract):
class Meta:
verbose_name = _("service access")
verbose_name_plural = _("service accesses")
constraints = [
models.UniqueConstraint(
fields=["user", "service"],
name="unique_user_service",
),
]
user = models.ForeignKey("auth.User", on_delete=models.PROTECT)
Review

This is correct! 💯

Notable because there is also a Membership model.. however, memberships are renewed every year, and a user should be able to use the same services across different memberships.

How we handle "eligibility to a service" can happen later..

This is correct! 💯 Notable because there is also a Membership model.. however, memberships are renewed every year, and a user should be able to use the same services across different memberships. How we handle "eligibility to a service" can happen later..
service = ServiceRegistry.choices_field(verbose_name=_("service"))
def __str__(self):
return f"{self.user} - {self.service}"

View file

@ -43,12 +43,14 @@ THIRD_PARTY_APPS = [
"allauth", "allauth",
"allauth.account", "allauth.account",
"django_view_decorator", "django_view_decorator",
"django_registries",
] ]
LOCAL_APPS = [ LOCAL_APPS = [
"utils", "utils",
"accounting", "accounting",
"membership", "membership",
"services",
] ]
INSTALLED_APPS = [ INSTALLED_APPS = [

0
src/services/__init__.py Normal file
View file

1
src/services/admin.py Normal file
View file

@ -0,0 +1 @@
# Register your models here.

6
src/services/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ServicesConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "services"

View file

1
src/services/models.py Normal file
View file

@ -0,0 +1 @@
# Create your models here.

21
src/services/registry.py Normal file
View file

@ -0,0 +1,21 @@
from django_registries.registry import Interface
from django_registries.registry import Registry
class ServiceRegistry(Registry):
"""Registry for services"""
implementations_module = "services"
class ServiceInterface(Interface):
"""Interface for services"""
registry = ServiceRegistry
public: bool = False
# TODO: add a way to add a something which defines the required fields for a service
# - maybe a list of tuples with the field name and the type of the field
# this could be used to generate a form for the service, and also to validate
# the data saved in a JSONField on the ServiceAccess model

27
src/services/services.py Normal file
View file

@ -0,0 +1,27 @@
from .registry import ServiceInterface
class MailService(ServiceInterface):
slug = "mail"
class MatrixService(ServiceInterface):
slug = "matrix"
class MastodonService(ServiceInterface):
slug = "mastodon"
class NextcloudService(ServiceInterface):
slug = "nextcloud"
class HedgeDocService(ServiceInterface):
slug = "hedgedoc"
public = True
class RalllyService(ServiceInterface):
slug = "rallly"
public = True

1
src/services/tests.py Normal file
View file

@ -0,0 +1 @@
# Create your tests here.

1
src/services/views.py Normal file
View file

@ -0,0 +1 @@
# Create your views here.