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

4
# Django Imports
5
from django.conf import settings
6
from django.http import HttpResponseServerError  # Http404
7
from django.http import HttpResponseRedirect
8
from django.utils import timezone
9
from django.core.exceptions import PermissionDenied  # ValidationError
10
from django.core.mail import send_mail, EmailMessage
11
from django.contrib.auth import REDIRECT_FIELD_NAME
David Haynes's avatar
David Haynes committed
12
from django.contrib.auth.models import User
13
from django.contrib.auth.decorators import user_passes_test, login_required
Jean Michel Rouly's avatar
Jean Michel Rouly committed
14
from django.shortcuts import render, get_object_or_404, redirect
15

16 17 18 19 20 21
# App Imports
from go.models import URL, RegisteredUser
from go.forms import URLForm, SignupForm

# Other Imports
from datetime import timedelta
Jean Michel Rouly's avatar
Jean Michel Rouly committed
22

David Haynes's avatar
David Haynes committed
23
"""
Jean Michel Rouly's avatar
Jean Michel Rouly committed
24 25 26 27 28
    This view handles the homepage that the user is presented with when
    they request '/'. If they're not logged in, they're redirected to
    login. If they're logged in but not registered, they're given the
    not_registered error page. If they are logged in AND registered, they
    get the URL registration form.
David Haynes's avatar
David Haynes committed
29 30
"""
def index(request):
31
    # If the user is blocked, redirect them to the blocked page.
32
    # If the user is not authenticated, show them a public landing page.
33
    if not request.user.is_authenticated():
Zosman's avatar
Zosman committed
34
        return render(request, 'public_landing.html')
David Haynes's avatar
David Haynes committed
35
    # If the user isn't approved, then display the you're not approved page.
36
    elif not request.user.registereduser.approved:
37
        if request.user.registereduser.blocked:
Zosman's avatar
Zosman committed
38
            return render(request, 'banned.html')
39
        else:
Zosman's avatar
Zosman committed
40
            return render(request, 'not_registered.html')
41

42

David Haynes's avatar
David Haynes committed
43
    # Initialize a URL form
44
    url_form = URLForm(host = request.META.get('HTTP_HOST'))  # unbound form
45

David Haynes's avatar
David Haynes committed
46 47
    # If a POST request is received, then the user has submitted a form and it's
    # time to parse the form and create a new URL object
48
    if request.method == 'POST':
David Haynes's avatar
David Haynes committed
49 50
        # Now we initialize the form again but this time we have the POST
        # request
51
        url_form = URLForm(request.POST, host = request.META.get('HTTP_HOST'))
David Haynes's avatar
David Haynes committed
52 53

        # Django will check the form to make sure it's valid
54 55
        if url_form.is_valid():

Jean Michel Rouly's avatar
Jean Michel Rouly committed
56 57
            # We don't commit the url object yet because we need to add its
            # owner, and parse its date field.
58
            url = url_form.save(commit = False)
59
            url.owner = request.user.registereduser
60

Jean Michel Rouly's avatar
Jean Michel Rouly committed
61
            # If the user entered a short url, it's already been validated,
Jean Michel Rouly's avatar
Jean Michel Rouly committed
62 63
            # so accept it. If they did not, however, then generate a
            # random one and use that instead.
64
            short = url_form.cleaned_data.get('short').strip()
David Haynes's avatar
David Haynes committed
65 66

            # Check if a short URL was entered
67 68 69
            if len(short) > 0:
                url.short = short
            else:
70 71 72 73 74 75
                # If the user didn't enter a short url, generate a random
                # one. However, if a random one can't be generated, return
                # a 500 server error.
                random_short = URL.generate_valid_short()
                if random_short is None:
                    return HttpResponseServerError(
David Haynes's avatar
David Haynes committed
76
                        render(request, 'admin/500.html', {})
77 78 79
                    )
                else:
                    url.short = random_short
80

Jean Michel Rouly's avatar
Jean Michel Rouly committed
81 82 83
            # Grab the expiration field value. It's currently an unsable
            # string value, so we need to parse it into a datetime object
            # relative to right now.
84
            expires = url_form.cleaned_data.get('expires')
85

David Haynes's avatar
David Haynes committed
86
            # Determine what the expiration date is
87 88 89 90 91 92
            if expires == URLForm.DAY:
                url.expires = timezone.now() + timedelta(days=1)
            elif expires == URLForm.WEEK:
                url.expires = timezone.now() + timedelta(weeks=1)
            elif expires == URLForm.MONTH:
                url.expires = timezone.now() + timedelta(weeks=3)
Matthew Rodgers's avatar
Matthew Rodgers committed
93 94
            elif expires == URLForm.CUSTOM:
                url.expires = url_form.cleaned_data.get('expires_custom')
95
            else:
96
                pass  # leave the field NULL
97

Jean Michel Rouly's avatar
Jean Michel Rouly committed
98 99
            # Make sure that our new URL object is clean, then save it and
            # let's redirect to view this baby.
100 101
            url.full_clean()
            url.save()
David Haynes's avatar
David Haynes committed
102

Jean Michel Rouly's avatar
Jean Michel Rouly committed
103
            return redirect('view', url.short)
104

David Haynes's avatar
David Haynes committed
105
    # Render index.html passing the form to the template
106
    return render(request, 'core/index.html', {
107
        'form': url_form,
Jean Michel Rouly's avatar
Jean Michel Rouly committed
108 109 110
    },
    )

David Haynes's avatar
David Haynes committed
111
"""
Jean Michel Rouly's avatar
Jean Michel Rouly committed
112 113
    This view allows the user to view details about a URL. Note that they
    do not need to be logged in to view info.
David Haynes's avatar
David Haynes committed
114 115
"""
def view(request, short):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
116

David Haynes's avatar
David Haynes committed
117
    # Get the current domain info
Nicholas Anderson's avatar
Nicholas Anderson committed
118
    domain = "%s://%s" % (request.scheme, request.META.get('HTTP_HOST')) + "/"
119

David Haynes's avatar
David Haynes committed
120
    # Get the URL that is being requested
121
    url = get_object_or_404(URL, short__iexact=short)
122

David Haynes's avatar
David Haynes committed
123
    # Render view.html passing the specified URL and Domain to the template
Jean Michel Rouly's avatar
Jean Michel Rouly committed
124
    return render(request, 'view.html', {
125
        'url': url,
126
        'domain': domain,
127 128 129
    },
    )

David Haynes's avatar
David Haynes committed
130
"""
Jean Michel Rouly's avatar
Jean Michel Rouly committed
131 132
    This view displays all the information about all of your URLs. You
    obviously need to be logged in to view your URLs.
David Haynes's avatar
David Haynes committed
133 134 135
"""
@login_required
def my_links(request):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
136

David Haynes's avatar
David Haynes committed
137
    # Do not display this page to unapproved users
138
    if not request.user.registereduser.approved:
139
        return render(request, 'not_registered.html')
Jean Michel Rouly's avatar
Jean Michel Rouly committed
140

David Haynes's avatar
David Haynes committed
141
    # Get the current domain info
142
    domain = "%s://%s" % (request.scheme, request.META.get('HTTP_HOST')) + "/"
143

David Haynes's avatar
David Haynes committed
144 145 146 147
    # Grab a list of all the URL's that are currently owned by the user
    urls = URL.objects.filter(owner=request.user.registereduser)

    # Render my_links.html passing the list of URL's and Domain to the template
148
    return render(request, 'my_links.html', {
149 150
        'urls': urls,
        'domain': domain,
151 152 153
    },
    )

Jean Michel Rouly's avatar
Jean Michel Rouly committed
154

David Haynes's avatar
David Haynes committed
155
"""
Jean Michel Rouly's avatar
Jean Michel Rouly committed
156 157
    This view deletes a URL if you have the permission to. User must be
    logged in and registered, and must also be the owner of the URL.
David Haynes's avatar
David Haynes committed
158 159 160
"""
@login_required
def delete(request, short):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
161

David Haynes's avatar
David Haynes committed
162
    # Do not allow unapproved users to delete links
163
    if not request.user.registereduser.approved:
164
        return render(request, 'not_registered.html')
Jean Michel Rouly's avatar
Jean Michel Rouly committed
165

David Haynes's avatar
David Haynes committed
166
    # Get the URL that is going to be deleted
167
    url = get_object_or_404(URL, short__iexact=short)
David Haynes's avatar
David Haynes committed
168 169

    # If the RegisteredUser is the owner of the URL
170
    if url.owner == request.user.registereduser:
David Haynes's avatar
David Haynes committed
171
        # remove the URL
172
        url.delete()
David Haynes's avatar
David Haynes committed
173
        # rediret to my_links
174 175
        return redirect('my_links')
    else:
David Haynes's avatar
David Haynes committed
176
        # do not allow them to delete
177
        raise PermissionDenied()
178

David Haynes's avatar
David Haynes committed
179 180 181
"""
    This view presents the user with a registration form. You can register yourself.
"""
182
@login_required
Jean Michel Rouly's avatar
Jean Michel Rouly committed
183
def signup(request):
184
    # Do not display signup page to registered or approved users
185
    if request.user.registereduser.blocked:
186
        return render(request, 'banned.html')
187
    elif request.user.registereduser.approved:
David Haynes's avatar
David Haynes committed
188
        return redirect('/')
189
    elif request.user.registereduser.registered:
David Haynes's avatar
David Haynes committed
190
        return redirect('registered')
191

David Haynes's avatar
David Haynes committed
192
    # Initialize our signup form
193 194
    signup_form = SignupForm(request,
        initial={'full_name': request.user.first_name + " " + request.user.last_name})
David Haynes's avatar
David Haynes committed
195 196

    # Set the full_name field to readonly since CAS will fill that in for them
197
    signup_form.fields['full_name'].widget.attrs['readonly'] = 'readonly'
Jean Michel Rouly's avatar
Jean Michel Rouly committed
198

David Haynes's avatar
David Haynes committed
199 200
    # If a POST request is received, then the user has submitted a form and it's
    # time to parse the form and create a new RegisteredUser
Jean Michel Rouly's avatar
Jean Michel Rouly committed
201
    if request.method == 'POST':
David Haynes's avatar
David Haynes committed
202 203
        # Now we initialize the form again but this time we have the POST
        # request
204 205
        signup_form = SignupForm(request, request.POST, instance=request.user.registereduser,
            initial={'full_name': request.user.first_name + " " + request.user.last_name})
David Haynes's avatar
David Haynes committed
206 207

        # set the readonly flag again for good measure
208
        signup_form.fields['full_name'].widget.attrs['readonly'] = 'readonly'
209

David Haynes's avatar
David Haynes committed
210
        # Django will check the form to make sure it's valid
211
        if signup_form.is_valid():
David Haynes's avatar
David Haynes committed
212
            # Grab data from the form and store into variables
213
            description = signup_form.cleaned_data.get('description')
214
            full_name = signup_form.cleaned_data.get('full_name')
215
            organization = signup_form.cleaned_data.get('organization')
216
            registered = signup_form.cleaned_data.get('registered')
217

218 219
            # Only send mail if we've defined the mailserver
            if settings.EMAIL_HOST and settings.EMAIL_PORT:
root's avatar
root committed
220
                user_mail = request.user.username + settings.EMAIL_DOMAIN
221
                # Email sent to notify Admins
222
                to_admin = EmailMessage(
223
                    'Signup from %s' % (request.user.registereduser.user),
224 225 226 227 228
                    ######################
                    '%s signed up at %s\n\n'
                    'Username: %s\n'
                    'Organization: %s\n\n'
                    'Message: %s\n\n'
229 230
                    'You can contact the user directly by replying to this email or '
                    'reply all to contact the user and notfiy the mailing list.\n'
231 232 233
                    'Please head to go.gmu.edu/useradmin to approve or '
                    'deny this application.'
                    % (str(full_name), str(timezone.now()).strip(),
234
                    str(request.user.registereduser.user), str(organization), str(description)),
235 236
                    ######################
                    settings.EMAIL_FROM,
237 238
                    [settings.EMAIL_TO],
                    reply_to=[user_mail]
239
                ).send()
240
                # Confirmation email sent to Users
241
                send_mail(
242 243 244 245 246 247 248 249 250 251 252 253 254
                    'We have received your Go application!',
                    ######################
                    'Hey there %s,\n\n'
                    'The Go admins have received your application and are '
                    'currently in the process of reviewing it.\n\n'
                    'You will receive another email when you have been '
                    'approved.\n\n'
                    '- Go Admins'
                    % (str(full_name)),
                    ######################
                    settings.EMAIL_FROM,
                    [user_mail]
                )
255

David Haynes's avatar
David Haynes committed
256 257
            # Make sure that our new RegisteredUser object is clean, then save
            # it and let's redirect to tell the user they have registered.
258
            signup_form.save()
259
            return redirect('registered')
Jean Michel Rouly's avatar
Jean Michel Rouly committed
260

David Haynes's avatar
David Haynes committed
261 262
    # render signup.html passing along the form and the current registered
    # status
263
    return render(request, 'core/signup.html', {
264
        'form': signup_form,
265
        'registered': False,
Jean Michel Rouly's avatar
Jean Michel Rouly committed
266 267
    },
    )
Jean Michel Rouly's avatar
Jean Michel Rouly committed
268

David Haynes's avatar
David Haynes committed
269
"""
Jean Michel Rouly's avatar
Jean Michel Rouly committed
270
    This view redirects a user based on the short URL they requested.
David Haynes's avatar
David Haynes committed
271 272
"""
def redirection(request, short):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
273

David Haynes's avatar
David Haynes committed
274 275
    # Get the current domain info
    domain = "%s://%s" % (request.scheme, request.META.get('HTTP_HOST')) + "/"
Jean Michel Rouly's avatar
Jean Michel Rouly committed
276

David Haynes's avatar
David Haynes committed
277
    # Get the URL object that relates to the requested Go link
278
    url = get_object_or_404(URL, short__iexact=short)
David Haynes's avatar
David Haynes committed
279 280
    # Increment our clicks by one
    url.clicks += 1
281

David Haynes's avatar
David Haynes committed
282
    # If the user is trying to make a Go link to itself, we 404 them
283
    if url.target == domain + short:
David Haynes's avatar
David Haynes committed
284
        return redirect('admin/404.html')
285

David Haynes's avatar
David Haynes committed
286
    # If the user is coming from a QR request then increment qrclicks
287 288 289
    if 'qr' in request.GET:
        url.qrclicks += 1

David Haynes's avatar
David Haynes committed
290
    # If the user is coming from a social media request then increment qrclicks
291 292 293
    if 'social' in request.GET:
        url.socialclicks += 1

David Haynes's avatar
David Haynes committed
294
    # Save our data and redirect the user towards thier destination
Jean Michel Rouly's avatar
Jean Michel Rouly committed
295
    url.save()
296
    return redirect(url.target)
Jean Michel Rouly's avatar
Jean Michel Rouly committed
297

298 299 300 301
"""
    Decorator function for views that checks that the user is logged in and is
    a staff member, displaying the login page if necessary.
"""
302
def staff_member_required(view_func, redirect_field_name=REDIRECT_FIELD_NAME, login_url='/'):
303 304 305 306 307 308
    return user_passes_test(
        lambda u: u.is_active and u.is_staff,
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )(view_func)

David Haynes's avatar
David Haynes committed
309
"""
310 311
    This view is a simplified admin panel, so that staff don't need to log in
    to approve links
David Haynes's avatar
David Haynes committed
312 313 314 315 316
"""
@staff_member_required
def useradmin(request):

    # If we receive a POST request
317
    if request.POST:
David Haynes's avatar
David Haynes committed
318
        # Get a list of the potential victims (users)
319
        userlist = request.POST.getlist('username')
David Haynes's avatar
David Haynes committed
320
        # If we're approving users
321
        if '_approve' in request.POST:
322
            for name in userlist:
323 324 325
                toApprove = RegisteredUser.objects.get(user__username__exact=name)
                toApprove.approved = True
                toApprove.save()
David Haynes's avatar
David Haynes committed
326 327

                # Send an email letting them know they are approved
328
                if settings.EMAIL_HOST and settings.EMAIL_PORT:
329
                    user_mail = toApprove.user.username + settings.EMAIL_DOMAIN
330 331 332 333 334 335 336 337
                    send_mail(
                        'Your Account has been Approved!',
                        ######################
                        'Hey there %s,\n\n'
                        'The Go admins have reviewed your application and have '
                        'approved you to use Go!\n\n'
                        'Head over to go.gmu.edu to create your first address.\n\n'
                        '- Go Admins'
338
                        % (str(toApprove.full_name)),
339 340 341 342
                        ######################
                        settings.EMAIL_FROM,
                        [user_mail]
                    )
David Haynes's avatar
David Haynes committed
343
        # If we're denying users
344
        elif '_deny' in request.POST:
345
            for name in userlist:
346
                toDeny = RegisteredUser.objects.get(user__username__exact=name)
347
                if settings.EMAIL_HOST and settings.EMAIL_PORT:
348
                    user_mail = toDeny.user.username + settings.EMAIL_DOMAIN
David Haynes's avatar
David Haynes committed
349 350

                    # Send an email letting them know they are denied
351 352 353 354 355 356 357 358 359
                    send_mail(
                        'Your Account has been Denied!',
                        ######################
                        'Hey there %s,\n\n'
                        'The Go admins have reviewed your application and have '
                        'decided to not approve you to use Go.\n\n'
                        'Please reach out to srct@gmu.edu to appeal '
                        'this decision.\n\n'
                        '- Go Admins'
360
                        % (str(toDeny.full_name)),
361 362 363 364
                        ######################
                        settings.EMAIL_FROM,
                        [user_mail]
                    )
David Haynes's avatar
David Haynes committed
365
                # Delete their associated RegisteredUsers
366
                toDeny.user.delete()
367
                return HttpResponseRedirect('useradmin')
368
        # If we're blocking users
Zosman's avatar
draft 1  
Zosman committed
369 370
        elif '_block' in request.POST:
            for name in userlist:
371
                toBlock = RegisteredUser.objects.get(user__username__exact=name)
Zosman's avatar
draft 1  
Zosman committed
372
                if settings.EMAIL_HOST and settings.EMAIL_PORT:
373
                    user_mail = toBlock.user.username + settings.EMAIL_DOMAIN
Zosman's avatar
draft 1  
Zosman committed
374 375 376 377 378 379 380 381 382
                    send_mail(
                        'Your Account has been Blocked!',
                        ######################
                        'Hey there %s,\n\n'
                        'The Go admins have reviewed your application and have '
                        'blocked you from using Go.\n\n'
                        'Please reach out to srct@gmu.edu to appeal '
                        'this decision.\n\n'
                        '- Go Admins'
383
                        % (str(toBlock.full_name)),
Zosman's avatar
draft 1  
Zosman committed
384 385 386 387
                        ######################
                        settings.EMAIL_FROM,
                        [user_mail]
                    )
388 389 390 391 392
                # toBlock.user.delete()
                toBlock.blocked = True
                toBlock.approved = False
                toBlock.registered = False
                toBlock.save()
393
        # If we're un-blocking users
394 395
        elif '_unblock' in request.POST:
            for name in userlist:
396
                toUnBlock = RegisteredUser.objects.get(user__username__exact=name)
397
                if settings.EMAIL_HOST and settings.EMAIL_PORT:
398
                    user_mail = toUnBlock.user.username + settings.EMAIL_DOMAIN
399
                    send_mail(
400
                        'Your Account has been Un-Blocked!',
401 402 403
                        ######################
                        'Hey there %s,\n\n'
                        'The Go admins have reviewed your application and have '
404
                        'Un-Blocked you from using Go.\n\n'
405
                        'If you wish to continue Go use please register again. \n\n'
406 407
                        'Congratulations! '
                        '- Go Admins'
408
                        % (str(toUnBlock.full_name)),
409 410 411 412
                        ######################
                        settings.EMAIL_FROM,
                        [user_mail]
                    )
413
                # toUNblock.user.delete()
414 415
                toUnBlock.blocked = False
                toUnBlock.save()
416
                return HttpResponseRedirect('useradmin')
417

418
        # If we're removing existing users
419 420
        elif '_remove' in request.POST:
            for name in userlist:
421
                toRemove = RegisteredUser.objects.get(user__username__exact=name)
422
                if settings.EMAIL_HOST and settings.EMAIL_PORT:
423
                    user_mail = toRemove.user.username + settings.EMAIL_DOMAIN
424 425 426 427 428 429 430 431
                    send_mail(
                        'Your Account has been Deleted!',
                        ######################
                        'Hey there %s,\n\n'
                        'The Go admins have decided to remove you from Go. \n\n'
                        'Please reach out to srct@gmu.edu to appeal '
                        'this decision.\n\n'
                        '- Go Admins'
432
                        % (str(toRemove.full_name)),
433 434 435 436
                        ######################
                        settings.EMAIL_FROM,
                        [user_mail]
                    )
437
                toRemove.user.delete()
438
                return HttpResponseRedirect('useradmin')
439
    # Get a list of all RegisteredUsers that need to be approved
440
    need_approval = RegisteredUser.objects.filter(registered=True).filter(approved=False)
441

442
    current_users = RegisteredUser.objects.filter(approved=True).filter(registered=True).filter(blocked=False)
443
    blocked_users = RegisteredUser.objects.filter(blocked=True)
444

David Haynes's avatar
David Haynes committed
445
    # Pass that list to the template
446
    return render(request, 'admin/useradmin.html', {
447 448 449
        'need_approval': need_approval,
        'current_users': current_users,
        'blocked_users': blocked_users
450 451
    },
    )