summaryrefslogtreecommitdiff
path: root/postgresqleu/membership/backendforms.py
blob: 6a67cc6a44888f810e33a67810598d828c04090f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import django.forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils import timezone

from collections import OrderedDict
from datetime import timedelta

from postgresqleu.util.time import time_sinceoruntil, datetime_string
from postgresqleu.util.widgets import StaticTextWidget, EmailTextWidget
from postgresqleu.util.backendforms import BackendForm
from postgresqleu.membership.models import Member, MemberLog, Meeting, MembershipConfiguration
from postgresqleu.membership.models import MeetingType, MeetingReminder
from postgresqleu.membership.backendlookups import MemberLookup


class BackendConfigForm(BackendForm):
    helplink = 'membership'

    class Meta:
        model = MembershipConfiguration
        fields = ['sender_email', 'sender_name', 'membership_years', 'membership_cost', 'country_validator',
                  'paymentmethods', ]
        widgets = {
            'paymentmethods': django.forms.CheckboxSelectMultiple,
        }

    def fix_fields(self):
        self.fields['paymentmethods'].label_from_instance = lambda x: "{0}{1}".format(x.internaldescription, x.active and " " or " (INACTIVE)")
        self.fields['membership_cost'].help_text = "Membership cost in {0}".format(settings.CURRENCY_SYMBOL)


class MemberLogManager(object):
    title = "Log"
    singular = "log"
    can_add = False

    def get_list(self, instance):
        if instance.pk:
            return [(None, line.timestamp, line.message) for line in MemberLog.objects.filter(member=instance).order_by('-timestamp')]


class BackendMemberForm(BackendForm):
    helplink = 'membership'
    list_fields = ['fullname', 'user', 'paiduntil']
    queryset_select_related = ['user', ]
    defaultsort = [['paiduntil', 'desc'], ['fullname', 'asc']]
    allow_email = True

    class Meta:
        model = Member
        fields = ['fullname', 'country', 'listed', 'country_exception',
                  'membersince', 'paiduntil', 'expiry_warning_sent', ]

    fieldsets = [
        {'id': 'user_info', 'Legend': 'User information', 'fields': ['fullname', 'country', 'listed', ]},
        {'id': 'admin_info', 'Legend': 'Administrative', 'fields': ['country_exception', ]},
        {'id': 'date_info', 'Legend': 'Date info', 'fields': ['membersince', 'paiduntil', 'expiry_warning_sent', ]},
    ]
    readonly_fields = ['membersince', 'paiduntil', 'expiry_warning_sent', ]

    linked_objects = OrderedDict({
        'log': MemberLogManager(),
    })

    @classmethod
    def get_column_filters(cls, conference):
        return {
            'Paid until': [],  # Empty list triggers the option to choose empty/not empty
        }


class BackendMeetingReminderForm(BackendForm):
    helplink = 'meetings'
    list_fields = ['sendat', 'sentat', ]
    readonly_fields = ['sentat', ]

    class Meta:
        model = MeetingReminder
        fields = ['sendat', 'sentat', ]

    def clean_sendat(self):
        if self.cleaned_data.get('sendat', None):
            if self.cleaned_data.get('sendat') > self.instance.meeting.dateandtime - timedelta(minutes=30):
                raise ValidationError("Reminder must be set at least 30 minutes before the meeting starts!")
            if self.cleaned_data.get('sendat') < timezone.now():
                raise ValidationError("This timestamp is in the past!")
        return self.cleaned_data.get('sendat', None)

    def clean(self):
        d = super().clean()
        if self.instance.sentat:
            raise ValidationError("Cannot edit a reminder that has already been sent")
        return d


class MeetingReminderManager(object):
    title = 'Reminders'
    singular = 'Reminder'
    can_add = True

    def get_list(self, instance):
        if instance.id:
            return [
                (r.id, "{} ({})".format(datetime_string(r.sendat),
                                        time_sinceoruntil(r.sendat)),
                 r.sentat is not None
                 ) for r in MeetingReminder.objects.filter(meeting=instance)]

    def get_form(self, obj, POST):
        return BackendMeetingReminderForm

    def get_object(self, masterobj, subid):
        return MeetingReminder.objects.get(meeting=masterobj, pk=subid)

    def get_instancemaker(self, masterobj):
        return lambda: MeetingReminder(meeting=masterobj)


class BackendMeetingForm(BackendForm):
    helplink = 'meetings'
    list_fields = ['name', 'dateandtime', 'meetingtype', 'state']
    linked_objects = OrderedDict({
        'reminders': MeetingReminderManager(),
    })
    extrabuttons = [
        ('View meeting log', 'log/'),
        ('View attendees', 'attendees/'),
    ]

    class Meta:
        model = Meeting
        fields = ['name', 'dateandtime', 'allmembers', 'members', 'meetingtype', 'meetingadmins', 'botname', ]

    fieldsets = [
        {'id': 'meeting_info', 'legend': 'Meeting information', 'fields': ['name', 'dateandtime', 'allmembers', 'members']},
        {'id': 'meeting_impl', 'legend': 'Meeting implementation', 'fields': ['meetingtype', 'meetingadmins', 'botname']},
    ]

    selectize_multiple_fields = {
        'members': MemberLookup(),
        'meetingadmins': MemberLookup(),
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Remove extra buttons unless we're in a web meeting and this web meeting has started
        if self.instance:
            if self.instance.meetingtype != MeetingType.WEB or self.instance.state == 0:
                self.extrabuttons = []
        else:
            self.extrabuttons = []

    def clean(self):
        d = super().clean()
        if d.get('meetingtype', None) == MeetingType.WEB:
            if d['botname']:
                self.add_error('botname', 'Bot name should not be specified for web meetings')
            if not d['meetingadmins']:
                self.add_error('meetingadmins', 'Meeting administrator(s) must be specified for web meetings')
        elif d.get('meetingtype', None) == MeetingType.IRC:
            if not d['botname']:
                self.add_error('botname', 'Bot name must be specified for IRC meetings')
            if d['meetingadmins']:
                self.add_error('meetingadmins', 'Meeting administrator(s) cannot be specified for IRC meetings')
        return d

    def clean_meetingtype(self):
        if self.cleaned_data.get('meetingtype', None) == MeetingType.WEB and not settings.MEETINGS_WS_BASE_URL:
            raise ValidationError("Web meetings server is not configured in local_settings.py")

        if self.instance and self.instance.state > 0 and self.instance.meetingtype != self.cleaned_data['meetingtype']:
            raise ValidationError("Cannot change the type of a meeting that has already started")

        return self.cleaned_data.get('meetingtype', None)


class BackendMemberSendEmailForm(django.forms.Form):
    helplink = 'membership'
    _from = django.forms.CharField(max_length=128, disabled=True, label="From")
    subject = django.forms.CharField(max_length=128, required=True)
    recipients = django.forms.Field(widget=StaticTextWidget, required=False)
    message = django.forms.CharField(widget=EmailTextWidget, required=True)
    idlist = django.forms.CharField(widget=django.forms.HiddenInput, required=True)
    confirm = django.forms.BooleanField(label="Confirm", required=False)

    def __init__(self, *args, **kwargs):
        super(BackendMemberSendEmailForm, self).__init__(*args, **kwargs)
        if not (self.data.get('subject') and self.data.get('message')):
            del self.fields['confirm']

    def clean_confirm(self):
        if not self.cleaned_data['confirm']:
            raise ValidationError("Please check this box to confirm that you are really sending this email! There is no going back!")