Repository: dotkom/onlineweb4

Issue:
Feedback views can't use @staff_member_required
We are taking away staff priovileges from other comittees than dotKom when the dashboard gets made, which makes these checks in feedback irrelevant. 

I suggest you make your own decorator here, where you validate whether or not the user is in a comittee that should be able to see feedbacks.

I don't know if we should allow dotKom and/or HS as well? Thoughts?



Discussion:
We should use the @permission_required decorator and make an ACL based on groups for this.

Well, should fagKom be able to see bedKom's feedbacks?

I would say no. Motherfuckers only see what they need to see.

In that case using permissions may be difficult, wouldn't it? I might be thinking of this the wrong way, but if you wish to filter on the committee that actually made the feedback I imagine some custom work needs to be done for it.

Oh fuck, that is true.

Using the helper method in apps/events/utils should do what we want with this.

Can be seen in use here; https://github.com/dotKom/onlineweb4/blob/develop/apps/events/views.py#L278

Could also be implemented using django-guardian for object level permissions. Example: https://github.com/dotKom/onlineweb4/blob/23e6e704665d9135ef385377702000bc3634c444/apps/posters/dashboard/views.py#L171


Resolving patch:
diff --git a/apps/feedback/utils.py b/apps/feedback/utils.py
new file mode 100644
--- /dev/null
+++ b/apps/feedback/utils.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+
+from django.contrib.contenttypes.models import ContentType
+
+from apps.events.models import Event
+from apps.events.utils import get_group_restricted_events
+from apps.feedback.models import FeedbackRelation
+
+
+def has_permission(feedback_relation, user):
+    content_object = feedback_relation.content_object
+
+    if isinstance(content_object, Event):
+        return content_object in get_group_restricted_events(user)
+
+    # If the object is not an event return false by default
+    return False
+
+
+def can_delete(text_answer, user):
+    feedback_relation = text_answer.feedback_relation
+
+    return has_permission(feedback_relation, user)
+
+
+def get_group_restricted_feedback_relations(user):
+    events = get_group_restricted_events(user, True)
+
+    return FeedbackRelation.objects.filter(object_id__in=events, content_type=ContentType.objects.get(model="event"))
diff --git a/apps/feedback/views.py b/apps/feedback/views.py
--- a/apps/feedback/views.py
+++ b/apps/feedback/views.py
@@ -7,7 +7,6 @@
 from django.shortcuts import render, redirect, get_object_or_404
 from django.contrib.contenttypes.models import ContentType
 from django.contrib import messages
-from django.contrib.admin.views.decorators import staff_member_required
 from django.contrib.auth.decorators import login_required
 from django.core.exceptions import ObjectDoesNotExist
 from django.utils.translation import ugettext_lazy as _
@@ -21,28 +20,29 @@
     RegisterToken
 )
 from apps.feedback.forms import create_answer_forms
+from apps.feedback.utils import has_permission, can_delete, get_group_restricted_feedback_relations
 
 
 @login_required
 def feedback(request, applabel, appmodel, object_id, feedback_id):
-    fbr = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
+    feedback_relation = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
 
-    if not fbr.can_answer(request.user):
-        messages.error(request, fbr.answer_error_message(request.user))
+    if not feedback_relation.can_answer(request.user):
+        messages.error(request, feedback_relation.answer_error_message(request.user))
         return redirect("home")
 
     if request.method == "POST":
-        answers = create_answer_forms(fbr, post_data=request.POST)
+        answers = create_answer_forms(feedback_relation, post_data=request.POST)
         if all([a.is_valid() for a in answers]):
             for a in answers:
                 a.save()
 
             # mark that the user has answered
-            fbr.answered.add(request.user)
-            fbr.save()
+            feedback_relation.answered.add(request.user)
+            feedback_relation.save()
 
             # Set field of study automaticly
-            fosa = FieldOfStudyAnswer(feedback_relation=fbr, answer=request.user.field_of_study)
+            fosa = FieldOfStudyAnswer(feedback_relation=feedback_relation, answer=request.user.field_of_study)
             fosa.save()
 
             messages.success(request, _(u"Takk for at du svarte."))
@@ -50,9 +50,9 @@ def feedback(request, applabel, appmodel, object_id, feedback_id):
         else:
             messages.error(request, _(u"Du må svare på alle påkrevde felt."))
     else:
-        answers = create_answer_forms(fbr)
+        answers = create_answer_forms(feedback_relation)
 
-    description = fbr.description
+    description = feedback_relation.description
 
     return render(
         request,
@@ -61,47 +61,55 @@ def feedback(request, applabel, appmodel, object_id, feedback_id):
     )
 
 
-@staff_member_required
+@login_required
 def result(request, applabel, appmodel, object_id, feedback_id):
-    return feedback_results(request, applabel, appmodel, object_id, feedback_id)
+    feedback_relation = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
+
+    if not has_permission(feedback_relation, request.user):
+        messages.error(request, _(u"Du har ikke tilgang til dette skjemaet."))
+        return redirect("home")
+
+    return feedback_results(request, feedback_relation)
 
 
 def results_token(request, applabel, appmodel, object_id, feedback_id,  token):
-    fbr = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
-    rt = get_object_or_404(RegisterToken, token=token)
+    feedback_relation = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
+    register_token = get_object_or_404(RegisterToken, token=token)
 
-    if rt.is_valid(fbr):
-        return feedback_results(request, applabel, appmodel, object_id, feedback_id, True)
+    if register_token.is_valid(feedback_relation):
+        return feedback_results(request, feedback_relation, True)
     else:
         return HttpResponse('Unauthorized', status=401)
 
 
-def feedback_results(request, applabel, appmodel, object_id, feedback_id, token=False):
-    fbr = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
-
+def feedback_results(request, feedback_relation, token=False):
     qa = namedtuple("Qa", "question, answers")
     question_and_answers = []
 
-    for question in fbr.questions:
+    for question in feedback_relation.questions:
         if (question.display or not token) and isinstance(question, TextQuestion):
-            question_and_answers.append(qa(question, fbr.answers_to_question(question)))
+            question_and_answers.append(qa(question, feedback_relation.answers_to_question(question)))
 
     info = None
 
-    if fbr.feedback.display_info or not token:
-        info = fbr.content_info()
-        info[_(u'Besvarelser')] = fbr.answered.count()
+    if feedback_relation.feedback.display_info or not token:
+        info = feedback_relation.content_info()
+        info[_(u'Besvarelser')] = feedback_relation.answered.count()
 
-    rt = get_object_or_404(RegisterToken, fbr=fbr)
+    register_token = get_object_or_404(RegisterToken, fbr=feedback_relation)
 
-    token_url = u"%s%sresults/%s" % (request.META['HTTP_HOST'], fbr.get_absolute_url(), rt.token)
+    token_url = u"%s%sresults/%s" % (
+        request.META['HTTP_HOST'],
+        feedback_relation.get_absolute_url(),
+        register_token.token
+    )
 
     return render(
         request,
         'feedback/results.html',
         {
             'question_and_answers': question_and_answers,
-            'description': fbr.description,
+            'description': feedback_relation.description,
             'token_url': token_url,
             'token': token,
             'info': info
@@ -109,33 +117,37 @@ def feedback_results(request, applabel, appmodel, object_id, feedback_id, token=
     )
 
 
-@staff_member_required
+@login_required
 def chart_data(request, applabel, appmodel, object_id, feedback_id):
-    return get_chart_data(request, applabel, appmodel, object_id, feedback_id)
+    feedback_relation = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
+
+    if not has_permission(feedback_relation, request.user):
+        messages.error(request, _(u"Du har ikke tilgang til denne dataen."))
+        return redirect("home")
+
+    return get_chart_data(request, feedback_relation)
 
 
 def chart_data_token(request, applabel, appmodel, object_id, feedback_id, token):
-    fbr = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
-    rt = get_object_or_404(RegisterToken, token=token)
+    feedback_relation = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
+    register_token = get_object_or_404(RegisterToken, token=token)
 
-    if rt.is_valid(fbr):
-        return get_chart_data(request, applabel, appmodel, object_id, feedback_id, True)
+    if register_token.is_valid(feedback_relation):
+        return get_chart_data(request, feedback_relation, True)
     else:
         return HttpResponse('Unauthorized', status=401)
 
 
-def get_chart_data(request, applabel, appmodel, object_id, feedback_id, token=False):
-    fbr = _get_fbr_or_404(applabel, appmodel, object_id, feedback_id)
-
+def get_chart_data(request, feedback_relation, token=False):
     rating_answers = []
     rating_titles = []
     answer_collection = dict()
     answer_collection['replies'] = dict()
     answer_length = int(len(RATING_CHOICES))
-    for question in fbr.ratingquestion:
+    for question in feedback_relation.ratingquestion:
         if question.display or not token:
             rating_titles.append(str(question))
-            answers = fbr.answers_to_question(question)
+            answers = feedback_relation.answers_to_question(question)
             answer_count = [0] * answer_length
             for answer in answers:
                 answer_count[int(answer.answer)] += 1
@@ -143,19 +155,19 @@ def get_chart_data(request, applabel, appmodel, object_id, feedback_id, token=Fa
 
     fos_answer_count = defaultdict(int)
 
-    if fbr.feedback.display_field_of_study or not token:
-        fos = fbr.field_of_study_answers.all()
+    if feedback_relation.feedback.display_field_of_study or not token:
+        fos = feedback_relation.field_of_study_answers.all()
         for answer in fos:
             fos_answer_count[str(answer)] += 1
 
     mc_questions = []
     mc_answer_count = []
 
-    for question in fbr.multiple_choice_question:
+    for question in feedback_relation.multiple_choice_question:
         if question.display or not token:
             mc_questions.append(unicode(question))
             answer_count = defaultdict(int)
-            for answer in fbr.answers_to_question(question):
+            for answer in feedback_relation.answers_to_question(question):
                 answer_count[str(answer)] += 1
             mc_answer_count.append(answer_count.items())
 
@@ -168,20 +180,23 @@ def get_chart_data(request, applabel, appmodel, object_id, feedback_id, token=Fa
     return HttpResponse(json.dumps(answer_collection), content_type='application/json')
 
 
-@staff_member_required
+@login_required
 def index(request):
-    feedbacks = FeedbackRelation.objects.all()
-    return render(request, 'feedback/index.html', {'feedbacks': feedbacks})
+    feedback_relations = get_group_restricted_feedback_relations(request.user)
+    return render(request, 'feedback/index.html', {'feedbacks': feedback_relations})
 
 
-@staff_member_required
+@login_required
 def delete_answer(request):
     if request.method == 'POST':
         answer_id = request.POST.get('answer_id')
         answer = get_object_or_404(TextAnswer, pk=answer_id)
-        answer.delete()
-        return HttpResponse(status=200)
-    return HttpResponse(status=401)
+
+        if can_delete(answer, request.user):
+            answer.delete()
+            return HttpResponse(status=200)
+
+    return HttpResponse(_(u"Du har ikke tilgang til å slette dette svaret", status=401))
 
 
 def _get_fbr_or_404(app_label, app_model, object_id, feedback_id):


Test patch: