forms.py 8.45 KB
Newer Older
1
2
3
# Future Imports
from __future__ import unicode_literals, absolute_import, print_function, division

4
# Django Imports
5
from django import forms
6
from django.core.exceptions import ValidationError
7
from django.utils.safestring import mark_safe
Matthew Rodgers's avatar
Matthew Rodgers committed
8
from django.utils import timezone
9
10
11
12
13

# App Imports
from go.models import URL, RegisteredUser

# Other Imports
David Haynes's avatar
David Haynes committed
14
from crispy_forms.helper import FormHelper
15
16
from crispy_forms.layout import Layout, Fieldset, Submit, HTML, Div, Field
from crispy_forms.bootstrap import StrictButton, PrependedText, Accordion, AccordionGroup
17
from bootstrap3_datetime.widgets import DateTimePicker
18
from datetime import date, datetime, timedelta
19

David Haynes's avatar
David Haynes committed
20
21
22
"""
    The form that is used in URL creation.
"""
23
class URLForm(forms.ModelForm):
24

25
26
    # Prevent redirect loop links
    def clean_target(self):
David Haynes's avatar
David Haynes committed
27
        # get the entered target link
28
        target = self.cleaned_data.get('target')
David Haynes's avatar
David Haynes committed
29
        # if the host (go.gmu.edu) is in the entered target link
30
31
32
33
34
        if self.host in target:
            raise ValidationError("You can't make a Go link to Go silly!")
        else:
            return target

35
36
37
    # Custom target URL field
    target = forms.URLField(
        required=True,
38
        label='Long URL (Required)',
39
40
        max_length=1000,
        widget=forms.URLInput(attrs={
41
            'placeholder': 'https://yoursite.com/'
42
43
44
45
46
47
        })
    )

    # Check to make sure the short url has not been used
    def unique_short(value):
        try:
David Haynes's avatar
David Haynes committed
48
            # if we're able to get a URL with the same short url
49
50
51
            URL.objects.get(short__iexact=value)
        except URL.DoesNotExist:
            return
David Haynes's avatar
David Haynes committed
52
        # then raise a ValidationError
53
54
55
56
        raise ValidationError('Short url already exists.')

    # Custom short-url field with validators.
    short = forms.SlugField(
David Haynes's avatar
David Haynes committed
57
58
59
60
61
62
        required = False,
        label = 'Short URL (Optional)',
        widget = forms.TextInput(),
        validators = [unique_short],
        max_length = 20,
        min_length = 3,
63
64
    )

David Haynes's avatar
David Haynes committed
65
    # define some string date standards
66
67
68
    DAY = '1 Day'
    WEEK = '1 Week'
    MONTH = '1 Month'
69
    CUSTOM = 'Custom Date'
70
71
    NEVER = 'Never'

David Haynes's avatar
David Haynes committed
72
    # define a tuple of string date standards to be used as our date choices
73
74
75
76
77
    EXPIRATION_CHOICES = (
        (DAY, DAY),
        (WEEK, WEEK),
        (MONTH, MONTH),
        (NEVER, NEVER),
78
        (CUSTOM, CUSTOM),
79
80
    )

Matthew Rodgers's avatar
Matthew Rodgers committed
81
    # Add preset expiration choices.
82
    expires = forms.ChoiceField(
David Haynes's avatar
David Haynes committed
83
84
85
86
87
        required = True,
        label = 'Expiration (Required)',
        choices = EXPIRATION_CHOICES,
        initial = NEVER,
        widget = forms.RadioSelect(),
88
89
    )

David Haynes's avatar
David Haynes committed
90
    # Check if the selected date is a valid date
Matthew Rodgers's avatar
Matthew Rodgers committed
91
    def valid_date(value):
David Haynes's avatar
David Haynes committed
92
        # a valid date is one that is greater than today
Matthew Rodgers's avatar
Matthew Rodgers committed
93
94
        if value > timezone.now():
            return
David Haynes's avatar
David Haynes committed
95
        # raise a ValidationError if the date is invalid
Matthew Rodgers's avatar
Matthew Rodgers committed
96
        else:
97
            raise ValidationError('Date must be after today.')
Matthew Rodgers's avatar
Matthew Rodgers committed
98
99


Matthew Rodgers's avatar
Matthew Rodgers committed
100
    # Add a custom expiration choice.
101
    expires_custom = forms.DateTimeField(
Matthew Rodgers's avatar
Matthew Rodgers committed
102
        required = False,
David Haynes's avatar
David Haynes committed
103
104
105
106
107
        label = 'Custom Date',
        input_formats = ['%m-%d-%Y'],
        validators = [valid_date],
        initial = lambda: datetime.now() + timedelta(days=1),
        widget = DateTimePicker(
108
109
110
111
112
113
            options={
                "format": "MM-DD-YYYY",
                "pickTime": False,
            },
            icon_attrs={
                "class": "fa fa-calendar",
David Haynes's avatar
David Haynes committed
114
115
            },
        )
116
117
    )

David Haynes's avatar
David Haynes committed
118
    # on initialization of the form, crispy forms renders this layout
119
    def __init__(self, *args, **kwargs):
120
121
        # Grab that host info
        self.host = kwargs.pop('host', None)
122
        super(URLForm, self).__init__(*args, **kwargs)
123
        # Define the basics for crispy-forms
124
        self.helper = FormHelper()
125
        self.helper.form_method = 'POST'
126

127
        # Some xtra vars for form css purposes
128
129
130
131
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-md-1'
        self.helper.field_class = 'col-md-6'

132
        # The main "layout" defined
133
        self.helper.layout = Layout(
134
135
            Fieldset('',
            #######################
136
                Accordion(
137
                    # Step 1: Long URL
138
139
140
141
                    AccordionGroup('Step 1: Long URL',
                        Div(
                            HTML("""
                                <h4>Paste the URL you would like to shorten:</h4>
142
                                <br />"""),
143
                            'target',
144
                            style="background: rgb(#F6F6F6);"),
145
                        active=True,
146
147
148
                        template='crispy/accordian-group.html'),

                    # Step 2: Short URL
149
150
151
152
                    AccordionGroup('Step 2: Short URL',
                        Div(
                            HTML("""
                                <h4>Create a custom Go address:</h4>
153
154
                                <br />"""),
                            PrependedText(
155
                            'short', 'https://go.gmu.edu/', template='crispy/customPrepended.html'),
156
                            style="background: rgb(#F6F6F6);"),
157
                        active=True,
158
159
160
                        template='crispy/accordian-group.html',),

                    # Step 3: Expiration
161
162
163
164
                    AccordionGroup('Step 3: URL Expiration',
                        Div(
                            HTML("""
                                <h4>Set when you would like your Go address to expire:</h4>
165
                                <br />"""),
166
                            'expires',
167
                            Field('expires_custom', template="crispy/customDateField.html"),
168
                            style="background: rgb(#F6F6F6);"),
169
                        active=True,
170
                        template='crispy/accordian-group.html'),
171

172
173
174
175
176
177
                    # FIN
                    template='crispy/accordian.html'),
            #######################
            HTML("""
                <br />"""),
            StrictButton('Shorten', css_class="btn btn-primary btn-md col-md-4", type='submit')))
178

David Haynes's avatar
David Haynes committed
179
    # metadata about this ModelForm
180
    class Meta:
David Haynes's avatar
David Haynes committed
181
        # what model this form is for
182
        model = URL
David Haynes's avatar
David Haynes committed
183
184
        # what attributes are included
        fields = ['target',]
185

David Haynes's avatar
David Haynes committed
186
187
188
"""
    The form that is used when a user is signing up to be a RegisteredUser
"""
189
class SignupForm(forms.ModelForm):
190

David Haynes's avatar
David Haynes committed
191
    # The full name of the RegisteredUser
192
    full_name = forms.CharField(
David Haynes's avatar
David Haynes committed
193
194
195
196
        required = True,
        label = 'Full Name (Required)',
        max_length = 100,
        widget = forms.TextInput(),
197
    )
David Haynes's avatar
David Haynes committed
198
199

    # The RegisteredUser's chosen organization
200
    organization = forms.CharField(
David Haynes's avatar
David Haynes committed
201
202
203
204
        required = True,
        label = 'Organization (Required)',
        max_length = 100,
        widget = forms.TextInput(),
205
    )
David Haynes's avatar
David Haynes committed
206
207

    # The RegisteredUser's reason for signing up to us Go
208
    description = forms.CharField(
David Haynes's avatar
David Haynes committed
209
210
211
212
        required = False,
        label = 'Description (Optional)',
        max_length = 200,
        widget = forms.Textarea(),
213
    )
David Haynes's avatar
David Haynes committed
214

215
216
    # A user becomes registered when they agree to the TOS
    registered = forms.BooleanField(
217
        required=True,
218
219
        # ***Need to replace lower url with production URL*** ie. go.gmu.edu/about#terms
        label = mark_safe('Do you accept the <a href="http://127.0.0.1:8000/about#terms">Terms of Service</a>?'),
220
221
    )

David Haynes's avatar
David Haynes committed
222
    # on initialization of the form, crispy forms renders this layout
223
224
225
226
    def __init__(self, request, *args, **kwargs):
        # Necessary to call request in forms.py, is otherwise restricted to views.py and models.py
        self.request = request
        super(SignupForm, self).__init__(*args, **kwargs)
David Haynes's avatar
David Haynes committed
227
        self.helper = FormHelper()
228
229
230
231
232
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-md-4'
        self.helper.field_class = 'col-md-6'

        self.helper.layout = Layout(
233
            Fieldset('',
234
                Div(
235
                    # Place in form fields
236
237
238
239
                    Div(
                        'full_name',
                        'organization',
                        'description',
240
                        'registered',
241
242
243
                        css_class='well'),

                    # Extras at bottom
244
                    StrictButton('Submit',css_class='btn btn-primary btn-md col-md-4', type='submit'),
245
                    css_class='col-md-6')))
David Haynes's avatar
David Haynes committed
246
247

    # metadata about this ModelForm
248
    class Meta:
David Haynes's avatar
David Haynes committed
249
        # what model this form is for
250
        model = RegisteredUser
David Haynes's avatar
David Haynes committed
251
252
        # what attributes are included
        fields = ['full_name', 'organization', 'description', 'registered',]