diff --git a/calsocial/__init__.py b/calsocial/__init__.py index 000e2eb..d6f6c02 100644 --- a/calsocial/__init__.py +++ b/calsocial/__init__.py @@ -235,12 +235,13 @@ class CalendarSocialApp(Flask): return render_template('user-settings.html', form=form) @staticmethod - @route('/event/') + @route('/event/', methods=['GET', 'POST']) def event_details(event_uuid): """View to display event details """ - from .models import Event + from .forms import InviteForm + from .models import db, Event, Invitation, Notification, NotificationAction try: event = Event.query.filter(Event.event_uuid == event_uuid).one() @@ -249,7 +250,24 @@ class CalendarSocialApp(Flask): except MultipleResultsFound: abort(500) - return render_template('event-details.html', event=event) + form = InviteForm(event) + + if form.validate_on_submit(): + invite = Invitation(event=event, sender=current_user.profile) + form.populate_obj(invite) + db.session.add(invite) + + notification = Notification(profile=form.invitee.data, + actor=current_user.profile, + item=event, + action=NotificationAction.invite) + db.session.add(notification) + + db.session.commit() + + return redirect(url_for('event_details', event_uuid=event.event_uuid)) + + return render_template('event-details.html', event=event, form=form) @staticmethod @route('/profile/@') diff --git a/calsocial/forms.py b/calsocial/forms.py index ea0534e..509c152 100644 --- a/calsocial/forms.py +++ b/calsocial/forms.py @@ -194,3 +194,68 @@ class LoginForm(BaseLoginForm): AuditLog.log(self.user, AuditLog.TYPE_LOGIN_FAIL) return ret + + +class ProfileField(StringField): + """Input field for profiles + """ + + def process_formdata(self, valuelist): + from sqlalchemy.orm.exc import NoResultFound + + from .models import User, Profile + + if not valuelist: + self.data = None + + return + + value = valuelist[0] + + if value.startswith('@'): + value = value[1:] + + try: + self.data = Profile.query.join(User).filter(User.username == value).one() + except NoResultFound: + self.data = None + + raise ValueError('Unknown user') + + def _value(self): + if self.data: + return self.data.fqn + + return '' + + +class InviteForm(FlaskForm): + """Form for event invitations + """ + + invitee = ProfileField(validators=[DataRequired()]) + + def __init__(self, event, *args, **kwargs): + FlaskForm.__init__(self, *args, **kwargs) + + self.event = event + + def validate_invitee(self, field): + """Validate the value of the invitee field + + :raises ValidationError: If the given user is already invited + """ + + from sqlalchemy.orm.exc import NoResultFound + + from .models import Invitation + + try: + Invitation.query \ + .filter(Invitation.event == self.event) \ + .filter(Invitation.invitee == field.data) \ + .one() + + raise ValidationError(_('User is already invited')) + except NoResultFound: + pass diff --git a/calsocial/models.py b/calsocial/models.py index e877458..36e7ce1 100644 --- a/calsocial/models.py +++ b/calsocial/models.py @@ -64,9 +64,13 @@ class NotificationAction(Enum): #: A user followed another follow = 1 + #: A user has been invited to an event + invite = 2 + NOTIFICATION_ACTION_MESSAGES = { - NotificationAction.follow: (_('%(actor)s followed you'), _('%(actor)s followed %(item)s')) + NotificationAction.follow: (_('%(actor)s followed you'), _('%(actor)s followed %(item)s')), + NotificationAction.invite: (None, _('%(actor)s invited you to %(item)s')), } diff --git a/calsocial/templates/event-details.html b/calsocial/templates/event-details.html index 1854c20..b445f5a 100644 --- a/calsocial/templates/event-details.html +++ b/calsocial/templates/event-details.html @@ -11,4 +11,22 @@ {{ event.description }} +
+

{% trans %}Invited users{% endtrans %}

+
    +{% for invitation in event.invitations %} +
  • {{ invitation.invitee }}
  • +{% endfor %} +
+
+

{% trans %}Invite{% endtrans %}

+
+ {{ form.hidden_tag() }} + + {{ form.invitee.errors }} + {{ form.invitee.label }} + {{ form.invitee}} + + +
{% endblock %}