Skip to content

Commit c48fb05

Browse files
authored
Merge pull request #3549 from webkom/create-abaquery-forums
Create abaquery forums
2 parents cc3afbf + fd5913a commit c48fb05

File tree

16 files changed

+712
-5
lines changed

16 files changed

+712
-5
lines changed

lego/api/urls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from django.views.decorators.csrf import csrf_exempt
66
from django.views.generic import RedirectView
77

8-
from .v1 import router as v1
8+
from .v1 import urlpatterns as v1_urlpatterns
99

1010

1111
@csrf_exempt
@@ -22,7 +22,7 @@ def version_redirect(request, path):
2222

2323
app_name = "api"
2424
urlpatterns = [
25-
re_path(r"^v1/", include((v1.urls, "v1"), namespace="v1")),
25+
re_path(r"^v1/", include((v1_urlpatterns, "v1"), namespace="v1")),
2626
re_path(
2727
r"^$", RedirectView.as_view(url=f"/api/{settings.API_VERSION}/"), name="default"
2828
),

lego/api/v1.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.urls import include, path
12
from rest_framework import routers
23

34
from lego.apps.articles.views import ArticlesViewSet
@@ -33,6 +34,8 @@
3334
FollowEventViewSet,
3435
FollowUserViewSet,
3536
)
37+
from lego.apps.forums.urls import urlpatterns as forums_urls
38+
from lego.apps.forums.views import ForumsViewSet, ThreadViewSet
3639
from lego.apps.frontpage.views import FrontpageViewSet
3740
from lego.apps.gallery.views import GalleryPictureViewSet, GalleryViewSet
3841
from lego.apps.ical.viewsets import ICalTokenViewset, ICalViewset
@@ -131,6 +134,7 @@
131134
router.register(r"followers-company", FollowCompanyViewSet)
132135
router.register(r"followers-event", FollowEventViewSet)
133136
router.register(r"followers-user", FollowUserViewSet)
137+
router.register(r"forums", ForumsViewSet)
134138
router.register(r"frontpage", FrontpageViewSet, basename="frontpage")
135139
router.register(r"galleries", GalleryViewSet)
136140
router.register(r"galleries/(?P<gallery_pk>\d+)/pictures", GalleryPictureViewSet)
@@ -192,6 +196,7 @@
192196
r"surveys/(?P<survey_pk>\d+)/submissions", SubmissionViewSet, basename="submission"
193197
)
194198
router.register(r"tags", TagViewSet)
199+
router.register(r"threads", ThreadViewSet)
195200
router.register(r"user-delete", UserDeleteViewSet, basename="user-delete")
196201
router.register(r"users", UsersViewSet)
197202
router.register(
@@ -201,3 +206,8 @@
201206
)
202207
router.register(r"oidc", OIDCViewSet, basename="oidc")
203208
router.register(r"webhooks-stripe", StripeWebhook, basename="webhooks-stripe")
209+
210+
urlpatterns = [
211+
path("", include(router.urls)),
212+
path("forums/", include((forums_urls, "forums"))),
213+
]

lego/apps/forums/__init__.py

Whitespace-only changes.

lego/apps/forums/admin.py

Whitespace-only changes.
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# Generated by Django 4.0.10 on 2024-02-26 16:56
2+
3+
import django.db.models.deletion
4+
import django.utils.timezone
5+
from django.conf import settings
6+
from django.db import migrations, models
7+
8+
import lego.apps.content.fields
9+
10+
11+
class Migration(migrations.Migration):
12+
initial = True
13+
14+
dependencies = [
15+
("users", "0041_user_linkedin_id_alter_user_github_username"),
16+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
17+
("tags", "0004_auto_20200324_1859"),
18+
]
19+
20+
operations = [
21+
migrations.CreateModel(
22+
name="Forum",
23+
fields=[
24+
(
25+
"id",
26+
models.AutoField(
27+
auto_created=True,
28+
primary_key=True,
29+
serialize=False,
30+
verbose_name="ID",
31+
),
32+
),
33+
(
34+
"created_at",
35+
models.DateTimeField(
36+
db_index=True, default=django.utils.timezone.now, editable=False
37+
),
38+
),
39+
(
40+
"updated_at",
41+
models.DateTimeField(
42+
default=django.utils.timezone.now, editable=False
43+
),
44+
),
45+
(
46+
"deleted",
47+
models.BooleanField(db_index=True, default=False, editable=False),
48+
),
49+
("require_auth", models.BooleanField(default=True)),
50+
("slug", models.SlugField(null=True, unique=True)),
51+
("title", models.CharField(max_length=255)),
52+
("description", models.TextField()),
53+
("text", lego.apps.content.fields.ContentField(allow_images=False)),
54+
("pinned", models.BooleanField(default=False)),
55+
(
56+
"can_edit_groups",
57+
models.ManyToManyField(
58+
blank=True,
59+
related_name="can_edit_%(class)s",
60+
to="users.abakusgroup",
61+
),
62+
),
63+
(
64+
"can_edit_users",
65+
models.ManyToManyField(
66+
blank=True,
67+
related_name="can_edit_%(class)s",
68+
to=settings.AUTH_USER_MODEL,
69+
),
70+
),
71+
(
72+
"can_view_groups",
73+
models.ManyToManyField(
74+
blank=True,
75+
related_name="can_view_%(class)s",
76+
to="users.abakusgroup",
77+
),
78+
),
79+
(
80+
"created_by",
81+
models.ForeignKey(
82+
default=None,
83+
editable=False,
84+
null=True,
85+
on_delete=django.db.models.deletion.SET_NULL,
86+
related_name="%(class)s_created",
87+
to=settings.AUTH_USER_MODEL,
88+
),
89+
),
90+
("tags", models.ManyToManyField(blank=True, to="tags.tag")),
91+
(
92+
"updated_by",
93+
models.ForeignKey(
94+
default=None,
95+
editable=False,
96+
null=True,
97+
on_delete=django.db.models.deletion.SET_NULL,
98+
related_name="%(class)s_updated",
99+
to=settings.AUTH_USER_MODEL,
100+
),
101+
),
102+
],
103+
options={
104+
"abstract": False,
105+
},
106+
),
107+
migrations.CreateModel(
108+
name="Thread",
109+
fields=[
110+
(
111+
"id",
112+
models.AutoField(
113+
auto_created=True,
114+
primary_key=True,
115+
serialize=False,
116+
verbose_name="ID",
117+
),
118+
),
119+
(
120+
"created_at",
121+
models.DateTimeField(
122+
db_index=True, default=django.utils.timezone.now, editable=False
123+
),
124+
),
125+
(
126+
"updated_at",
127+
models.DateTimeField(
128+
default=django.utils.timezone.now, editable=False
129+
),
130+
),
131+
(
132+
"deleted",
133+
models.BooleanField(db_index=True, default=False, editable=False),
134+
),
135+
("require_auth", models.BooleanField(default=True)),
136+
("slug", models.SlugField(null=True, unique=True)),
137+
("title", models.CharField(max_length=255)),
138+
("description", models.TextField()),
139+
("text", lego.apps.content.fields.ContentField(allow_images=False)),
140+
("pinned", models.BooleanField(default=False)),
141+
(
142+
"can_edit_groups",
143+
models.ManyToManyField(
144+
blank=True,
145+
related_name="can_edit_%(class)s",
146+
to="users.abakusgroup",
147+
),
148+
),
149+
(
150+
"can_edit_users",
151+
models.ManyToManyField(
152+
blank=True,
153+
related_name="can_edit_%(class)s",
154+
to=settings.AUTH_USER_MODEL,
155+
),
156+
),
157+
(
158+
"can_view_groups",
159+
models.ManyToManyField(
160+
blank=True,
161+
related_name="can_view_%(class)s",
162+
to="users.abakusgroup",
163+
),
164+
),
165+
(
166+
"created_by",
167+
models.ForeignKey(
168+
default=None,
169+
editable=False,
170+
null=True,
171+
on_delete=django.db.models.deletion.SET_NULL,
172+
related_name="%(class)s_created",
173+
to=settings.AUTH_USER_MODEL,
174+
),
175+
),
176+
(
177+
"forum",
178+
models.ForeignKey(
179+
on_delete=django.db.models.deletion.CASCADE,
180+
related_name="threads",
181+
to="forums.forum",
182+
),
183+
),
184+
("tags", models.ManyToManyField(blank=True, to="tags.tag")),
185+
(
186+
"updated_by",
187+
models.ForeignKey(
188+
default=None,
189+
editable=False,
190+
null=True,
191+
on_delete=django.db.models.deletion.SET_NULL,
192+
related_name="%(class)s_updated",
193+
to=settings.AUTH_USER_MODEL,
194+
),
195+
),
196+
],
197+
options={
198+
"abstract": False,
199+
},
200+
),
201+
]

lego/apps/forums/migrations/__init__.py

Whitespace-only changes.

lego/apps/forums/models.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from django.db.models import CASCADE, ForeignKey
2+
3+
from lego.apps.content.models import Content
4+
from lego.apps.forums.permissions import ForumPermissionHandler, ThreadPermissionHandler
5+
from lego.apps.permissions.models import ObjectPermissionsModel
6+
from lego.utils.models import BasisModel
7+
8+
9+
class Forum(Content, BasisModel, ObjectPermissionsModel):
10+
class Meta:
11+
abstract = False
12+
permission_handler = ForumPermissionHandler()
13+
14+
15+
class Thread(Content, BasisModel, ObjectPermissionsModel):
16+
forum = ForeignKey(Forum, on_delete=CASCADE, related_name="threads")
17+
18+
class Meta:
19+
abstract = False
20+
permission_handler = ThreadPermissionHandler()

lego/apps/forums/permissions.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from lego.apps.permissions.constants import CREATE, DELETE, EDIT, LIST, VIEW
2+
from lego.apps.permissions.permissions import PermissionHandler
3+
4+
5+
class ForumPermissionHandler(PermissionHandler):
6+
force_object_permission_check = True
7+
authentication_map = {LIST: False, VIEW: False}
8+
default_keyword_permission = "/sudo/admin/forums/{perm}/"
9+
default_require_auth = True
10+
11+
def has_perm(
12+
self,
13+
user,
14+
perm,
15+
obj=None,
16+
queryset=None,
17+
check_keyword_permissions=True,
18+
**kwargs
19+
):
20+
if perm == LIST:
21+
return True
22+
23+
if not user.is_authenticated:
24+
return False
25+
26+
# Check object permissions before keywork perms
27+
if obj is not None:
28+
if self.has_object_permissions(user, perm, obj):
29+
return True
30+
31+
if perm == EDIT and self.created_by(user, obj):
32+
return True
33+
34+
has_perm = super().has_perm(
35+
user, perm, obj, queryset, check_keyword_permissions, **kwargs
36+
)
37+
38+
if has_perm:
39+
return True
40+
41+
return False
42+
43+
def has_object_permissions(self, user, perm, obj):
44+
return not (perm == DELETE or perm == EDIT)
45+
46+
47+
class ThreadPermissionHandler(PermissionHandler):
48+
force_object_permission_check = True
49+
authentication_map = {LIST: False, VIEW: False}
50+
default_keyword_permission = "/sudo/admin/threads/{perm}/"
51+
default_require_auth = True
52+
53+
def has_perm(
54+
self,
55+
user,
56+
perm,
57+
obj=None,
58+
queryset=None,
59+
check_keyword_permissions=True,
60+
**kwargs
61+
):
62+
if perm == LIST:
63+
return True
64+
if not user.is_authenticated:
65+
return False
66+
67+
# Check object permissions before keywork perms
68+
if obj is not None:
69+
if self.has_object_permissions(user, perm, obj):
70+
return True
71+
72+
if perm == EDIT and self.created_by(user, obj):
73+
return True
74+
75+
if perm == CREATE:
76+
return True
77+
78+
has_perm = super().has_perm(
79+
user, perm, obj, queryset, check_keyword_permissions, **kwargs
80+
)
81+
82+
if has_perm:
83+
return True
84+
85+
return False
86+
87+
def has_object_permissions(self, user, perm, obj):
88+
if perm == DELETE:
89+
return False
90+
if perm == EDIT and obj.created_by == user:
91+
return True
92+
if perm == CREATE:
93+
return True
94+
return not (perm == DELETE or perm == EDIT)

0 commit comments

Comments
 (0)