diff --git a/events/forms.py b/events/forms.py index 14fcf26..52bb0d2 100644 --- a/events/forms.py +++ b/events/forms.py @@ -259,6 +259,12 @@ class NewTeamEventForm(forms.ModelForm): class DeleteEventForm(forms.Form): confirm = forms.BooleanField(label="Yes, delete event", required=True) +class EventInviteMemberForm(forms.Form): + member = forms.ChoiceField(label=_("")) + +class EventInviteEmailForm(forms.Form): + emails = MultiEmailField(label=_(""), widget=forms.widgets.Textarea) + class EventSeriesForm(forms.ModelForm): class Meta: model = EventSeries diff --git a/get_together/templates/get_together/emails/attendee_invite.html b/get_together/templates/get_together/emails/attendee_invite.html new file mode 100644 index 0000000..a4c23d1 --- /dev/null +++ b/get_together/templates/get_together/emails/attendee_invite.html @@ -0,0 +1,13 @@ +{% extends "get_together/emails/base.html" %} + +{% block content %} +

You've been invited to attend {{event.name|striptags}}

+ +

{{ sender }} has invited you to an event by {{team.name}}.

+ +

{{event.name|striptags}}

+

{{event.summary|striptags}}

+
+View this event. +

+{% endblock %} diff --git a/get_together/templates/get_together/emails/attendee_invite.txt b/get_together/templates/get_together/emails/attendee_invite.txt new file mode 100644 index 0000000..e14a1a3 --- /dev/null +++ b/get_together/templates/get_together/emails/attendee_invite.txt @@ -0,0 +1,11 @@ +{% block content %} +== You've been invited to attend {{event.name|striptags}} == + +{{ sender }} has invited you to an event by {{team.name}} + +=== {{event.name|striptags}} === +{{event.summary}} + +Click here to view this event: {{event.get_full_url}} + +{% endblock %} diff --git a/get_together/templates/get_together/events/invite_attendees.html b/get_together/templates/get_together/events/invite_attendees.html new file mode 100644 index 0000000..b0b26cb --- /dev/null +++ b/get_together/templates/get_together/events/invite_attendees.html @@ -0,0 +1,58 @@ +{% extends "get_together/base.html" %} +{% load markup tz %} + +{% block add_to_title %} | {{event.name}}{% endblock %} + +{% block content %} +
+

Invite people to {{ event.name }}

+
+ + {% if is_email_confirmed %} +
+
+

By email

+

Add a list of emails, separated by commas

+
+ {% csrf_token %} + {{ email_form.as_p }} + +
+
+ {% endif %} + + {% if can_edit_team %} +
+
+

Team members

+ {% if member_choice_count > 0 %} +

Select team member of members to invite

+
+ {% csrf_token %} + {{ team_form.as_p }} + +
+ {% else %} +
All invitable team members have responded.
+ {% endif %} +
+ {% endif %} + + {% if not can_edit_team and not is_email_confirmed %} +
+
You can not send invites for this event.
+
+ {% endif %} +
+
+{% endblock %} + +{% block javascript %} + +{% endblock %} \ No newline at end of file diff --git a/get_together/templates/get_together/events/show_event.html b/get_together/templates/get_together/events/show_event.html index be18c94..090179f 100644 --- a/get_together/templates/get_together/events/show_event.html +++ b/get_together/templates/get_together/events/show_event.html @@ -102,6 +102,9 @@

{{ event.name }}

Hosted by {{ team.name }}

+ {% if can_edit_team or is_email_confirmed %} + Invite + {% endif %} {% if settings.SOCIAL_AUTH_TWITTER_KEY %} Tweet {% endif %} @@ -121,7 +124,7 @@ {% endif %} diff --git a/get_together/urls.py b/get_together/urls.py index a032336..eea83ff 100644 --- a/get_together/urls.py +++ b/get_together/urls.py @@ -79,6 +79,7 @@ urlpatterns = [ path('team//+create-event/', views.create_event, name='create-event'), path('events//+edit/', views.edit_event, name='edit-event'), path('events//+attend/', event_views.attend_event, name='attend-event'), + path('events//+invite/', views.invite_attendees, name='invite-attendees'), path('events//+delete/', views.delete_event, name='delete-event'), path('events//+add_place/', views.add_place_to_event, name='add-place'), path('events//+comment/', event_views.comment_event, name='comment-event'), diff --git a/get_together/views/events.py b/get_together/views/events.py index 0a32c17..e7955e3 100644 --- a/get_together/views/events.py +++ b/get_together/views/events.py @@ -4,8 +4,11 @@ from django.contrib import messages from django.contrib.auth import logout as logout_user from django.contrib.auth.decorators import login_required from django.shortcuts import render, redirect, reverse, get_object_or_404 -from django.http import HttpResponse, JsonResponse +from django.contrib.sites.models import Site from django.utils import timezone +from django.core.mail import send_mail +from django.template.loader import get_template, render_to_string +from django.conf import settings from events.models.events import ( Event, @@ -28,7 +31,9 @@ from events.forms import ( EventCommentForm, NewPlaceForm, UploadEventPhotoForm, - NewCommonEventForm + NewCommonEventForm, + EventInviteEmailForm, + EventInviteMemberForm, ) from events import location @@ -68,6 +73,8 @@ def show_event(request, event_id, event_slug): 'presentation_list': event.presentations.filter(status=Presentation.ACCEPTED).order_by('start_time'), 'pending_presentations': event.presentations.filter(status=Presentation.PROPOSED).count(), 'can_edit_event': request.user.profile.can_edit_event(event), + 'can_edit_team': request.user.profile.can_edit_team(event.team), + 'is_email_confirmed': request.user.account.is_email_confirmed, } return render(request, 'get_together/events/show_event.html', context) @@ -136,6 +143,88 @@ def create_event(request, team_id): else: return redirect('home') + +@login_required +def invite_attendees(request, event_id): + event = get_object_or_404(Event, id=event_id) + attendee_userids = [attendee.user.id for attendee in Attendee.objects.filter(event=event)] + members = Member.objects.filter(team=event.team, ).order_by('user__realname') + member_choices = [(member.id, member.user) for member in members if member.user.user.account.is_email_confirmed and member.user.id not in attendee_userids] + default_choices = [('all', 'All Members (%s)' % len(member_choices))] + + if request.method == 'POST' and request.POST.get('form', None) == 'email': + email_form = EventInviteEmailForm(request.POST) + if email_form.is_valid(): + to = email_form.cleaned_data['emails'] + for email in to: + invite_attendee(email, event, request.user.profile) + messages.add_message(request, messages.SUCCESS, message=_('Sent %s invites' % len(to))) + return redirect(event.get_absolute_url()) + team_form = EventInviteMemberForm() + team_form.fields['member'].choices = default_choices + member_choices + elif request.method == 'POST' and request.POST.get('form', None) == 'team': + team_form = EventInviteMemberForm(request.POST) + team_form.fields['member'].choices = default_choices + member_choices + if team_form.is_valid(): + to = team_form.cleaned_data['member'] + if to == 'all': + for (member_id, user) in member_choices: + try: + attendee = Attendee.objects.get(event=event, user=user) + except: + # No attendee record found, so send the invite + invite_attendee(user.user.email, event, request.user.profile) + messages.add_message(request, messages.SUCCESS, message=_('Sent %s invites' % len(member_choices))) + return redirect(event.get_absolute_url()) + else: + member = get_object_or_404(Member, id=to) + try: + attendee = Attendee.objects.get(event=event, user=member.user) + except: + # No attendee record found, so send the invite + invite_attendee(member.user.user.email, event, request.user.profile) + messages.add_message(request, messages.SUCCESS, message=_('Invited %s' % member.user)) + return redirect(event.get_absolute_url()) + email_form = EventInviteEmailForm() + else: + email_form = EventInviteEmailForm() + team_form = EventInviteMemberForm() + team_form.fields['member'].choices = default_choices + member_choices + + context = { + 'event': event, + 'email_form': email_form, + 'team_form': team_form, + 'member_choice_count': len(member_choices), + 'can_edit_team': request.user.profile.can_edit_team(event.team), + 'is_email_confirmed': request.user.account.is_email_confirmed, + } + return render(request, 'get_together/events/invite_attendees.html', context) + + +def invite_attendee(email, event, sender): + context = { + 'sender': sender, + 'team': event.team, + 'event': event, + 'site': Site.objects.get(id=1), + } + email_subject = '[GetTogether] Invite to attend %s' % event.name + email_body_text = render_to_string('get_together/emails/attendee_invite.txt', context) + email_body_html = render_to_string('get_together/emails/attendee_invite.html', context) + email_recipients = [email] + email_from = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@gettogether.community') + + send_mail( + from_email=email_from, + html_message=email_body_html, + message=email_body_text, + recipient_list=email_recipients, + subject=email_subject, + fail_silently=True, + ) + + @login_required def add_event_photo(request, event_id): event = get_object_or_404(Event, id=event_id)