devfund-website/blender_notes/views.py
Sybren A. Stüvel 375cab6e6e Added notes system for the admin
Notes can now be added to *any* model in the admin. Deletion is
immediate and irreversible.

The following permissions can be granted to users/groups:
    - blender_notes.add_note
    - blender_notes.change_note
    - blender_notes.delete_note
    - blender_notes.view_note

WARNING: a user with view_note permissions can view *ALL* notes. There
is no model-level access. In other words, even when someone cannot see
Memberships, they can read ALL notes on ALL Memberships.
2018-09-18 16:31:58 +02:00

92 lines
3.6 KiB
Python

import logging
from django.contrib.auth.decorators import permission_required
from django.http import HttpResponseBadRequest
from django.contrib.contenttypes.models import ContentType
from django.utils.decorators import method_decorator
from django.views import View
from django.views.generic.edit import FormView
from django.shortcuts import redirect
from . import forms, models
log = logging.getLogger(__name__)
class NotesView(FormView):
"""Fetching and creating notes."""
template_name = 'blender_notes/notes_in_admin.html'
form_class = forms.NoteForm
@method_decorator(permission_required('blender_notes.view_note', raise_exception=True))
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
@method_decorator(permission_required('blender_notes.add_note', raise_exception=True))
def post(self, request, *args, **kwargs):
return super().post(request, *args, **kwargs)
def form_valid(self, form):
ctype = ContentType.objects.get_by_natural_key(
self.kwargs['app_label'], self.kwargs['model_name'])
log.info('Attaching note to %s %s %s for user %s',
self.kwargs['app_label'], self.kwargs['model_name'], self.kwargs['object_id'],
self.request.user)
note: models.Note = form.instance
note.creator = self.request.user
note.object_id = self.kwargs['object_id']
note.content_type = ctype
note.save()
context = self.get_context_data(**self.kwargs)
# Note was succesfully added, start with a fresh form instead of from POSTed data.
form_class = self.get_form_class()
context['form'] = form_class()
return self.render_to_response(context)
def get_context_data(self, **kwargs) -> dict:
context = super().get_context_data(**kwargs)
context.update(self.kwargs)
query = models.Note.objects.get_by_natural_key(
self.kwargs['app_label'],
self.kwargs['model_name'],
self.kwargs['object_id'])
context['notes'] = query
return context
def get_success_url(self):
return self.request.get_raw_uri()
class DeleteNoteView(View):
@method_decorator(permission_required('blender_notes.delete_note', raise_exception=True))
def post(self, request, **kwargs):
app_label = self.kwargs['app_label']
model_name = self.kwargs['model_name']
object_id = self.kwargs['object_id']
note_id = self.kwargs['note_id']
note = models.Note.objects.get(pk=note_id)
if note.object_id != object_id:
log.warning('Not deleting note %d, it was called for object_id=%d but '
'belongs to object_id=%d', note.pk, object_id)
return HttpResponseBadRequest('Mismatched Object ID')
if note.content_type.model != model_name or note.content_type.app_label != app_label:
log.warning('Not deleting note %d, it was called for content_type=%r/%r but '
'belongs to content_type=%r/%r', note.pk, app_label, model_name,
note.content_type.app_label, note.content_type.model)
return HttpResponseBadRequest('Mismatched Content Type')
log.info('Deleting note %d of %s %s %s on behalf of user %s',
note_id, app_label, model_name, object_id, self.request.user)
note.delete()
return redirect('notes:for-object',
app_label=app_label,
model_name=model_name,
object_id=object_id)