mirror of
https://github.com/jlengrand/bugsink.git
synced 2026-03-10 08:01:17 +00:00
issue-views: test for project membership
This commit is contained in:
@@ -1,3 +1,40 @@
|
||||
from functools import wraps
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.core.exceptions import PermissionDenied
|
||||
|
||||
from projects.models import Project
|
||||
from issues.models import Issue
|
||||
|
||||
|
||||
def login_exempt(view):
|
||||
view.login_exempt = True
|
||||
return view
|
||||
|
||||
|
||||
def project_membership_required(function):
|
||||
@wraps(function)
|
||||
def wrapper(request, *args, **kwargs):
|
||||
project_id = kwargs.pop("project_id")
|
||||
project = get_object_or_404(Project, pk=project_id)
|
||||
kwargs["project"] = project
|
||||
if project.users.filter(pk=request.user.pk).exists():
|
||||
return function(request, *args, **kwargs)
|
||||
|
||||
raise PermissionDenied("You don't have permission to access this project")
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def issue_membership_required(function):
|
||||
@wraps(function)
|
||||
def wrapper(request, *args, **kwargs):
|
||||
issue_pk = kwargs.pop("issue_pk")
|
||||
issue = get_object_or_404(Issue, pk=issue_pk)
|
||||
kwargs["issue"] = issue
|
||||
if issue.project.users.filter(pk=request.user.pk).exists():
|
||||
return function(request, *args, **kwargs)
|
||||
|
||||
raise PermissionDenied("You don't have permission to access this project")
|
||||
|
||||
return wrapper
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.test import TestCase as DjangoTestCase
|
||||
from django.contrib.auth.models import User
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from projects.models import Project
|
||||
from projects.models import Project, ProjectMembership
|
||||
from releases.models import create_release_if_needed
|
||||
from bugsink.registry import reset_pc_registry, get_pc_registry
|
||||
from bugsink.period_counter import PeriodCounter, TL_DAY
|
||||
@@ -424,6 +424,7 @@ class ViewTests(DjangoTestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(username='test', password='test')
|
||||
self.project = Project.objects.create()
|
||||
ProjectMembership.objects.create(project=self.project, user=self.user)
|
||||
self.issue = Issue.objects.create(project=self.project, **denormalized_issue_fields())
|
||||
self.event = create_event(self.project, self.issue)
|
||||
self.client.force_login(self.user)
|
||||
|
||||
@@ -6,8 +6,7 @@ from django.db.models import Q
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
from events.models import Event
|
||||
|
||||
from projects.models import Project
|
||||
from bugsink.decorators import project_membership_required, issue_membership_required
|
||||
|
||||
from .utils import get_issue_grouper_for_data
|
||||
from .models import Issue, IssueQuerysetStateManager, IssueStateManager
|
||||
@@ -101,7 +100,8 @@ def _apply_action(manager, issue_or_qs, action):
|
||||
manager.unmute(issue_or_qs)
|
||||
|
||||
|
||||
def issue_list(request, project_id, state_filter="open"):
|
||||
@project_membership_required
|
||||
def issue_list(request, project, state_filter="open"):
|
||||
if request.method == "POST":
|
||||
issue_ids = request.POST.getlist('issue_ids[]')
|
||||
issue_qs = Issue.objects.filter(pk__in=issue_ids)
|
||||
@@ -124,11 +124,9 @@ def issue_list(request, project_id, state_filter="open"):
|
||||
}
|
||||
|
||||
issue_list = d_state_filter[state_filter](
|
||||
Issue.objects.filter(project_id=project_id)
|
||||
Issue.objects.filter(project=project)
|
||||
).order_by("-last_seen")
|
||||
|
||||
project = get_object_or_404(Project, pk=project_id)
|
||||
|
||||
return render(request, "issues/issue_list.html", {
|
||||
"project": project,
|
||||
"issue_list": issue_list,
|
||||
@@ -145,11 +143,11 @@ def issue_list(request, project_id, state_filter="open"):
|
||||
})
|
||||
|
||||
|
||||
def issue_last_event(request, issue_pk):
|
||||
issue = get_object_or_404(Issue, pk=issue_pk)
|
||||
@issue_membership_required
|
||||
def issue_last_event(request, issue):
|
||||
last_event = issue.event_set.order_by("timestamp").last()
|
||||
|
||||
return redirect(issue_event_stacktrace, issue_pk=issue_pk, event_pk=last_event.pk)
|
||||
return redirect(issue_event_stacktrace, issue_pk=issue.pk, event_pk=last_event.pk)
|
||||
|
||||
|
||||
def _handle_post(request, issue):
|
||||
@@ -166,8 +164,8 @@ def _handle_post(request, issue):
|
||||
return HttpResponseRedirect(request.path_info)
|
||||
|
||||
|
||||
def issue_event_stacktrace(request, issue_pk, event_pk):
|
||||
issue = get_object_or_404(Issue, pk=issue_pk)
|
||||
@issue_membership_required
|
||||
def issue_event_stacktrace(request, issue, event_pk):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
@@ -201,8 +199,8 @@ def issue_event_stacktrace(request, issue_pk, event_pk):
|
||||
})
|
||||
|
||||
|
||||
def issue_event_details(request, issue_pk, event_pk):
|
||||
issue = get_object_or_404(Issue, pk=issue_pk)
|
||||
@issue_membership_required
|
||||
def issue_event_details(request, issue, event_pk):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
@@ -216,8 +214,8 @@ def issue_event_details(request, issue_pk, event_pk):
|
||||
})
|
||||
|
||||
|
||||
def issue_history(request, issue_pk):
|
||||
issue = get_object_or_404(Issue, pk=issue_pk)
|
||||
@issue_membership_required
|
||||
def issue_history(request, issue):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
@@ -229,8 +227,8 @@ def issue_history(request, issue_pk):
|
||||
})
|
||||
|
||||
|
||||
def issue_grouping(request, issue_pk):
|
||||
issue = get_object_or_404(Issue, pk=issue_pk)
|
||||
@issue_membership_required
|
||||
def issue_grouping(request, issue):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
@@ -242,8 +240,8 @@ def issue_grouping(request, issue_pk):
|
||||
})
|
||||
|
||||
|
||||
def issue_event_list(request, issue_pk):
|
||||
issue = get_object_or_404(Issue, pk=issue_pk)
|
||||
@issue_membership_required
|
||||
def issue_event_list(request, issue):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
|
||||
11
templates/403.html
Normal file
11
templates/403.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}403 Forbidden{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="m-4">
|
||||
<h1 class="text-4xl mt-4 font-bold">Permission denied</h1>
|
||||
|
||||
<div class="pt-2">{{ exception }}</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user