mirror of
https://github.com/lucaspalomodevelop/eventcally.git
synced 2026-03-13 16:14:36 +00:00
446 lines
15 KiB
Python
446 lines
15 KiB
Python
from dateutil.relativedelta import relativedelta
|
|
from flask import request
|
|
from flask_babelex import gettext, lazy_gettext
|
|
from flask_wtf import FlaskForm
|
|
from wtforms import (
|
|
BooleanField,
|
|
FormField,
|
|
IntegerField,
|
|
RadioField,
|
|
SelectField,
|
|
SelectMultipleField,
|
|
StringField,
|
|
SubmitField,
|
|
TextAreaField,
|
|
)
|
|
from wtforms.fields.core import FieldList
|
|
from wtforms.fields.html5 import EmailField, URLField
|
|
from wtforms.validators import DataRequired, Length, Optional
|
|
|
|
from project.forms.common import Base64ImageForm, event_rating_choices
|
|
from project.forms.event_place import EventPlaceLocationForm
|
|
from project.forms.widgets import CustomDateField, CustomDateTimeField, HTML5StringField
|
|
from project.models import (
|
|
EventAttendanceMode,
|
|
EventDateDefinition,
|
|
EventOrganizer,
|
|
EventPlace,
|
|
EventStatus,
|
|
EventTargetGroupOrigin,
|
|
Image,
|
|
Location,
|
|
PublicStatus,
|
|
)
|
|
|
|
|
|
class EventDateDefinitionFormMixin:
|
|
start = CustomDateTimeField(
|
|
lazy_gettext("Start"),
|
|
validators=[DataRequired()],
|
|
description=lazy_gettext("Indicate when the event date will start."),
|
|
)
|
|
end = CustomDateTimeField(
|
|
lazy_gettext("End"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext(
|
|
"Indicate when the event date will end. An event can last a maximum of 14 days."
|
|
),
|
|
)
|
|
allday = BooleanField(
|
|
lazy_gettext("All-day"),
|
|
validators=[Optional()],
|
|
)
|
|
recurrence_rule = TextAreaField(
|
|
lazy_gettext("Recurring event"),
|
|
validators=[Optional()],
|
|
)
|
|
|
|
def validate_date_definition(self):
|
|
if self.start.data and self.end.data:
|
|
if self.start.data > self.end.data:
|
|
msg = gettext("The start must be before the end.")
|
|
self.start.errors.append(msg)
|
|
return False
|
|
|
|
max_end = self.start.data + relativedelta(days=14)
|
|
if self.end.data > max_end:
|
|
msg = gettext("An event can last a maximum of 14 days.")
|
|
self.end.errors.append(msg)
|
|
return False
|
|
return True
|
|
|
|
|
|
class EventDateDefinitionForm(FlaskForm, EventDateDefinitionFormMixin):
|
|
def validate(self):
|
|
result = super().validate()
|
|
|
|
if not self.validate_date_definition():
|
|
result = False
|
|
|
|
return result
|
|
|
|
|
|
class EventPlaceForm(FlaskForm):
|
|
name = StringField(
|
|
lazy_gettext("Name"),
|
|
validators=[Optional()],
|
|
)
|
|
location = FormField(EventPlaceLocationForm, default=lambda: Location())
|
|
|
|
def populate_obj(self, obj):
|
|
for name, field in self._fields.items():
|
|
if name == "location" and not obj.location:
|
|
obj.location = Location()
|
|
field.populate_obj(obj, name)
|
|
|
|
|
|
class OrganizerForm(EventPlaceForm):
|
|
pass
|
|
|
|
|
|
class EventOrganizerForm(FlaskForm):
|
|
name = StringField(
|
|
lazy_gettext("Organizator"),
|
|
validators=[Optional()],
|
|
)
|
|
url = URLField(lazy_gettext("Link URL"), validators=[Optional()])
|
|
email = EmailField(lazy_gettext("Email"), validators=[Optional()])
|
|
phone = StringField(lazy_gettext("Phone"), validators=[Optional()])
|
|
fax = StringField(lazy_gettext("Fax"), validators=[Optional()])
|
|
|
|
|
|
class SharedEventForm(FlaskForm):
|
|
name = HTML5StringField(
|
|
lazy_gettext("Name"),
|
|
validators=[DataRequired(), Length(min=3, max=255)],
|
|
description=lazy_gettext("Enter a short, meaningful name for the event."),
|
|
)
|
|
description = TextAreaField(
|
|
lazy_gettext("Description"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext("Add an description of the event."),
|
|
)
|
|
external_link = URLField(
|
|
lazy_gettext("Link URL"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext(
|
|
"Enter a link to an external website containing more information about the event."
|
|
),
|
|
)
|
|
ticket_link = URLField(
|
|
lazy_gettext("Ticket Link URL"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext("Enter a link where tickets can be purchased."),
|
|
)
|
|
tags = StringField(
|
|
lazy_gettext("Tags"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext(
|
|
"Enter keywords with which the event should be found. Words do not need to be entered if they are already in the name or description."
|
|
),
|
|
)
|
|
kid_friendly = BooleanField(
|
|
lazy_gettext("Kid friendly"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext("If the event is particularly suitable for children."),
|
|
)
|
|
accessible_for_free = BooleanField(
|
|
lazy_gettext("Accessible for free"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext("If the event is accessible for free."),
|
|
)
|
|
age_from = IntegerField(
|
|
lazy_gettext("Typical Age from"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext("The minimum age that participants should be."),
|
|
)
|
|
age_to = IntegerField(
|
|
lazy_gettext("Typical Age to"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext("The maximum age that participants should be."),
|
|
)
|
|
registration_required = BooleanField(
|
|
lazy_gettext("Registration required"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext(
|
|
"If the participants needs to register for the event."
|
|
),
|
|
)
|
|
booked_up = BooleanField(
|
|
lazy_gettext("Booked up"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext("If the event is booked up or sold out."),
|
|
)
|
|
expected_participants = IntegerField(
|
|
lazy_gettext("Expected number of participants"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext("The estimated expected attendance."),
|
|
)
|
|
price_info = TextAreaField(
|
|
lazy_gettext("Price info"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext(
|
|
"Enter price information in textual form. E.g., different prices for adults and children."
|
|
),
|
|
)
|
|
target_group_origin = SelectField(
|
|
lazy_gettext("Target group origin"),
|
|
coerce=int,
|
|
choices=[
|
|
(
|
|
int(EventTargetGroupOrigin.both),
|
|
lazy_gettext("EventTargetGroupOrigin.both"),
|
|
),
|
|
(
|
|
int(EventTargetGroupOrigin.tourist),
|
|
lazy_gettext("EventTargetGroupOrigin.tourist"),
|
|
),
|
|
(
|
|
int(EventTargetGroupOrigin.resident),
|
|
lazy_gettext("EventTargetGroupOrigin.resident"),
|
|
),
|
|
],
|
|
description=lazy_gettext(
|
|
"Choose whether the event is particularly suitable for tourists or residents."
|
|
),
|
|
)
|
|
attendance_mode = SelectField(
|
|
lazy_gettext("Attendance mode"),
|
|
coerce=int,
|
|
choices=[
|
|
(
|
|
int(EventAttendanceMode.offline),
|
|
lazy_gettext("EventAttendanceMode.offline"),
|
|
),
|
|
(
|
|
int(EventAttendanceMode.online),
|
|
lazy_gettext("EventAttendanceMode.online"),
|
|
),
|
|
(int(EventAttendanceMode.mixed), lazy_gettext("EventAttendanceMode.mixed")),
|
|
],
|
|
description=lazy_gettext("Choose how people can attend the event."),
|
|
)
|
|
photo = FormField(
|
|
Base64ImageForm,
|
|
lazy_gettext("Photo"),
|
|
default=lambda: Image(),
|
|
description=lazy_gettext(
|
|
"We recommend uploading a photo for the event. It looks a lot more, but of course it works without it."
|
|
),
|
|
)
|
|
|
|
|
|
class BaseEventForm(SharedEventForm):
|
|
date_definitions = FieldList(
|
|
FormField(EventDateDefinitionForm, default=lambda: EventDateDefinition()),
|
|
min_entries=1,
|
|
)
|
|
date_definition_template = FormField(
|
|
EventDateDefinitionForm, default=lambda: EventDateDefinition()
|
|
)
|
|
previous_start_date = CustomDateTimeField(
|
|
lazy_gettext("Previous start date"),
|
|
validators=[Optional()],
|
|
description=lazy_gettext(
|
|
"Enter when the event should have taken place before it was postponed."
|
|
),
|
|
)
|
|
category_ids = SelectMultipleField(
|
|
lazy_gettext("Categories"),
|
|
validators=[DataRequired()],
|
|
coerce=int,
|
|
description=lazy_gettext("Choose categories that fit the event."),
|
|
)
|
|
rating = SelectField(
|
|
lazy_gettext("Rating"),
|
|
default=50,
|
|
coerce=int,
|
|
choices=event_rating_choices,
|
|
description=lazy_gettext(
|
|
"Choose how relevant the event is to your organization. The value is not visible and is used for sorting."
|
|
),
|
|
)
|
|
co_organizer_ids = SelectMultipleField(
|
|
lazy_gettext("Co-organizers"),
|
|
validators=[Optional()],
|
|
coerce=int,
|
|
description=lazy_gettext(
|
|
"Select optional co-organizers. You can add and modify organizers at Organization > Organizers."
|
|
),
|
|
)
|
|
|
|
def validate(self):
|
|
result = super().validate()
|
|
|
|
if self.co_organizer_ids.data and self.organizer_id.data:
|
|
if self.organizer_id.data in self.co_organizer_ids.data:
|
|
msg = gettext("Invalid co-organizer.")
|
|
self.co_organizer_ids.errors.append(msg)
|
|
result = False
|
|
|
|
return result
|
|
|
|
|
|
class CreateEventForm(BaseEventForm):
|
|
event_place_choice = RadioField(
|
|
lazy_gettext("Place"),
|
|
choices=[
|
|
(1, lazy_gettext("Select existing place")),
|
|
(2, lazy_gettext("Enter new place")),
|
|
],
|
|
default=1,
|
|
coerce=int,
|
|
)
|
|
event_place_id = SelectField(
|
|
lazy_gettext("Place"),
|
|
validators=[Optional()],
|
|
coerce=int,
|
|
)
|
|
new_event_place = FormField(EventPlaceForm, default=lambda: EventPlace())
|
|
|
|
organizer_choice = RadioField(
|
|
lazy_gettext("Organizer"),
|
|
choices=[
|
|
(1, lazy_gettext("Select existing organizer")),
|
|
(2, lazy_gettext("Enter new organizer")),
|
|
],
|
|
default=1,
|
|
coerce=int,
|
|
)
|
|
organizer_id = SelectField(
|
|
lazy_gettext("Organizer"),
|
|
validators=[Optional()],
|
|
coerce=int,
|
|
)
|
|
new_organizer = FormField(OrganizerForm, default=lambda: EventOrganizer())
|
|
|
|
submit_draft = SubmitField(lazy_gettext("Save as draft"))
|
|
submit = SubmitField(lazy_gettext("Publish event"))
|
|
|
|
def populate_obj(self, obj):
|
|
for name, field in self._fields.items():
|
|
if name == "new_event_place":
|
|
if self.event_place_choice.data != 2:
|
|
continue
|
|
if not obj.event_place:
|
|
obj.event_place = EventPlace()
|
|
field.populate_obj(obj, "event_place")
|
|
elif name == "new_organizer":
|
|
if self.organizer_choice.data != 2:
|
|
continue
|
|
if not obj.organizer:
|
|
obj.organizer = EventOrganizer()
|
|
field.populate_obj(obj, "organizer")
|
|
elif name == "photo" and not obj.photo:
|
|
obj.photo = Image()
|
|
elif name == "date_definition_template":
|
|
continue
|
|
field.populate_obj(obj, name)
|
|
|
|
obj.public_status = (
|
|
PublicStatus.published if self.submit.data else PublicStatus.draft
|
|
)
|
|
|
|
def validate(self):
|
|
result = super().validate()
|
|
|
|
if (
|
|
not self.event_place_id.data or self.event_place_id.data == 0
|
|
) and not self.new_event_place.form.name.data:
|
|
msg = gettext("Select existing place or enter new place")
|
|
self.event_place_id.errors.append(msg)
|
|
self.new_event_place.form.name.errors.append(msg)
|
|
result = False
|
|
|
|
if (
|
|
not self.organizer_id.data or self.organizer_id.data == 0
|
|
) and not self.new_organizer.form.name.data:
|
|
msg = gettext("Select existing organizer or enter new organizer")
|
|
self.organizer_id.errors.append(msg)
|
|
self.new_organizer.form.name.errors.append(msg)
|
|
result = False
|
|
|
|
return result
|
|
|
|
|
|
class UpdateEventForm(BaseEventForm):
|
|
event_place_id = SelectField(
|
|
lazy_gettext("Place"),
|
|
validators=[DataRequired()],
|
|
coerce=int,
|
|
description=lazy_gettext(
|
|
"Choose where the event takes place. You can add and modify places at Organization > Places."
|
|
),
|
|
)
|
|
organizer_id = SelectField(
|
|
lazy_gettext("Organizer"),
|
|
validators=[DataRequired()],
|
|
coerce=int,
|
|
description=lazy_gettext(
|
|
"Select the organizer. You can add and modify organizers at Organization > Organizers."
|
|
),
|
|
)
|
|
|
|
status = SelectField(
|
|
lazy_gettext("Status"),
|
|
coerce=int,
|
|
choices=[
|
|
(int(EventStatus.scheduled), lazy_gettext("EventStatus.scheduled")),
|
|
(int(EventStatus.cancelled), lazy_gettext("EventStatus.cancelled")),
|
|
(int(EventStatus.movedOnline), lazy_gettext("EventStatus.movedOnline")),
|
|
(int(EventStatus.postponed), lazy_gettext("EventStatus.postponed")),
|
|
(int(EventStatus.rescheduled), lazy_gettext("EventStatus.rescheduled")),
|
|
],
|
|
description=lazy_gettext("Select the status of the event."),
|
|
)
|
|
|
|
public_status = SelectField(
|
|
lazy_gettext("Public status"),
|
|
coerce=int,
|
|
choices=[
|
|
(int(PublicStatus.published), lazy_gettext("PublicStatus.published")),
|
|
(int(PublicStatus.draft), lazy_gettext("PublicStatus.draft")),
|
|
],
|
|
description=lazy_gettext("Select the public status of the event."),
|
|
)
|
|
|
|
submit = SubmitField(lazy_gettext("Update event"))
|
|
|
|
def populate_obj(self, obj):
|
|
for name, field in self._fields.items():
|
|
if name == "photo" and not obj.photo:
|
|
obj.photo = Image()
|
|
elif name == "date_definition_template":
|
|
continue
|
|
field.populate_obj(obj, name)
|
|
|
|
if obj.photo and obj.photo.is_empty():
|
|
obj.photo = None
|
|
obj.photo_id = None
|
|
|
|
|
|
class DeleteEventForm(FlaskForm):
|
|
submit = SubmitField(lazy_gettext("Delete event"))
|
|
|
|
|
|
class FindEventForm(FlaskForm):
|
|
class Meta:
|
|
csrf = False
|
|
|
|
date_from = CustomDateField(lazy_gettext("From"), validators=[Optional()])
|
|
date_to = CustomDateField(
|
|
lazy_gettext("to"), set_end_of_day=True, validators=[Optional()]
|
|
)
|
|
keyword = StringField(lazy_gettext("Keyword"), validators=[Optional()])
|
|
category_id = SelectField(
|
|
lazy_gettext("Category"), validators=[Optional()], coerce=int
|
|
)
|
|
organizer_id = SelectField(
|
|
lazy_gettext("Organizer"), validators=[Optional()], coerce=int
|
|
)
|
|
|
|
submit = SubmitField(lazy_gettext("Find events"))
|
|
|
|
def is_submitted(self):
|
|
return "submit" in request.args
|