-
Notifications
You must be signed in to change notification settings - Fork 10
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
allow multiple comments per participation #1457
base: main
Are you sure you want to change the base?
Changes from all commits
4903e14
e62dcfc
4683f2d
a30d7ba
7210278
bba7af0
16dfe9d
64e8643
4e59023
e6b605d
9bc0f60
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# Generated by Django 5.0.9 on 2025-01-05 12:37 | ||
|
||
import django.db.models.deletion | ||
import django.utils.timezone | ||
from django.conf import settings | ||
from django.db import migrations, models | ||
|
||
|
||
def migrate_comment(apps, schema_editor): | ||
ParticipationComment = apps.get_model("core", "ParticipationComment") | ||
AbstractParticipation = apps.get_model("core", "AbstractParticipation") | ||
db_alias = schema_editor.connection.alias | ||
comments = [] | ||
for participation in AbstractParticipation.objects.using(db_alias).all(): | ||
if participation.comment: | ||
comments.append( | ||
ParticipationComment(participation=participation, text=participation.comment) | ||
) | ||
ParticipationComment.objects.using(db_alias).bulk_create(comments) | ||
|
||
|
||
def revert_comments(apps, schema_editor): | ||
ParticipationComment = apps.get_model("core", "ParticipationComment") | ||
db_alias = schema_editor.connection.alias | ||
for comment in ParticipationComment.objects.using(db_alias).all(): | ||
comment.participation.comment = comment.text | ||
comment.participation.save() | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("core", "0034_alter_eventtype_show_participant_data"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="ParticipationComment", | ||
fields=[ | ||
( | ||
"id", | ||
models.BigAutoField( | ||
auto_created=True, primary_key=True, serialize=False, verbose_name="ID" | ||
), | ||
), | ||
( | ||
"visibile_for", | ||
models.IntegerField( | ||
choices=[ | ||
(0, "responsibles only"), | ||
(1, "responsibles and corresponding participant"), | ||
(2, "everyone"), | ||
], | ||
default=0, | ||
verbose_name="visible for", | ||
), | ||
), | ||
("text", models.CharField(max_length=255, verbose_name="Comment")), | ||
( | ||
"authored_by_responsible", | ||
models.ForeignKey( | ||
blank=True, | ||
null=True, | ||
on_delete=django.db.models.deletion.SET_NULL, | ||
to=settings.AUTH_USER_MODEL, | ||
), | ||
), | ||
( | ||
"created_at", | ||
models.DateTimeField(auto_now_add=True), | ||
), | ||
( | ||
"participation", | ||
models.ForeignKey( | ||
on_delete=django.db.models.deletion.CASCADE, | ||
related_name="comments", | ||
to="core.abstractparticipation", | ||
), | ||
), | ||
], | ||
), | ||
migrations.RunPython(migrate_comment, revert_comments), | ||
migrations.RemoveField( | ||
model_name="abstractparticipation", | ||
name="comment", | ||
), | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,14 +2,16 @@ | |
from crispy_forms.helper import FormHelper | ||
from crispy_forms.layout import HTML, Field, Layout | ||
from django import forms | ||
from django.db import transaction | ||
from django.utils.formats import date_format | ||
from django.utils.timezone import localtime | ||
from django.utils.translation import gettext_lazy as _ | ||
|
||
from ephios.core.models import AbstractParticipation, Shift | ||
from ephios.core.models.events import ParticipationComment | ||
from ephios.core.signup.flow.participant_validation import get_conflicting_participations | ||
from ephios.core.signup.participants import AbstractParticipant | ||
from ephios.extra.widgets import CustomSplitDateTimeWidget | ||
from ephios.extra.widgets import CustomSplitDateTimeWidget, PreviousCommentWidget | ||
|
||
|
||
class BaseParticipationForm(forms.ModelForm): | ||
|
@@ -21,6 +23,10 @@ class BaseParticipationForm(forms.ModelForm): | |
widget=CustomSplitDateTimeWidget, | ||
required=False, | ||
) | ||
comment = forms.CharField(label=_("Comment"), max_length=255, required=False) | ||
comment_is_public = forms.BooleanField( | ||
label=_("Make comment visible for other participants"), required=False | ||
) | ||
|
||
def clean_individual_start_time(self): | ||
if self.cleaned_data["individual_start_time"] == self.shift.start_time: | ||
|
@@ -32,27 +38,52 @@ def clean_individual_end_time(self): | |
return None | ||
return self.cleaned_data["individual_end_time"] | ||
|
||
def get_comment_visibility(self): | ||
return ( | ||
ParticipationComment.Visibility.PUBLIC | ||
if self.cleaned_data["comment_is_public"] | ||
else ParticipationComment.Visibility.PARTICIPANT | ||
) | ||
|
||
def clean(self): | ||
cleaned_data = super().clean() | ||
cleaned_data["comment_visibility"] = self.get_comment_visibility() | ||
if not self.errors: | ||
start = cleaned_data["individual_start_time"] or self.shift.start_time | ||
end = cleaned_data["individual_end_time"] or self.shift.end_time | ||
if end < start: | ||
self.add_error("individual_end_time", _("End time must not be before start time.")) | ||
return cleaned_data | ||
|
||
def save(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm we can't remove the commit parameter here, as e.g. the named teams Participation Form calls save with the commit parameter. I actually ran into the exception while testing. |
||
with transaction.atomic(): | ||
result = super().save() | ||
if comment := self.cleaned_data["comment"]: | ||
ParticipationComment.objects.create( | ||
participation=result, | ||
text=comment, | ||
authored_by_responsible=self.acting_user, | ||
visibile_for=self.get_comment_visibility(), | ||
) | ||
return result | ||
Comment on lines
+58
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use |
||
|
||
class Meta: | ||
model = AbstractParticipation | ||
fields = ["individual_start_time", "individual_end_time", "comment"] | ||
fields = ["individual_start_time", "individual_end_time"] | ||
|
||
def __init__(self, *args, **kwargs): | ||
instance = kwargs["instance"] | ||
self.acting_user = kwargs.pop("acting_user", None) | ||
kwargs["initial"] = { | ||
**kwargs.get("initial", {}), | ||
"individual_start_time": instance.individual_start_time or self.shift.start_time, | ||
"individual_end_time": instance.individual_end_time or self.shift.end_time, | ||
} | ||
super().__init__(*args, **kwargs) | ||
if self.instance.pk and self.instance.comments.exists(): | ||
self.fields["previous_comments"] = forms.CharField( | ||
widget=PreviousCommentWidget(comments=self.instance.comments.all()), required=False | ||
) | ||
|
||
def get_customization_notification_info(self): | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,9 @@ <h6 class="d-inline"> | |
<button class="btn" type="button" data-bs-toggle="collapse" | ||
data-bs-target="#participation-collapse-{{ form.instance.id }}" aria-expanded="false" | ||
aria-controls="collapseExample"> | ||
{% if form.instance.comments.exists %} | ||
<span class="fa fa-comment"></span> <span class="pe-2">{{ form.instance.comments.count }}</span> | ||
{% endif %} | ||
<span class="{% if form.instance.has_customized_signup %}text-dark{% else %}text-secondary{% endif %}"> | ||
<i class="fas fa-cog"></i> | ||
<i class="fas fa-exclamation{% if not form.instance.has_customized_signup %} invisible{% endif %}"></i> | ||
|
@@ -57,13 +60,23 @@ <h6 class="d-inline"> | |
<div class="card-body"> | ||
{{ form.individual_start_time|as_crispy_field }} | ||
{{ form.individual_end_time|as_crispy_field }} | ||
{% if form.comment.initial %} | ||
{{ form.comment|as_crispy_field }} | ||
{% if form.previous_comments %} | ||
{{ form.previous_comments|as_crispy_field }} | ||
{% endif %} | ||
<div class="mb-3"> | ||
<div class="form-label"> | ||
{{ form.comment.label_tag }} | ||
<span class="float-end form-check"> | ||
<input type="checkbox" id="{{ form.comment_is_internal.auto_id }}" name="{{ form.comment_is_internal.html_name }}" class="form-check-input"> | ||
{{ form.comment_is_internal.label_tag }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
</span> | ||
</div> | ||
<input class="form-control" id="{{ form.comment.auto_id }}" name="{{ form.comment.html_name }}"> | ||
</div> | ||
{% block participation_form %} | ||
{% endblock %} | ||
<div class="mb-n3"></div> | ||
</div> | ||
</div> | ||
</div> | ||
{% endblock %} | ||
{% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bonus points for building the reverse method. Do we need the db_alias here?