views.py 11.1 KB
Newer Older
1
from go.models import URL, RegisteredUser
David Haynes's avatar
David Haynes committed
2
from go.forms import URLForm, SignupForm, ExampleForm
3
from datetime import timedelta
4
from django.conf import settings
5
from django.http import HttpResponseServerError  # Http404
6
from django.utils import timezone
7
8
# from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied  # ValidationError
9
from django.core.mail import send_mail
10
11
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import user_passes_test, login_required
Jean Michel Rouly's avatar
Jean Michel Rouly committed
12
from django.shortcuts import render, get_object_or_404, redirect
13
# import os
14

Jean Michel Rouly's avatar
Jean Michel Rouly committed
15
16
17
18
19
20
21

##############################################################################
"""
Define useful helper methods here.
"""


22
def is_approved(user):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
23
24
    """
    This function checks if a user account has a corresponding RegisteredUser,
25
    thus checking if the user is approved.
Jean Michel Rouly's avatar
Jean Michel Rouly committed
26
27
    """

28
    try:
29
        registered = RegisteredUser.objects.get(username=user.username)
30
        return registered.approved
31
32
33
    except RegisteredUser.DoesNotExist:
        return False

Jean Michel Rouly's avatar
Jean Michel Rouly committed
34

35
36
37
38
39
40
41
def is_registered(user):
    """
    This function checks if a user account has a corresponding RegisteredUser,
    thus checking if the user is registered.
    """

    try:
42
        registered = RegisteredUser.objects.get(username=user.username)
43
44
45
46
47
        return True
    except RegisteredUser.DoesNotExist:
        return False


Jean Michel Rouly's avatar
Jean Michel Rouly committed
48
49
50
51
52
53
##############################################################################
"""
Define error page handling here.
"""


54
def error_404(request):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
55
56
57
58
    """
    Error 404 view, in case a url is not found.
    """

59
    return render(request, '404.html', {
60
61
62
    },
    )

63

64
def error_500(request):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
65
66
67
68
    """
    Error 500 view, in case a server error occurs.
    """

69
    return render(request, '500.html', {
70
71
    },
    )
David Haynes's avatar
David Haynes committed
72
73
74
75
76
77
78
79
80
81
def test(request):
    """
    Testing page, pls ignore.
    """
    url_form = ExampleForm()
    if request.method == 'POST':
        url_form = URLForm(request.POST)  # bind dat form
    return render(request, 'test.html', {
        'form': url_form,
    },)
82

Jean Michel Rouly's avatar
Jean Michel Rouly committed
83
84
85
86
87
88
##############################################################################
"""
Define user views here.
"""


Jean Michel Rouly's avatar
Jean Michel Rouly committed
89
def index(request):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
90
91
92
93
94
95
96
    """
    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.
    """
Jean Michel Rouly's avatar
Jean Michel Rouly committed
97

98
99
100
101
    # If the user is not authenticated, show them a public landing page.
    if not request.user.is_authenticated():
        return render(request, 'public_landing.html')

Jean Michel Rouly's avatar
Jean Michel Rouly committed
102
    # If the user isn't registered, don't give them any leeway.
103
    if not is_approved(request.user):
104
105
        return render(request, 'not_registered.html')

106
    url_form = URLForm()  # unbound form
107
108

    if request.method == 'POST':
109
        url_form = URLForm(request.POST)  # bind dat form
110
111
        if url_form.is_valid():

Jean Michel Rouly's avatar
Jean Michel Rouly committed
112
113
            # We don't commit the url object yet because we need to add its
            # owner, and parse its date field.
114
115
116
            url = url_form.save(commit=False)
            url.owner = request.user

Jean Michel Rouly's avatar
Jean Michel Rouly committed
117
            # If the user entered a short url, it's already been validated,
Jean Michel Rouly's avatar
Jean Michel Rouly committed
118
119
            # so accept it. If they did not, however, then generate a
            # random one and use that instead.
120
            short = url_form.cleaned_data.get('short').strip()
121
122
123
            if len(short) > 0:
                url.short = short
            else:
124
125
126
127
128
129
                # 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(
130
                        render(request, '500.html', {})
131
132
133
                    )
                else:
                    url.short = random_short
134

Jean Michel Rouly's avatar
Jean Michel Rouly committed
135
136
137
            # 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.
138
            expires = url_form.cleaned_data.get('expires')
139
140
141
142
143
144
145
146

            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)
            else:
147
                pass  # leave the field NULL
148

Jean Michel Rouly's avatar
Jean Michel Rouly committed
149
150
            # Make sure that our new URL object is clean, then save it and
            # let's redirect to view this baby.
151
152
            url.full_clean()
            url.save()
Jean Michel Rouly's avatar
Jean Michel Rouly committed
153
            return redirect('view', url.short)
154

155
    return render(request, 'core/index.html', {
156
        'form': url_form,
Jean Michel Rouly's avatar
Jean Michel Rouly committed
157
158
159
    },
    )

Jean Michel Rouly's avatar
Jean Michel Rouly committed
160

Jean Michel Rouly's avatar
Jean Michel Rouly committed
161
def view(request, short):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
162
163
164
165
166
    """
    This view allows the user to view details about a URL. Note that they
    do not need to be logged in to view info.
    """

Jean Michel Rouly's avatar
Jean Michel Rouly committed
167
    domain = "//%s" % request.META.get('HTTP_HOST') + "/"
168

169
    url = get_object_or_404(URL, short__iexact=short)
170

Jean Michel Rouly's avatar
Jean Michel Rouly committed
171
    return render(request, 'view.html', {
172
        'url': url,
173
        'domain': domain,
174
175
176
    },
    )

Jean Michel Rouly's avatar
Jean Michel Rouly committed
177

178
@login_required
179
def my_links(request):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
180
181
182
183
184
    """
    This view displays all the information about all of your URLs. You
    obviously need to be logged in to view your URLs.
    """

185
    if not is_approved(request.user):
186
        return render(request, 'not_registered.html')
Jean Michel Rouly's avatar
Jean Michel Rouly committed
187

188
    urls = URL.objects.filter(owner=request.user)
189

Jean Michel Rouly's avatar
Jean Michel Rouly committed
190
    domain = "//%s" % request.META.get('HTTP_HOST') + "/"
191

192
    return render(request, 'my_links.html', {
193
194
        'urls': urls,
        'domain': domain,
195
196
197
    },
    )

Jean Michel Rouly's avatar
Jean Michel Rouly committed
198

199
@login_required
200
def delete(request, short):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
201
202
203
204
205
    """
    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.
    """

206
    if not is_approved(request.user):
207
        return render(request, 'not_registered.html')
Jean Michel Rouly's avatar
Jean Michel Rouly committed
208

209
    url = get_object_or_404(URL, short__iexact=short)
210
211
    if url.owner == request.user:
        url.delete()
212
213
        return redirect('my_links')
    else:
214
        raise PermissionDenied()
215

Jean Michel Rouly's avatar
Jean Michel Rouly committed
216

217
@login_required
Jean Michel Rouly's avatar
Jean Michel Rouly committed
218
def signup(request):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
219
220
221
222
223
    """
    This view presents the user with a registration form. You can register
    yourself, or another person.

    """
224
    # Do not display signup page to registered or approved users (Staff can still see these pages)
225
    if is_registered(request.user) and not request.user.is_staff:
226
        return render(request, 'core/signup.html', {
227
            'registered': True,
228
229
230
231
            'approved': False,
        },
        )
    elif is_approved(request.user) and not request.user.is_staff:
232
        return render(request, 'core/signup.html', {
233
234
            'registered': True,
            'approved': True,
235
236
237
238
239
240
241
242
243
244
        },
        )

    signup_form = SignupForm(initial={'username': request.user.username})
    # Non-staff have the username field read-only and pre-filled
    if request.user.is_staff:
        signup_form = SignupForm()
    else:
        signup_form = SignupForm(initial={'username': request.user.username})
        signup_form.fields['username'].widget.attrs['readonly'] = 'readonly'
Jean Michel Rouly's avatar
Jean Michel Rouly committed
245
246

    if request.method == 'POST':
247
        signup_form = SignupForm(request.POST, initial={'approved': False,
248
                                 'username': request.user.username})
249

250
        if signup_form.is_valid():
251
252
253
254
255
            # Prevent hax: if not staff, force the username back to the request username.
            if not request.user.is_staff:
                username = request.user.username
            else:
                username = signup_form.cleaned_data.get('username')
256
257
            full_name = signup_form.cleaned_data.get('full_name')
            description = signup_form.cleaned_data.get('description')
258

259
260
261
            # Only send mail if we've defined the mailserver
            if settings.EMAIL_HOST and settings.EMAIL_PORT:
                send_mail('Signup from %s' % (username), '%s signed up at %s\n'
262
263
264
265
                          'Username: %s\nMessage: %s\nPlease attend to this request at '
                          'your earliest convenience.' % (str(full_name),
                          str(timezone.now()).strip(), str(username), str(description)),
                          settings.EMAIL_FROM, [settings.EMAIL_TO])
266

267
268
            signup_form.save()

269
            return redirect('registered')
Jean Michel Rouly's avatar
Jean Michel Rouly committed
270

271
    return render(request, 'core/signup.html', {
272
        'form': signup_form,
273
        'registered': False,
Jean Michel Rouly's avatar
Jean Michel Rouly committed
274
275
    },
    )
Jean Michel Rouly's avatar
Jean Michel Rouly committed
276

Jean Michel Rouly's avatar
Jean Michel Rouly committed
277

Jean Michel Rouly's avatar
Jean Michel Rouly committed
278
def redirection(request, short):
Jean Michel Rouly's avatar
Jean Michel Rouly committed
279
280
281
    """
    This view redirects a user based on the short URL they requested.
    """
Jean Michel Rouly's avatar
Jean Michel Rouly committed
282

283
    url = get_object_or_404(URL, short__iexact=short)
Jean Michel Rouly's avatar
Jean Michel Rouly committed
284
    url.clicks = url.clicks + 1
285
286
287
288
289
290
291

    if 'qr' in request.GET:
        url.qrclicks += 1

    if 'social' in request.GET:
        url.socialclicks += 1

Jean Michel Rouly's avatar
Jean Michel Rouly committed
292
    url.save()
293

Jean Michel Rouly's avatar
Jean Michel Rouly committed
294
295
296
297
298
    """
    Include server-side tracking because there is no template displayed to
    the user which would include javascript tracking.
    """

299
300
    from piwikapi.tracking import PiwikTracker
    from django.conf import settings
301
    # First, if PIWIK variables are undefined, don't try to push
302
    if settings.PIWIK_SITE_ID != "" and settings.PIWIK_URL != "":
303
304
305
306
307
308
309
        try:
            piwiktracker = PiwikTracker(settings.PIWIK_SITE_ID, request)
            piwiktracker.set_api_url(settings.PIWIK_URL)
            piwiktracker.do_track_page_view('Redirect to %s' % url.target)
        # Second, if we do get an error, don't let that keep us from redirecting
        except:
            pass
310

311
    return redirect(url.target)
Jean Michel Rouly's avatar
Jean Michel Rouly committed
312
313


314
315
316
317
318
319
320
321
322
323
324
325
326
def staff_member_required(view_func, redirect_field_name=REDIRECT_FIELD_NAME, login_url='about'):
    """
    Decorator for views that checks that the user is logged in and is a staff
    member, displaying the login page if necessary.
    """
    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)


@staff_member_required
Chris Reffett's avatar
Chris Reffett committed
327
def useradmin(request):
328
329
330
331
332
    """
    This view is a simplified admin panel, so that staff don't need to log in
    to approve links
    """
    if request.POST:
333
        userlist = request.POST.getlist('username')
334
        if '_approve' in request.POST:
335
336
337
338
            for name in userlist:
                toapprove = RegisteredUser.objects.get(username=name)
                toapprove.approved = True
                toapprove.save()
339
        elif '_deny' in request.POST:
340
341
342
            for name in userlist:
                todeny = RegisteredUser.objects.get(username=name)
                todeny.delete()
343
    need_approval = RegisteredUser.objects.filter(approved=False)
344
    return render(request, 'admin/useradmin.html', {
345
346
347
348
349
        'need_approval': need_approval
    },
    )


Jean Michel Rouly's avatar
Jean Michel Rouly committed
350
351
352
353
354
355
356
##############################################################################
"""
Define static user views here.
"""


def about(request):
357
    return render(request, 'core/about.html', {
Jean Michel Rouly's avatar
Jean Michel Rouly committed
358
359
360
    },
    )

361

362
363
364
365
def registered(request):
    return render(request, 'registered.html', {
    },
    )