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 MembershipType
from .models import ServiceAccess
from .models import SubscriptionPeriod
@ -20,3 +21,9 @@ class MembershipTypeAdmin(admin.ModelAdmin):
@admin.register(SubscriptionPeriod)
class SubscriptionPeriodAdmin(admin.ModelAdmin):
"""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.utils import timezone
from django.utils.translation import gettext as _
from services.registry import ServiceRegistry
from utils.mixins import CreatedModifiedAbstract
@ -139,3 +141,22 @@ class MembershipType(CreatedModifiedAbstract):
def __str__(self) -> str:
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.account",
"django_view_decorator",
"django_registries",
]
LOCAL_APPS = [
"utils",
"accounting",
"membership",
"services",
]
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.