~oubiwann/adytum-collection/Projects

« back to all changes in this revision

Viewing changes to MacGregorSite/cms/views/admin.py

  • Committer: oubiwann
  • Date: 2009-03-20 04:32:44 UTC
  • Revision ID: svn-v4:a5ecbb21-ded8-0310-8b19-a7ee6de54fb5:Projects:880
* Moved admin security code into a security module.
* Moved response and page not found into new view publisher module.
* Moved edit_instance and edit_updated_page into admin module.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# See the License for the specific language governing permissions and
15
15
# limitations under the License.
16
16
#
17
 
 
18
 
"""Administrative views for page editing and user management."""
19
 
 
 
17
"""
 
18
Administrative views for page editing and user management.
 
19
"""
20
20
import csv
21
 
import functools
22
21
import logging
23
22
import StringIO
24
23
 
 
24
import yaml
 
25
 
25
26
from django import http
26
27
from django.core import urlresolvers
27
28
from django.core import validators
28
 
import forms
 
29
 
29
30
from google.appengine.api import memcache
30
31
from google.appengine.ext import db
 
32
 
 
33
import forms
31
34
import models
32
35
import utility
33
 
import yaml
34
 
 
35
 
 
36
 
def admin_required(func):
37
 
  """Ensure that the logged in user is an administrator."""
38
 
 
39
 
  @functools.wraps(func)
40
 
  def __wrapper(request, *args, **kwds):
41
 
    """Makes it possible for admin_required to be used as a decorator."""
42
 
    if request.user_is_admin:
43
 
      return func(request, *args, **kwds)  # pylint: disable-msg=W0142
44
 
    else:
45
 
      return utility.forbidden(
46
 
          request,
47
 
          error_message='You must be an administrator to view this page.')
48
 
 
49
 
  return __wrapper
50
 
 
51
 
 
52
 
def super_user_required(func):
53
 
  """Ensure that the logged in user has editing privileges."""
54
 
 
55
 
  @functools.wraps(func)
56
 
  def __wrapper(request, *args, **kwds):
57
 
    """Makes it possible for super_user_required to be used as a decorator."""
58
 
    if request.profile.is_superuser:
59
 
      return func(request, *args, **kwds)  # pylint: disable-msg=W0142
60
 
    else:
61
 
      return utility.forbidden(
62
 
          request,
63
 
          error_message='You must be a superuser to view this page.')
64
 
 
65
 
  return __wrapper
66
 
 
67
 
 
68
 
@super_user_required
 
36
import security
 
37
from views import publisher
 
38
 
 
39
 
 
40
def edit_instance(request, model_type, model_form_type,
 
41
                  edit_template, success_url, object_id, **kwargs):
 
42
  # pylint: disable-msg=R0913
 
43
  """Generic method to handle editing objects with Django forms.
 
44
 
 
45
  Args:
 
46
    request: the http request
 
47
    model_type: the class of object being edited
 
48
    model_form_type: the form type to use for editing this object
 
49
    edit_template: the template to use for editing the object
 
50
    success_url: the URL to redirect the user to when the editing is succesful
 
51
    object_id: the ID of the object to edit, or None if creating a new object
 
52
    kwargs: additional data to be passed to the edit form
 
53
 
 
54
  Returns:
 
55
    A HTTP response, either a redirect to the success_url or the edit form.
 
56
 
 
57
  """
 
58
  editing = False
 
59
  type_instance = None
 
60
  if object_id:
 
61
    editing = True
 
62
    type_instance = model_type.get_by_id(int(object_id))
 
63
    if type_instance is None:
 
64
      return http.HttpResponseNotFound('No object exists with key %r',
 
65
                                       object_id)
 
66
 
 
67
  form = model_form_type(data=request.POST or None, instance=type_instance)
 
68
 
 
69
  kwargs['form'] = form
 
70
  kwargs['type_instance'] = type_instance
 
71
  kwargs['editing'] = editing
 
72
 
 
73
  if not request.POST:
 
74
    return publisher.respond(request, edit_template, kwargs)
 
75
 
 
76
  errors = form.errors
 
77
  if not errors:
 
78
    try:
 
79
      type_instance = form.save(commit=False)
 
80
    except ValueError, err:
 
81
      errors['__all__'] = unicode(err)
 
82
  if errors:
 
83
    return publisher.respond(request, edit_template, kwargs)
 
84
 
 
85
  if 'callback' in kwargs:
 
86
    kwargs['callback'](type_instance, kwargs['params'])
 
87
 
 
88
  type_instance.put()
 
89
 
 
90
  return http.HttpResponseRedirect(success_url)
 
91
 
 
92
 
 
93
def edit_updated_page(page_id, message_id='', tab_name=''):
 
94
  """Issues a redirect to the edit form for page_id.
 
95
 
 
96
  Args:
 
97
    page_id: the id of the page that is being edited
 
98
    message_id: the id of the message element to be displayed to the user once
 
99
                the page is reloaded
 
100
    tab_name: the name of the tab to default to when the page is reloaded
 
101
 
 
102
  Returns:
 
103
    A http redirect to the edit form for page_id
 
104
 
 
105
  """
 
106
  url = urlresolvers.reverse('views.admin.edit_page', args=[str(page_id)])
 
107
  if message_id:
 
108
    url = '%s?m=%s' % (url, message_id)
 
109
  if tab_name:
 
110
    url = '%s#%s' % (url, tab_name)
 
111
  return http.HttpResponseRedirect(url)
 
112
 
 
113
 
 
114
@security.super_user_required
69
115
def index(request):
70
116
  """Show the root administrative page."""
71
 
  return utility.respond(request, 'admin/index')
72
 
 
73
 
 
74
 
@super_user_required
 
117
  return publisher.respond(request, 'admin/index')
 
118
 
 
119
 
 
120
@security.super_user_required
75
121
def recently_modified(request):
76
122
  """Show the 10 most recently modified pages."""
77
123
  pages = models.Page.all().order('modified').fetch(10)
78
 
  return utility.respond(request, 'admin/recently_modified', {'pages': pages})
79
 
 
80
 
 
81
 
@super_user_required
 
124
  return publisher.respond(request, 'admin/recently_modified', {'pages': pages})
 
125
 
 
126
 
 
127
@security.super_user_required
82
128
def get_help(request):
83
129
  """Return a help page for the site maintainer."""
84
 
  return utility.respond(request, 'admin/help')
 
130
  return publisher.respond(request, 'admin/help')
85
131
 
86
132
 
87
133
def edit_acl(request):
129
175
  page = models.Page.get_by_id(int(page_id))
130
176
 
131
177
  if not page:
132
 
    return utility.page_not_found(request)
 
178
    return publisher.page_not_found(request)
133
179
  if not page.user_can_write(request.profile):
134
180
    return utility.forbidden(request)
135
181
 
172
218
  if page_id:
173
219
    page = models.Page.get_by_id(int(page_id))
174
220
    if not page:
175
 
      return utility.page_not_found(
 
221
      return publisher.page_not_found(
176
222
          request, 'No page exists with id %r.' % page_id)
177
223
    if not page.user_can_write(request.profile):
178
224
      return utility.forbidden(request)
202
248
 
203
249
  if not request.POST:
204
250
    form = forms.PageEditForm(data=None, instance=page)
205
 
    return utility.respond(request, 'admin/edit_page',
 
251
    return publisher.respond(request, 'admin/edit_page',
206
252
                           {'form': form, 'page': page, 'files': files,
207
253
                            'acl_data': acl_data})
208
254
 
214
260
    except ValueError, err:
215
261
      form.errors['__all__'] = unicode(err)
216
262
  if form.errors:
217
 
    return utility.respond(request, 'admin/edit_page',
 
263
    return publisher.respond(request, 'admin/edit_page',
218
264
                           {'form': form, 'page': page, 'files': files})
219
265
 
220
266
  page.content = request.POST['editorHtml']
267
313
 
268
314
  """
269
315
  if not request.POST or not 'page_id' in request.POST:
270
 
    return utility.page_not_found(request)
 
316
    return publisher.page_not_found(request)
271
317
 
272
318
  page_id = request.POST['page_id']
273
319
  page = models.Page.get_by_id(int(page_id))
275
321
  if not page:
276
322
    logging.warning('admin.upload_file was passed an invalid page id %r',
277
323
                    page_id)
278
 
    return utility.page_not_found(request)
 
324
    return publisher.page_not_found(request)
279
325
 
280
326
  if not page.user_can_write(request.profile):
281
327
    return utility.forbidden(request)
290
336
    url = request.POST['url']
291
337
    file_name = url.split('/')[-1]
292
338
  else:
293
 
    return utility.page_not_found(request)
 
339
    return publisher.page_not_found(request)
294
340
 
295
341
  if not url and not file_name:
296
342
    url = 'invalid URL'
299
345
    try:
300
346
      validators.isValidURL(url, None)
301
347
    except validators.ValidationError, excption:
302
 
      return utility.page_not_found(request, excption.messages[0])
 
348
      return publisher.page_not_found(request, excption.messages[0])
303
349
 
304
350
  file_record = page.get_attachment(file_name)
305
351
 
340
386
    record.delete()
341
387
    return utility.edit_updated_page(page_id, tab_name='files')
342
388
  else:
343
 
    return utility.page_not_found(request)
 
389
    return publisher.page_not_found(request)
344
390
 
345
391
 
346
392
def delete_page(request, page_id):
360
406
  page = models.Page.get_by_id(int(page_id))
361
407
 
362
408
  if not page:
363
 
    return utility.page_not_found(request)
 
409
    return publisher.page_not_found(request)
364
410
 
365
411
  if not page.user_can_write(request.profile):
366
412
    return utility.forbidden(request)
371
417
  return http.HttpResponseRedirect(url)
372
418
 
373
419
 
374
 
@super_user_required
 
420
@security.super_user_required
375
421
def download_page_html(request, page_id):
376
422
  """Gives users access to the current html content of a page.
377
423
 
385
431
  """
386
432
  page = models.Page.get_by_id(int(page_id))
387
433
  if not page:
388
 
    return utility.page_not_found(request)
 
434
    return publisher.page_not_found(request)
389
435
  response = http.HttpResponse(content=page.content, mimetype='text/html')
390
436
  response['Content-Disposition'] = 'attachment; filename=%s.html' % page.name
391
437
  return response
392
438
 
393
439
 
394
 
@super_user_required
 
440
@security.super_user_required
395
441
def filter_users(request):
396
442
  """Lists all the UserGroups in the DB to filter the user list.
397
443
 
403
449
 
404
450
  """
405
451
  groups = models.UserGroup.all().order('name')
406
 
  return utility.respond(request, 'admin/filter_users', {'groups': groups})
407
 
 
408
 
 
409
 
@super_user_required
 
452
  return publisher.respond(request, 'admin/filter_users', {'groups': groups})
 
453
 
 
454
 
 
455
@security.super_user_required
410
456
def list_groups(request):
411
457
  """Lists all the UserGroups in the DB for editing.
412
458
 
418
464
 
419
465
  """
420
466
  groups = models.UserGroup.all().order('name')
421
 
  return utility.respond(request, 'admin/list_groups', {'groups': groups})
422
 
 
423
 
 
424
 
@super_user_required
 
467
  return publisher.respond(request, 'admin/list_groups', {'groups': groups})
 
468
 
 
469
 
 
470
@security.super_user_required
425
471
def view_group(request, group_id):
426
472
  """Lists all the UserProfiles in a group.
427
473
 
440
486
      users = models.UserProfile.get(group.users)
441
487
    else:
442
488
      users = []
443
 
  return utility.respond(request, 'admin/view_group', {'users': users})
444
 
 
445
 
 
446
 
@super_user_required
 
489
  return publisher.respond(request, 'admin/view_group', {'users': users})
 
490
 
 
491
 
 
492
@security.super_user_required
447
493
def add_to_group(_request, group_id, email):
448
494
  """Adds a user to a group.
449
495
 
468
514
  return http.HttpResponseRedirect(url)
469
515
 
470
516
 
471
 
@super_user_required
 
517
@security.super_user_required
472
518
def remove_from_group(_request, group_id, email):
473
519
  """Removes a user from a group.
474
520
 
493
539
  return http.HttpResponseRedirect(url)
494
540
 
495
541
 
496
 
@super_user_required
 
542
@security.super_user_required
497
543
def new_group(request):
498
544
  """Creates a new group.
499
545
 
507
553
  return edit_group(request, None)
508
554
 
509
555
 
510
 
@super_user_required
 
556
@security.super_user_required
511
557
def edit_group(request, group_id):
512
558
  """Edits an existing group or creates a new one if no ID is passed.
513
559
 
522
568
  group = None
523
569
  if group_id:
524
570
    group = models.UserGroup.get_by_id(int(group_id))
525
 
  return utility.edit_instance(request, models.UserGroup, forms.GroupEditForm,
 
571
  return edit_instance(request, models.UserGroup, forms.GroupEditForm,
526
572
                               'admin/edit_group',
527
573
                               urlresolvers.reverse('views.admin.list_groups'),
528
574
                               group_id, group=group)
529
575
 
530
576
 
531
 
@super_user_required
 
577
@security.super_user_required
532
578
def delete_group(_request, group_id):
533
579
  """Deletes a given group.
534
580
 
547
593
  return http.HttpResponseRedirect(url)
548
594
 
549
595
 
550
 
@super_user_required
 
596
@security.super_user_required
551
597
def edit_user(request, email):
552
598
  """Renders and processes a form to edit a UserProfile.
553
599
 
565
611
                                 args=[request.POST['email']])
566
612
      return http.HttpResponseRedirect(url)
567
613
    else:
568
 
      return utility.respond(request, 'admin/edit_user', {'title': 'Edit user'})
 
614
      return publisher.respond(request, 'admin/edit_user', {'title': 'Edit user'})
569
615
 
570
616
  profile = models.UserProfile.load(email, utility.get_domain(request))
571
617
  if not profile:
572
 
    return utility.page_not_found(request)
 
618
    return publisher.page_not_found(request)
573
619
  title = 'Edit user: %s (%s)' % (email, profile.domain)
574
620
 
575
 
  return utility.edit_instance(
 
621
  return edit_instance(
576
622
    request, models.UserProfile, forms.UserEditForm, 'admin/edit_user',
577
623
    urlresolvers.reverse('views.admin.index'), profile.key().id(), title=title,
578
624
    profile=profile)
579
625
 
580
626
 
581
 
@super_user_required
 
627
@security.super_user_required
582
628
def bulk_edit_users(request):
583
629
  """Renders and processes a form to edit UserProfiles with a csv format.
584
630
 
590
636
 
591
637
  """
592
638
  if not request.POST:
593
 
    return utility.respond(request, 'admin/bulk_edit_users',
 
639
    return publisher.respond(request, 'admin/bulk_edit_users',
594
640
                           {'title': 'Bulk user upload form'})
595
641
 
596
642
  data = request.POST['users_text']
613
659
  return http.HttpResponseRedirect(url)
614
660
 
615
661
 
616
 
@super_user_required
 
662
@security.super_user_required
617
663
def export_users(_request):
618
664
  """Export a csv file listing all UserProfiles in the database.
619
665
 
637
683
  return response
638
684
 
639
685
 
640
 
@super_user_required
 
686
@security.super_user_required
641
687
def add_to_sidebar(_request, page_id):
642
688
  """Adds a page to the bottom of the sidebar.
643
689
 
655
701
      urlresolvers.reverse('views.admin.edit_sidebar'))
656
702
 
657
703
 
658
 
@super_user_required
 
704
@security.super_user_required
659
705
def edit_sidebar(request):
660
706
  """Renders and processes a form to edit the YAML definition of the sidebar.
661
707
 
684
730
      error_message = 'Invalid YAML, missing key %s' % error
685
731
 
686
732
    if error_message:
687
 
      return utility.respond(request, 'admin/edit_sidebar',
 
733
      return publisher.respond(request, 'admin/edit_sidebar',
688
734
                             {'yaml': yaml_data,
689
735
                              'error_message': error_message})
690
736
 
694
740
    yaml_data = ''
695
741
    if sidebar:
696
742
      yaml_data = sidebar.yaml
697
 
    return utility.respond(request, 'admin/edit_sidebar', {'yaml': yaml_data})
698
 
 
699
 
 
700
 
@admin_required
 
743
    return publisher.respond(request, 'admin/edit_sidebar', {'yaml': yaml_data})
 
744
 
 
745
 
 
746
@security.admin_required
701
747
def flush_memcache_info(_request):
702
748
  """Flushes the memcache.
703
749
 
713
759
      urlresolvers.reverse('views.admin.display_memcache_info'))
714
760
 
715
761
 
716
 
@admin_required
 
762
@security.admin_required
717
763
def display_memcache_info(request):
718
764
  """Displays all of the information about the applications memcache.
719
765
 
725
771
 
726
772
  """
727
773
  # pylint: disable-msg=E1101
728
 
  return utility.respond(request, 'admin/memcache_info',
 
774
  return publisher.respond(request, 'admin/memcache_info',
729
775
                         {'memcache_info': memcache.get_stats()})