Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement lending system #3501

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d9db172
Implement lending system
Arashfa0301 Oct 4, 2023
10278d8
Fix location field bug
jonasdeluna Oct 19, 2023
69ee849
Fix other thing
jonasdeluna Oct 19, 2023
79a8620
Fix more
jonasdeluna Feb 1, 2024
eb0ce16
Change responsible_role to responsible_roles
jonasdeluna Feb 6, 2024
3583477
Add fixtures
itsisak Feb 18, 2024
0934b6f
Fix image field on lending
jonasdeluna Feb 20, 2024
cd8db09
Update notified users
jonasdeluna Feb 20, 2024
78dc3a1
Fix conflict bug
jonasdeluna Feb 20, 2024
10db26d
Add remove user migration
Bestem0r Feb 27, 2024
651e70a
Fix roles and validation for LendingInstance
Bestem0r Mar 5, 2024
dcf7b07
Change to basismodel for lendinginstance
Bestem0r Mar 5, 2024
e549314
Rename user to author, add comment to lendinginstance
Bestem0r Mar 5, 2024
2e0dd15
Implement lending system
Arashfa0301 Oct 4, 2023
e2b7ca0
Fix location field bug
jonasdeluna Oct 19, 2023
f36ffda
Fix other thing
jonasdeluna Oct 19, 2023
9bc279b
Fix more
jonasdeluna Feb 1, 2024
097aeb4
Change responsible_role to responsible_roles
jonasdeluna Feb 6, 2024
235ceea
Add fixtures
itsisak Feb 18, 2024
6ce54ba
Fix image field on lending
jonasdeluna Feb 20, 2024
264a16b
Update notified users
jonasdeluna Feb 20, 2024
7b9c0c8
Fix conflict bug
jonasdeluna Feb 20, 2024
024b0ca
Add remove user migration
Bestem0r Feb 27, 2024
4a62d98
Fix roles and validation for LendingInstance
Bestem0r Mar 5, 2024
911630e
Change to basismodel for lendinginstance
Bestem0r Mar 5, 2024
ab09ba5
Rename user to author, add comment to lendinginstance
Bestem0r Mar 5, 2024
0c729d5
Add notification on update of lending instance
jonasdeluna Mar 12, 2024
75848dc
Merge remote-tracking branch 'origin/implement-lending-system' into i…
Bestem0r Mar 12, 2024
afc32a3
Implement lending system
Bestem0r Mar 12, 2024
cd58144
Remove notifications
jonasdeluna May 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
master_doc = "index"

# General information about the project.
project = u"LEGO"
copyright = u"2014 - 2020, Abakus Webkom"
project = "LEGO"
copyright = "2014 - 2020, Abakus Webkom"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
Expand Down Expand Up @@ -197,7 +197,7 @@
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
("index", "LEGO.tex", u"LEGO Documentation", u"Abakus Webkom", "manual")
("index", "LEGO.tex", "LEGO Documentation", "Abakus Webkom", "manual")
]

# The name of an image file (relative to this directory) to place at the top of
Expand All @@ -224,7 +224,7 @@

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [("index", "lego", u"LEGO Documentation", [u"Abakus Webkom"], 1)]
man_pages = [("index", "lego", "LEGO Documentation", ["Abakus Webkom"], 1)]

# If true, show URL addresses after external links.
# man_show_urls = False
Expand All @@ -238,8 +238,8 @@
(
"index",
"LEGO",
u"LEGO Documentation",
u"Abakus Webkom",
"LEGO Documentation",
"Abakus Webkom",
"LEGO",
"One line description of project.",
"Miscellaneous",
Expand Down
6 changes: 6 additions & 0 deletions lego/api/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
from lego.apps.gallery.views import GalleryPictureViewSet, GalleryViewSet
from lego.apps.ical.viewsets import ICalTokenViewset, ICalViewset
from lego.apps.joblistings.views import JoblistingViewSet
from lego.apps.lending.urls import urlpatterns as lending_urls
from lego.apps.lending.views import LendableObjectViewSet, LendingInstanceViewSet
from lego.apps.meetings.views import (
MeetingInvitationTokenViewSet,
MeetingInvitationViewSet,
Expand Down Expand Up @@ -145,6 +147,9 @@
basename="abakusgroup-memberships",
)
router.register(r"joblistings", JoblistingViewSet, basename="joblisting")
router.register(r"lendableobject", LendableObjectViewSet, basename="lendableobject")
router.register(r"lendinginstance", LendingInstanceViewSet, basename="lendinginstance")

router.register(
r"meeting-token", MeetingInvitationTokenViewSet, basename="meeting-token"
)
Expand Down Expand Up @@ -210,4 +215,5 @@
urlpatterns = [
path("", include(router.urls)),
path("forums/", include((forums_urls, "forums"))),
path("", include((lending_urls, "lending"))),
jonasdeluna marked this conversation as resolved.
Show resolved Hide resolved
]
28 changes: 27 additions & 1 deletion lego/apps/comments/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models

from lego.apps.comments.permissions import CommentPermissionHandler
from lego.apps.content.fields import ContentField
from lego.apps.reactions.models import Reaction
from lego.utils.managers import BasisModelManager
from lego.utils.models import BasisModel

Expand All @@ -19,6 +20,7 @@ class Comment(BasisModel):
object_id = models.PositiveIntegerField(db_index=True)
content_object = GenericForeignKey()
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.CASCADE)
reactions = GenericRelation(Reaction)

objects = CommentManager() # type: ignore

Expand All @@ -34,5 +36,29 @@ def delete(self):
else:
super(Comment, self).delete(force=True)

def get_reactions_grouped(self, user):
grouped = {}
for reaction in self.reactions.all():
if reaction.emoji.pk not in grouped:
grouped[reaction.emoji.pk] = {
"emoji": reaction.emoji.pk,
"unicode_string": reaction.emoji.unicode_string,
"count": 0,
"has_reacted": False,
"reaction_id": None,
}

grouped[reaction.emoji.pk]["count"] += 1

if reaction.created_by == user:
grouped[reaction.emoji.pk]["has_reacted"] = True
grouped[reaction.emoji.pk]["reaction_id"] = reaction.id

return sorted(grouped.values(), key=lambda kv: kv["count"], reverse=True)

Comment on lines +39 to +57
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's going on here? Why is this in this PR?

def __str__(self):
return self.text

@property
def content_target_self(self):
return f"{self._meta.app_label}.{self._meta.model_name}-{self.pk}"
11 changes: 10 additions & 1 deletion lego/apps/comments/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib.contenttypes.models import ContentType
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.fields import DateTimeField
from rest_framework.fields import CharField, DateTimeField

from lego.apps.comments.models import Comment
from lego.apps.content.fields import ContentSerializerField
Expand All @@ -14,6 +15,8 @@ class CommentSerializer(BasisModelSerializer):
updated_at = DateTimeField(read_only=True)
content_target = GenericRelationField(source="content_object")
text = ContentSerializerField()
reactions_grouped = serializers.SerializerMethodField()
content_target_self = CharField(read_only=True)

class Meta:
model = Comment
Expand All @@ -22,11 +25,17 @@ class Meta:
"text",
"author",
"content_target",
"content_target_self",
"created_at",
"updated_at",
"parent",
"reactions_grouped",
)

def get_reactions_grouped(self, obj):
user = self.context["request"].user
return obj.get_reactions_grouped(user)

def validate(self, attrs):
content_target = attrs.get("content_object")

Expand Down
56 changes: 56 additions & 0 deletions lego/apps/comments/tests/test_reactions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from lego.apps.articles.models import Article
from lego.apps.comments.models import Comment
from lego.apps.emojis.models import Emoji
from lego.apps.reactions.models import Reaction
from lego.apps.users.models import User
from lego.utils.test_utils import BaseTestCase


class CommentReactionsTestCase(BaseTestCase):
fixtures = [
"test_abakus_groups.yaml",
"test_users.yaml",
"test_emojis.yaml",
"test_articles.yaml",
]

def setUp(self):
self.comment = Comment.objects.create(
created_by_id=0,
text="first comment",
content_object=Article.objects.all().first(),
)
self.user = User.objects.all().first()
self.comment.created_by = self.user
self.comment.save()

self.emoji = Emoji.objects.first()

def test_add_reaction(self):
test_reaction = Reaction.objects.create(
content_object=self.comment, emoji=self.emoji
)
test_reaction.created_by = self.user
test_reaction.save()

reactions_grouped = self.comment.get_reactions_grouped(self.user)
self.assertEqual(len(reactions_grouped), 1)
self.assertEqual(reactions_grouped[0]["count"], 1)
self.assertEqual(reactions_grouped[0]["has_reacted"], True)
self.assertEqual(
reactions_grouped[0]["unicode_string"], self.emoji.unicode_string
)

def test_remove_reaction(self):
test_reaction = Reaction.objects.create(
content_object=self.comment, emoji=self.emoji
)

reactions_grouped = self.comment.get_reactions_grouped(self.user)
self.assertEqual(len(reactions_grouped), 1)
self.assertEqual(reactions_grouped[0]["count"], 1)

test_reaction.delete()

reactions_grouped = self.comment.get_reactions_grouped(self.user)
self.assertEqual(len(reactions_grouped), 0)
25 changes: 17 additions & 8 deletions lego/apps/email/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
from django_filters.rest_framework import BooleanFilter, CharFilter, FilterSet

from lego.apps.email.models import EmailList
from lego.apps.users.constants import GROUP_COMMITTEE, GROUP_GRADE
from lego.apps.users.constants import (
GROUP_BOARD,
GROUP_COMMITTEE,
GROUP_GRADE,
GROUP_ORDAINED,
GROUP_SUB,
)
from lego.apps.users.filters import CharInFilter
from lego.apps.users.models import User


Expand All @@ -21,8 +28,8 @@ class EmailUserFilterSet(FilterSet):
email = CharFilter(field_name="internal_email__email", lookup_expr="icontains")
userUsername = CharFilter(field_name="username", lookup_expr="icontains")
userFullname = CharFilter(field_name="userFullname", method="fullname")
userCommittee = CharFilter(field_name="userCommitee", method="commitee")
userGrade = CharFilter(field_name="abakus_groups", method="grade")
userGroups = CharInFilter(field_name="userGroups", method="groups")
enabled = BooleanFilter(field_name="internal_email_enabled")

def grade(self, queryset, name, value):
Expand All @@ -34,13 +41,15 @@ def grade(self, queryset, name, value):
)
return queryset

def commitee(self, queryset, name, value):
if value == "-":
return queryset.exclude(abakus_groups__type=GROUP_COMMITTEE)
def groups(self, queryset, name, value):
relevant_types = [GROUP_COMMITTEE, GROUP_BOARD, GROUP_ORDAINED, GROUP_SUB]

if value == ["-"]:
return queryset.exclude(abakus_groups__type__in=relevant_types)
if value:
return queryset.filter(
abakus_groups__name__icontains=value,
abakus_groups__type=GROUP_COMMITTEE,
abakus_groups__name__in=value,
abakus_groups__type__in=relevant_types,
)
return queryset

Expand All @@ -59,5 +68,5 @@ class Meta:
"userUsername",
"userFullname",
"userGrade",
"userCommittee",
"userGroups",
)
31 changes: 30 additions & 1 deletion lego/apps/email/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from django.core.exceptions import ValidationError
from rest_framework import exceptions, serializers

Expand All @@ -7,7 +9,7 @@
PublicUserListField,
PublicUserWithGroupsField,
)
from lego.apps.users.models import User
from lego.apps.users.models import Membership, User

from .fields import EmailAddressField

Expand Down Expand Up @@ -44,6 +46,33 @@ class Meta:
"additional_emails",
)

def validate(self, attrs: Any) -> Any:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this stuff has nothing to do with the lending system

# Use existing values where missing to support patch requests
get = (
lambda index: attrs[index]
if index in attrs
else getattr(self.instance, index)
)
length = (
lambda value: len(value) if hasattr(value, "__len__") else value.count()
)
# Require at least one receiver of the email list
users_len, emails_len = length(get("users")), length(get("additional_emails"))
if users_len == 0 and emails_len == 0:
groups = (
attrs["groups"] if "groups" in attrs else self.instance.groups.all()
)
group_roles = get("group_roles")
memberships = Membership.objects.filter(abakus_group__in=groups)

if length(group_roles) > 0:
memberships = memberships.filter(role__in=group_roles)

if not memberships.exists():
raise ValidationError("Cannot create a mail list without receivers")

return super().validate(attrs)


class EmailListDetailSerializer(EmailListSerializer):
users = PublicUserListField({"read_only": True})
Expand Down
Loading
Loading