internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: ephios-dev/ephios

Issue:
Show other groups that are allowed to view the event
Als Planer möchte ich beim Bearbeiten eines Events unterhalb des Feldes für die Sichtbarkeit eine Liste der Gruppen sehen, für die das Event außerdem sichtbar ist. Dies sind Gruppen, die die view_event-Permission für dieses Event haben, aber für die ich nicht die publish_event_for_group-Permission habe.


Discussion:

Resolving patch:
diff --git a/event_management/models.py b/event_management/models.py
--- a/event_management/models.py
+++ b/event_management/models.py
@@ -57,7 +57,7 @@ class Event(Model):
     class Meta:
         verbose_name = _("event")
         verbose_name_plural = _("events")
-        permissions = [("view_past_event", _("Can view events in the past"))]
+        permissions = [("view_past_event", _("Can view past events"))]
 
     @property
     def start_time(self):
diff --git a/event_management/views.py b/event_management/views.py
--- a/event_management/views.py
+++ b/event_management/views.py
@@ -69,8 +69,9 @@ def get_form(self, form_class=None):
         visible_queryset = get_objects_for_user(
             self.request.user, "publish_event_for_group", klass=Group
         )
+        visible_initial = get_groups_with_perms(self.object, only_with_perms_in=["view_event"])
         initial = {
-            "visible_for": get_groups_with_perms(self.object, only_with_perms_in=["view_event"]),
+            "visible_for": visible_initial,
             "responsible_persons": get_users_with_perms(
                 self.object, only_with_perms_in=["change_event"], with_group_users=False
             ),
@@ -80,6 +81,14 @@ def get_form(self, form_class=None):
         }
         event_form = EventForm(self.request.POST or None, instance=self.object, initial=initial)
         event_form.fields["visible_for"].queryset = visible_queryset
+        groups_without_perms = visible_initial.difference(visible_queryset)
+        if groups_without_perms:
+            event_form.fields["visible_for"].help_text = _(
+                "Select groups which the event shall be visible for. "
+                "This event is also visible for <b>{groups}</b>, "
+                "but you don't have the permission to change visibility "
+                "for those groups."
+            ).format(groups=", ".join(groups_without_perms.values_list("name", flat=True)))
         return event_form
 
 
diff --git a/jep/management/commands/setupdata.py b/jep/management/commands/setupdata.py
--- a/jep/management/commands/setupdata.py
+++ b/jep/management/commands/setupdata.py
@@ -119,9 +119,7 @@ def create_objects(self, *args, **options):
             active=True,
         )
 
-        assign_perm("event_management.change_event", planners)
-        assign_perm("event_management.view_event", planners)
-        assign_perm("event_management.view_event", volunteers)
+        assign_perm("event_management.view_event", volunteers, event)
 
         Shift.objects.create(
             event=event,


Test patch:
Repository: ephios-dev/ephios

Issue:
Fix translations in group edit & create form



Discussion:

Resolving patch:
diff --git a/user_management/forms.py b/user_management/forms.py
--- a/user_management/forms.py
+++ b/user_management/forms.py
@@ -97,15 +97,16 @@ def clean_password(self):
 
 class GroupForm(ModelForm):
     publish_event_for_group = ModelMultipleChoiceField(
+        label=_("Can publish event for group"),
         queryset=Group.objects.all(),
         required=False,
         help_text=_("Choose groups that this group can make events visible for."),
         widget=Select2MultipleWidget,
     )
-    can_view_past_event = BooleanField(required=False, label=_("Can view past events"))
-    can_add_event = BooleanField(required=False)
+    can_view_past_event = BooleanField(label=_("Can view past events"), required=False)
+    can_add_event = BooleanField(label=_("Can add event"), required=False)
     users = ModelMultipleChoiceField(
-        queryset=UserProfile.objects.all(), widget=MultiUserProfileWidget
+        label=_("Users"), queryset=UserProfile.objects.all(), widget=MultiUserProfileWidget
     )
 
     field_order = [


Test patch:
Repository: ephios-dev/ephios

Issue:
Redirect anonymous users to login view instead of raising 403
this also raises 403 if users are not logged in. this is not what we want

_Originally posted by @jeriox in https://github.com/jeriox/jep/pull/48#discussion_r479789720_


Discussion:

Resolving patch:
diff --git a/jep/permissions.py b/jep/permissions.py
--- a/jep/permissions.py
+++ b/jep/permissions.py
@@ -1,8 +1,12 @@
 import guardian.mixins
+from django.contrib.auth import REDIRECT_FIELD_NAME
 from django.contrib.auth.models import Permission, Group
+from django.contrib.auth.views import redirect_to_login
 from guardian.ctypes import get_content_type
 from guardian.utils import get_group_obj_perms_model
 
+from jep import settings
+
 
 def get_groups_with_perms(obj, only_with_perms_in):
 
@@ -32,4 +36,10 @@ class CustomPermissionRequiredMixin(guardian.mixins.PermissionRequiredMixin):
     raise_exception = True
     accept_global_perms = True
 
-    # FIXME redirect non logged in users and raise Permission for others
+    def on_permission_check_fail(self, request, response, obj=None):
+        if request.user.is_authenticated:
+            return response
+        else:
+            return redirect_to_login(
+                self.request.get_full_path(), settings.LOGIN_URL, REDIRECT_FIELD_NAME
+            )


Test patch:
Repository: ephios-dev/ephios

Issue:
Implement Content Security Policy
which means we can't have inline javascript!

* https://docs.djangoproject.com/en/3.1/topics/security/
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src


Discussion:

Resolving patch:
diff --git a/ephios/event_management/templatetags/event_extras.py b/ephios/event_management/templatetags/event_extras.py
--- a/ephios/event_management/templatetags/event_extras.py
+++ b/ephios/event_management/templatetags/event_extras.py
@@ -35,8 +35,8 @@ def signup_errors(shift, user):
     return shift.signup_method.get_signup_errors(user.as_participant())
 
 
-@register.filter(name="can_user_decline")
-def can_user_decline(shift, user):
+@register.filter(name="can_decline")
+def can_decline(shift, user):
     return shift.signup_method.can_decline(user.as_participant())
 
 
diff --git a/ephios/helpers/context.py b/ephios/helpers/context.py
--- a/ephios/helpers/context.py
+++ b/ephios/helpers/context.py
@@ -1,3 +1,6 @@
+from django.templatetags.static import static
+from django.utils.translation import get_language
+
 from ephios.helpers.signals import footer_link
 
 
@@ -7,6 +10,8 @@ def ephios_base_context(request):
         for label, url in result.items():
             footer[label] = url
 
-    return {
-        "footer": footer,
-    }
+    datatables_translation_url = None
+    if get_language() == "de-de":
+        datatables_translation_url = static("datatables/german.json")
+
+    return {"footer": footer, "datatables_translation_url": datatables_translation_url}
diff --git a/ephios/settings.py b/ephios/settings.py
--- a/ephios/settings.py
+++ b/ephios/settings.py
@@ -68,6 +68,7 @@
     "django.contrib.auth.middleware.AuthenticationMiddleware",
     "django.contrib.messages.middleware.MessageMiddleware",
     "django.middleware.clickjacking.XFrameOptionsMiddleware",
+    "csp.middleware.CSPMiddleware",
 ]
 
 ROOT_URLCONF = "ephios.urls"


Test patch:
Repository: ephios-dev/ephios

Issue:
Kalender-URL schöner anzeigen
Als Nutzer möchte ich auf meiner Profilseite ein read-only-Feld sehen, in dem die URL zu meinem Kalender-Feed steht. Der Link soll nicht klickbar sein, damit die ics-Datei nicht heruntergeladen wird. Neben dem Link soll ein Button zum Kopieren der URL vorhanden sein.


Discussion:

Resolving patch:
diff --git a/ephios/extra/context.py b/ephios/extra/context.py
--- a/ephios/extra/context.py
+++ b/ephios/extra/context.py
@@ -5,6 +5,7 @@
 from django.utils.translation import get_language
 
 from ephios.extra.signals import footer_link
+from ephios.settings import SITE_URL
 
 try:
     EPHIOS_VERSION = (
@@ -29,4 +30,5 @@ def ephios_base_context(request):
         "footer": footer,
         "datatables_translation_url": datatables_translation_url,
         "ephios_version": EPHIOS_VERSION,
+        "SITE_URL": SITE_URL,
     }


Test patch:
Repository: ephios-dev/ephios

Issue:
Age checking for signup consideres wrong date
When checking the participant age, the age at the current date is evaluated instead of the age at the event date


Discussion:

Resolving patch:
diff --git a/ephios/event_management/signup.py b/ephios/event_management/signup.py
--- a/ephios/event_management/signup.py
+++ b/ephios/event_management/signup.py
@@ -47,9 +47,8 @@ class AbstractParticipant:
     date_of_birth: date
     email: Optional[str]  # if set to None, no notifications are sent
 
-    @property
-    def age(self):
-        today, born = date.today(), self.date_of_birth
+    def get_age(self, today: date = None):
+        today, born = today or date.today(), self.date_of_birth
         return today.year - born.year - ((today.month, today.day) < (born.month, born.day))
 
     def __str__(self):
@@ -156,7 +155,8 @@ def check_inside_signup_timeframe(method, participant):
 
 def check_participant_age(method, participant):
     minimum_age = method.configuration.minimum_age
-    if minimum_age is not None and participant.age < minimum_age:
+    day = method.shift.start_time.date()
+    if minimum_age is not None and participant.get_age(day) < minimum_age:
         return ParticipationError(
             _("You are too young. The minimum age is {age}.").format(age=minimum_age)
         )


Test patch:
Repository: ephios-dev/ephios

Issue:
Event creation mails do not include event description



Discussion:

Resolving patch:
diff --git a/ephios/event_management/mail.py b/ephios/event_management/mail.py
--- a/ephios/event_management/mail.py
+++ b/ephios/event_management/mail.py
@@ -1,3 +1,5 @@
+from urllib.parse import urljoin
+
 from django.core import mail
 from django.core.mail import EmailMultiAlternatives
 from django.template.loader import render_to_string
@@ -20,8 +22,16 @@ def new_event(event):
 
     subject = _("New {type}: {title}").format(type=event.type, title=event.title)
     text_content = _(
-        "A new {type} ({title}) has been added. \n You can view it here: {link}"
-    ).format(type=event.type, title=event.title, link=event.get_absolute_url())
+        "A new {type} ({title}, {location}) has been added.\n"
+        "Further information: {description}\n"
+        "You can view the event here: {url}"
+    ).format(
+        type=event.type,
+        title=event.title,
+        location=event.location,
+        description=event.description,
+        url=urljoin(SITE_URL, event.get_absolute_url()),
+    )
     html_content = render_to_string(
         "event_management/mails/new_event.html", {"event": event, "site_url": SITE_URL}
     )
diff --git a/ephios/user_management/mail.py b/ephios/user_management/mail.py
--- a/ephios/user_management/mail.py
+++ b/ephios/user_management/mail.py
@@ -1,3 +1,5 @@
+from urllib.parse import urljoin
+
 from django.contrib.auth.tokens import default_token_generator
 from django.core.mail import EmailMultiAlternatives
 from django.template.loader import render_to_string
@@ -16,9 +18,9 @@ def send_account_creation_info(userprofile):
     reset_link = reverse("password_reset_confirm", kwargs={"uidb64": uid, "token": token})
     text_content = _(
         "You're receiving this email because a new account has been created for you at ephios.\n"
-        "Please go to the following page and choose a password: {url}{reset_link}\n"
+        "Please go to the following page and choose a password: {url}\n"
         "Your username is your email address: {email}\n"
-    ).format(url=SITE_URL, reset_link=reset_link, email=userprofile.email)
+    ).format(url=urljoin(SITE_URL, reset_link), email=userprofile.email)
 
     html_content = render_to_string(
         "user_management/new_account_email.html",
@@ -34,9 +36,9 @@ def send_account_update_info(userprofile):
     url = reverse("user_management:profile")
     text_content = _(
         "You're receiving this email because your account at ephios has been updated.\n"
-        "You can see the changes in your profile: {site_url}{url}\n"
+        "You can see the changes in your profile: {url}\n"
         "Your username is your email address: {email}\n"
-    ).format(site_url=SITE_URL, url=url, email=userprofile.email)
+    ).format(url=urljoin(SITE_URL, url), email=userprofile.email)
 
     html_content = render_to_string(
         "user_management/account_updated_email.html",


Test patch:
Repository: ephios-dev/ephios

Issue:
List of own upcoming shifts
As a user, I want to see a list of shifts that I have been confirmed for on the main page.


Discussion:

Resolving patch:
diff --git a/ephios/event_management/templatetags/event_extras.py b/ephios/event_management/templatetags/event_extras.py
--- a/ephios/event_management/templatetags/event_extras.py
+++ b/ephios/event_management/templatetags/event_extras.py
@@ -43,3 +43,10 @@ def can_decline(shift, user):
 @register.filter(name="decline_errors")
 def decline_errors(shift, user):
     return shift.signup_method.get_decline_errors(user.as_participant())
+
+
+@register.filter(name="confirmed_shifts")
+def confirmed_shifts(user):
+    return user.get_shifts(
+        with_participation_state_in=[AbstractParticipation.States.CONFIRMED]
+    ).order_by("start_time")


Test patch:
diff --git a/tests/event_management/test_event_copy.py b/tests/event_management/test_event_copy.py
--- a/tests/event_management/test_event_copy.py
+++ b/tests/event_management/test_event_copy.py
@@ -1,4 +1,4 @@
-from datetime import date, datetime, timedelta
+from datetime import datetime, timedelta
 
 import pytest
 import recurrence
Repository: ephios-dev/ephios

Issue:
Translations for v0.2.0



Discussion:

Resolving patch:
diff --git a/ephios/user_management/consequences.py b/ephios/user_management/consequences.py
--- a/ephios/user_management/consequences.py
+++ b/ephios/user_management/consequences.py
@@ -117,7 +117,7 @@ def execute(cls, consequence):
 
     @classmethod
     def render(cls, consequence):
-        return _("{user} logs {hours:.1f} hours on {date} for {reason}").format(
+        return _("{user} logs {hours:.1f} hours on {date}. Reason: {reason}").format(
             user=consequence.user.get_full_name(),
             hours=consequence.data.get("hours"),
             reason=consequence.data.get("reason"),


Test patch:
Repository: ephios-dev/ephios

Issue:
User can self-grant permissions
Consider group A with only the permission to manage users and group B with all permissions.
A user in group A can now edit the own user profile and add group B to the own groups. After saving, the user is now member of group B and has all permissions.

One should only be able to edit the group memberships of a user if one also has the change_group permission. Otherwise the field should be deactivated and a hint should be shown.
The hints on the group edit form should also be improved to explain that the "users" permission means editing userprofiles and the "group" permission means editing groups, group memberships and permissions.


Discussion:

Resolving patch:
diff --git a/ephios/user_management/forms.py b/ephios/user_management/forms.py
--- a/ephios/user_management/forms.py
+++ b/ephios/user_management/forms.py
@@ -115,7 +115,9 @@ class GroupForm(ModelForm):
     )
     can_manage_group = BooleanField(
         label=_("Can manage groups"),
-        help_text=_("If checked, users in this group can view, add, edit and delete groups."),
+        help_text=_(
+            "If checked, users in this group can add and edit all groups, their permissions as well as group memberships."
+        ),
         required=False,
     )
     users = ModelMultipleChoiceField(
@@ -235,9 +237,21 @@ def save(self, commit=True):
 
 class UserProfileForm(ModelForm):
     groups = ModelMultipleChoiceField(
-        label=_("Groups"), queryset=Group.objects.all(), widget=Select2MultipleWidget
+        label=_("Groups"),
+        queryset=Group.objects.all(),
+        widget=Select2MultipleWidget,
+        required=False,
+        disabled=True,  # explicitly enable for users with `change_group` permission
     )
 
+    def __init__(self, *args, **kwargs):
+        request = kwargs.pop("request")
+        super().__init__(*args, **kwargs)
+        if request and request.user.has_perm("change_group"):
+            self.fields["groups"].disabled = False
+        else:
+            self.fields["groups"].help_text = _("You are not allowed to change group associations.")
+
     field_order = [
         "email",
         "first_name",
diff --git a/ephios/user_management/views/accounts.py b/ephios/user_management/views/accounts.py
--- a/ephios/user_management/views/accounts.py
+++ b/ephios/user_management/views/accounts.py
@@ -37,7 +37,9 @@ class UserProfileCreateView(CustomPermissionRequiredMixin, TemplateView):
     model = UserProfile
 
     def get_context_data(self, **kwargs):
-        kwargs.setdefault("userprofile_form", UserProfileForm(self.request.POST or None))
+        kwargs.setdefault(
+            "userprofile_form", UserProfileForm(self.request.POST or None, request=self.request)
+        )
         kwargs.setdefault(
             "qualification_formset", QualificationGrantFormset(self.request.POST or None)
         )
@@ -78,6 +80,7 @@ def get_userprofile_form(self):
                 "groups": self.get_object().groups.all(),
             },
             instance=self.object,
+            request=self.request,
         )
 
     def get_qualification_formset(self):


Test patch:
Repository: ephios-dev/ephios

Issue:
Format event description
As a planner, I want to be able to format the event description. This should at least mean that links will be formatted so that they are clickable. Maybe this should mean that the description will accept Markdown.


Discussion:

Resolving patch:
diff --git a/ephios/extra/templatetags/rich_text.py b/ephios/extra/templatetags/rich_text.py
--- a/ephios/extra/templatetags/rich_text.py
+++ b/ephios/extra/templatetags/rich_text.py
@@ -53,22 +53,28 @@
 ALLOWED_PROTOCOLS = ["http", "https", "mailto", "tel"]
 
 
-def markdown_compile(source):
+def markdown_compile(source, excluded_tags=""):
     extensions = ["markdown.extensions.sane_lists", "markdown.extensions.nl2br"]
+    tags = ALLOWED_TAGS.copy()
+    for tag in excluded_tags.split(","):
+        try:
+            tags.remove(tag)
+        except ValueError:
+            pass
     return bleach.clean(
         markdown.markdown(source, extensions=extensions),
-        tags=ALLOWED_TAGS,
+        tags=tags,
         attributes=ALLOWED_ATTRIBUTES,
         protocols=ALLOWED_PROTOCOLS,
     )
 
 
 @register.filter
-def rich_text(text: str, **kwargs):
+def rich_text(text: str, excluded_tags=""):
     """
     Processes markdown and cleans HTML in a text input.
     """
     text = str(text)
     linker = bleach.Linker(parse_email=True)
-    body_md = linker.linkify(markdown_compile(text))
+    body_md = linker.linkify(markdown_compile(text, excluded_tags=excluded_tags))
     return mark_safe(body_md)


Test patch:
Repository: ephios-dev/ephios

Issue:
Add caching
As of #278 some settings reside in the database, so we should defintely cache database requests.


Discussion:

Resolving patch:
diff --git a/ephios/settings.py b/ephios/settings.py
--- a/ephios/settings.py
+++ b/ephios/settings.py
@@ -114,6 +114,12 @@
 
 DATABASES = {"default": env.db_url()}
 
+# Caches
+CACHES = {"default": env.cache_url(default="locmemcache://")}
+SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
+DJANGO_REDIS_IGNORE_EXCEPTIONS = True
+DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
+
 # Password validation
 # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
 


Test patch:
Repository: ephios-dev/ephios

Issue:
Cannot delete section
As a planner, I cannot delete an existing section from a shift with the section_based signup method


Discussion:

Resolving patch:
diff --git a/ephios/plugins/basesignup/signup/section_based.py b/ephios/plugins/basesignup/signup/section_based.py
--- a/ephios/plugins/basesignup/signup/section_based.py
+++ b/ephios/plugins/basesignup/signup/section_based.py
@@ -134,6 +134,7 @@ def clean_sections(self):
                 for key in ("title", "qualifications", "min_count", "uuid")
             }
             for form in self.sections_formset
+            if not form.cleaned_data.get("DELETE")
         ]
         return sections
 


Test patch:
Repository: ephios-dev/ephios

Issue:
Maximum number of participants for SectionBasedSignup



Discussion:

Resolving patch:
diff --git a/ephios/plugins/basesignup/signup/section_based.py b/ephios/plugins/basesignup/signup/section_based.py
--- a/ephios/plugins/basesignup/signup/section_based.py
+++ b/ephios/plugins/basesignup/signup/section_based.py
@@ -104,6 +104,7 @@ class SectionForm(forms.Form):
         required=False,
     )
     min_count = forms.IntegerField(label=_("min amount"), min_value=0, required=True)
+    max_count = forms.IntegerField(label=_("max amount"), min_value=1, required=False)
     uuid = forms.CharField(widget=forms.HiddenInput, required=False)
 
     def clean_uuid(self):
@@ -131,7 +132,7 @@ def clean_sections(self):
         sections = [
             {
                 key: form.cleaned_data[key]
-                for key in ("title", "qualifications", "min_count", "uuid")
+                for key in ("title", "qualifications", "min_count", "max_count", "uuid")
             }
             for form in self.sections_formset
             if not form.cleaned_data.get("DELETE")
@@ -233,7 +234,15 @@ def get_configuration_fields(self):
         }
 
     def get_participant_count_bounds(self):
-        return sum(section.get("min_count") or 0 for section in self.configuration.sections), None
+        return (
+            sum(section.get("min_count") or 0 for section in self.configuration.sections),
+            sum(
+                section.get("max_count") or section.get("min_count")
+                for section in self.configuration.sections
+            )
+            if all(section.get("max_count") for section in self.configuration.sections)
+            else None,
+        )
 
     @staticmethod
     def check_qualification(method, participant):


Test patch:
Repository: ephios-dev/ephios

Issue:
Select2 on disposition view shows error alert
Closing the select2 field in the disposition view without selecting an entry (e.g. by typing something into the field an then clicking somewhere outside the field) also triggers the form submission. This fails because no valid user has been selected and consequently shows an ugly alert to the user.


Discussion:

Resolving patch:
diff --git a/ephios/core/context.py b/ephios/core/context.py
--- a/ephios/core/context.py
+++ b/ephios/core/context.py
@@ -1,7 +1,6 @@
 import importlib
 
 from django.conf import settings
-from django.templatetags.static import static
 from django.utils.translation import get_language
 
 from ephios.core.models import AbstractParticipation
@@ -17,14 +16,10 @@ def ephios_base_context(request):
         for label, url in result.items():
             footer[label] = url
 
-    datatables_translation_url = None
-    if get_language() == "de-de":
-        datatables_translation_url = static("datatables/german.json")
-
     return {
         "ParticipationStates": AbstractParticipation.States,
         "footer": footer,
-        "datatables_translation_url": datatables_translation_url,
+        "LANGUAGE_CODE": get_language(),
         "ephios_version": EPHIOS_VERSION,
         "SITE_URL": settings.SITE_URL,
         "PWA_APP_ICONS": settings.PWA_APP_ICONS,


Test patch: