forms.py 8.35 KB
Newer Older
1
# Django Imports
2
from django import forms
3
from django.core.exceptions import ValidationError
4
from django.utils.safestring import mark_safe
Matthew Rodgers's avatar
Matthew Rodgers committed
5
from django.utils import timezone
6 7 8 9 10

# App Imports
from go.models import URL, RegisteredUser

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

212 213
    # A user becomes registered when they agree to the TOS
    registered = forms.BooleanField(
214
        required=True,
215 216
        # ***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>?'),
217 218
    )

David Haynes's avatar
David Haynes committed
219
    # on initialization of the form, crispy forms renders this layout
220 221 222 223
    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
224
        self.helper = FormHelper()
225 226 227 228 229
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-md-4'
        self.helper.field_class = 'col-md-6'

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

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

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