forked from CGM_Public/pretix_original
Control: Add drag and drop to sort categories and products (#2242)
* add drag and drop to categories * add drag and drop to products * add light grey background to dragged element * add missing th, add sr-only desc of columns * group up/down/move elements * improve visualizing drag-area by dimming others * change up/down-links to buttons in form-post * limit sorting to POST requests Co-authored-by: Raphael Michel <michel@rami.io>
This commit is contained in:
committed by
GitHub
parent
dde4e12ce1
commit
8121167d5e
@@ -24,6 +24,8 @@
|
||||
<a href="{% url "control:event.items.categories.add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new category" %}
|
||||
</a>
|
||||
</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
@@ -33,15 +35,16 @@
|
||||
<th class="action-col-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody data-dnd-url="{% url "control:event.items.categories.reorder" organizer=request.event.organizer.slug event=request.event.slug %}">
|
||||
{% for c in categories %}
|
||||
<tr>
|
||||
<tr data-dnd-id="{{ c.id }}">
|
||||
<td>
|
||||
<strong><a href="{% url "control:event.items.categories.edit" organizer=request.event.organizer.slug event=request.event.slug category=c.id %}">{{ c.internal_name|default:c.name }}</a></strong>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url "control:event.items.categories.up" organizer=request.event.organizer.slug event=request.event.slug category=c.id %}" class="btn btn-default btn-sm {% if forloop.counter0 == 0 and is_paginated and not page_obj.has_previous %}disabled{% endif %}"><i class="fa fa-arrow-up"></i></a>
|
||||
<a href="{% url "control:event.items.categories.down" organizer=request.event.organizer.slug event=request.event.slug category=c.id %}" class="btn btn-default btn-sm {% if forloop.revcounter0 == 0 and is_paginated and not page_obj.has_next %}disabled{% endif %}"><i class="fa fa-arrow-down"></i></a>
|
||||
<button formaction="{% url "control:event.items.categories.up" organizer=request.event.organizer.slug event=request.event.slug category=c.id %}" class="btn btn-default btn-sm sortable-up"{% if forloop.counter0 == 0 and not page_obj.has_previous %} disabled{% endif %}><i class="fa fa-arrow-up"></i></button>
|
||||
<button formaction="{% url "control:event.items.categories.down" organizer=request.event.organizer.slug event=request.event.slug category=c.id %}" class="btn btn-default btn-sm sortable-down"{% if forloop.revcounter0 == 0 and not page_obj.has_next %} disabled{% endif %}><i class="fa fa-arrow-down"></i></button>
|
||||
<span class="dnd-container"></span>
|
||||
</td>
|
||||
<td class="text-right flip">
|
||||
<a href="{% url "control:event.items.categories.edit" organizer=request.event.organizer.slug event=request.event.slug category=c.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
@@ -56,6 +59,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
<a href="{% url "control:event.items.add" organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new product" %}</a>
|
||||
</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
@@ -36,15 +38,16 @@
|
||||
<th class="iconcol"></th>
|
||||
<th class="iconcol"></th>
|
||||
<th>{% trans "Category" %}</th>
|
||||
<th class="action-col-2"></th>
|
||||
<th class="action-col-2"></th>
|
||||
<th class="action-col-2"><span class="sr-only">Move</span></th>
|
||||
<th class="action-col-2"><span class="sr-only">Edit</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% regroup items by category as cat_list %}
|
||||
{% for c in cat_list %}
|
||||
<tbody data-dnd-url="{% url "control:event.items.reorder" organizer=request.event.organizer.slug event=request.event.slug %}">
|
||||
{% for i in c.list %}
|
||||
<tr {% if not i.active %}class="row-muted"{% endif %}>
|
||||
{% if forloop.counter0 == 0 and i.category %}<tr class="sortable-disabled"><th colspan="8" scope="colgroup" class="text-muted">{{ i.category.name }}</th></tr>{% endif %}
|
||||
<tr data-dnd-id="{{ i.id }}" {% if not i.active %}class="row-muted"{% endif %}>
|
||||
<td><strong>
|
||||
{% if not i.active %}<strike>{% endif %}
|
||||
<a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.id %}">{{ i }}</a>
|
||||
@@ -105,8 +108,9 @@
|
||||
</td>
|
||||
<td>{% if i.category %}{{ i.category.name }}{% endif %}</td>
|
||||
<td>
|
||||
<a href="{% url "control:event.items.up" organizer=request.event.organizer.slug event=request.event.slug item=i.id %}" class="btn btn-default btn-sm {% if forloop.counter0 == 0 and is_paginated and not page_obj.has_previous %}disabled{% endif %}"><i class="fa fa-arrow-up"></i></a>
|
||||
<a href="{% url "control:event.items.down" organizer=request.event.organizer.slug event=request.event.slug item=i.id %}" class="btn btn-default btn-sm {% if forloop.revcounter0 == 0 and is_paginated and not page_obj.has_next %}disabled{% endif %}"><i class="fa fa-arrow-down"></i></a>
|
||||
<button formaction="{% url "control:event.items.up" organizer=request.event.organizer.slug event=request.event.slug item=i.id %}" class="btn btn-default btn-sm sortable-up"{% if forloop.counter0 == 0 %} disabled{% endif %}><i class="fa fa-arrow-up"></i></button>
|
||||
<button formaction="{% url "control:event.items.down" organizer=request.event.organizer.slug event=request.event.slug item=i.id %}" class="btn btn-default btn-sm sortable-down"{% if forloop.revcounter0 == 0 %} disabled{% endif %}><i class="fa fa-arrow-down"></i></button>
|
||||
<span class="dnd-container"></span>
|
||||
</td>
|
||||
<td class="text-right flip col-actions">
|
||||
<a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=i.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
@@ -115,10 +119,11 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -239,6 +239,7 @@ urlpatterns = [
|
||||
re_path(r'^items/(?P<item>\d+)/$', item.ItemUpdateGeneral.as_view(), name='event.item'),
|
||||
re_path(r'^items/(?P<item>\d+)/up$', item.item_move_up, name='event.items.up'),
|
||||
re_path(r'^items/(?P<item>\d+)/down$', item.item_move_down, name='event.items.down'),
|
||||
re_path(r'^items/reorder$', item.reorder_items, name='event.items.reorder'),
|
||||
re_path(r'^items/(?P<item>\d+)/delete$', item.ItemDelete.as_view(), name='event.items.delete'),
|
||||
re_path(r'^items/typeahead/meta/$', typeahead.item_meta_values, name='event.items.meta.typeahead'),
|
||||
re_path(r'^items/select2$', typeahead.items_select2, name='event.items.select2'),
|
||||
@@ -250,6 +251,7 @@ urlpatterns = [
|
||||
re_path(r'^categories/(?P<category>\d+)/up$', item.category_move_up, name='event.items.categories.up'),
|
||||
re_path(r'^categories/(?P<category>\d+)/down$', item.category_move_down,
|
||||
name='event.items.categories.down'),
|
||||
re_path(r'^categories/reorder$', item.reorder_categories, name='event.items.categories.reorder'),
|
||||
re_path(r'^categories/(?P<category>\d+)/$', item.CategoryUpdate.as_view(),
|
||||
name='event.items.categories.edit'),
|
||||
re_path(r'^categories/add$', item.CategoryCreate.as_view(), name='event.items.categories.add'),
|
||||
|
||||
@@ -53,6 +53,7 @@ from django.urls import resolve, reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext, gettext_lazy as _
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.generic import ListView
|
||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||
from django.views.generic.edit import DeleteView
|
||||
@@ -138,6 +139,7 @@ def item_move(request, item, up=True):
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@require_http_methods(["POST"])
|
||||
def item_move_up(request, organizer, event, item):
|
||||
item_move(request, item, up=True)
|
||||
return redirect('control:event.items',
|
||||
@@ -146,6 +148,7 @@ def item_move_up(request, organizer, event, item):
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@require_http_methods(["POST"])
|
||||
def item_move_down(request, organizer, event, item):
|
||||
item_move(request, item, up=False)
|
||||
return redirect('control:event.items',
|
||||
@@ -153,6 +156,38 @@ def item_move_down(request, organizer, event, item):
|
||||
event=request.event.slug)
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@event_permission_required("can_change_items")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_items(request, organizer, event):
|
||||
try:
|
||||
ids = json.loads(request.body.decode('utf-8'))['ids']
|
||||
except (JSONDecodeError, KeyError, ValueError):
|
||||
return HttpResponseBadRequest("expected JSON: {ids:[]}")
|
||||
|
||||
input_items = list(request.event.items.filter(id__in=[i for i in ids if i.isdigit()]))
|
||||
|
||||
if len(input_items) != len(ids):
|
||||
raise Http404(_("Some of the provided item ids are invalid."))
|
||||
|
||||
item_categories = {i.category_id for i in input_items}
|
||||
if len(item_categories) > 1:
|
||||
raise Http404(_("You cannot reorder items spanning different categories."))
|
||||
|
||||
# get first and only category
|
||||
item_category = next(iter(item_categories))
|
||||
if len(input_items) != request.event.items.filter(category=item_category).count():
|
||||
raise Http404(_("Not all items have been selected."))
|
||||
|
||||
for i in input_items:
|
||||
pos = ids.index(str(i.pk))
|
||||
if pos != i.position: # Save unneccessary UPDATE queries
|
||||
i.position = pos
|
||||
i.save(update_fields=['position'])
|
||||
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
class CategoryDelete(EventPermissionRequiredMixin, DeleteView):
|
||||
model = ItemCategory
|
||||
form_class = CategoryForm
|
||||
@@ -307,6 +342,7 @@ def category_move(request, category, up=True):
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@require_http_methods(["POST"])
|
||||
def category_move_up(request, organizer, event, category):
|
||||
category_move(request, category, up=True)
|
||||
return redirect('control:event.items.categories',
|
||||
@@ -315,6 +351,7 @@ def category_move_up(request, organizer, event, category):
|
||||
|
||||
|
||||
@event_permission_required("can_change_items")
|
||||
@require_http_methods(["POST"])
|
||||
def category_move_down(request, organizer, event, category):
|
||||
category_move(request, category, up=False)
|
||||
return redirect('control:event.items.categories',
|
||||
@@ -322,6 +359,32 @@ def category_move_down(request, organizer, event, category):
|
||||
event=request.event.slug)
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
@event_permission_required("can_change_items")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_categories(request, organizer, event):
|
||||
try:
|
||||
ids = json.loads(request.body.decode('utf-8'))['ids']
|
||||
except (JSONDecodeError, KeyError, ValueError):
|
||||
return HttpResponseBadRequest("expected JSON: {ids:[]}")
|
||||
|
||||
input_categories = list(request.event.categories.filter(id__in=[i for i in ids if i.isdigit()]))
|
||||
|
||||
if len(input_categories) != len(ids):
|
||||
raise Http404(_("Some of the provided category ids are invalid."))
|
||||
|
||||
if len(input_categories) != request.event.categories.count():
|
||||
raise Http404(_("Not all categories have been selected."))
|
||||
|
||||
for c in input_categories:
|
||||
pos = ids.index(str(c.pk))
|
||||
if pos != c.position: # Save unneccessary UPDATE queries
|
||||
c.position = pos
|
||||
c.save(update_fields=['position'])
|
||||
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
FakeQuestion = namedtuple(
|
||||
'FakeQuestion', 'id question position required'
|
||||
)
|
||||
@@ -423,18 +486,21 @@ class QuestionList(ListView):
|
||||
|
||||
@transaction.atomic
|
||||
@event_permission_required("can_change_items")
|
||||
@require_http_methods(["POST"])
|
||||
def reorder_questions(request, organizer, event):
|
||||
try:
|
||||
ids = json.loads(request.body.decode('utf-8'))['ids']
|
||||
except (JSONDecodeError, KeyError, ValueError):
|
||||
return HttpResponseBadRequest("expected JSON: {ids:[]}")
|
||||
|
||||
input_questions = request.event.questions.filter(id__in=[i for i in ids if i.isdigit()])
|
||||
# filter system_questions - normal questions are int/digit, system_questions strings
|
||||
custom_question_ids = [i for i in ids if i.isdigit()]
|
||||
input_questions = list(request.event.questions.filter(id__in=custom_question_ids))
|
||||
|
||||
if input_questions.count() != len([i for i in ids if i.isdigit()]):
|
||||
if len(input_questions) != len(custom_question_ids):
|
||||
raise Http404(_("Some of the provided question ids are invalid."))
|
||||
|
||||
if input_questions.count() != request.event.questions.count():
|
||||
if len(input_questions) != request.event.questions.count():
|
||||
raise Http404(_("Not all questions have been selected."))
|
||||
|
||||
for q in input_questions:
|
||||
|
||||
@@ -5,11 +5,40 @@ $(function () {
|
||||
url = container.data("dnd-url"),
|
||||
handle = $('<span class="btn btn-default btn-sm dnd-sort-handle"><i class="fa fa-arrows"></i></span>');
|
||||
|
||||
console.log(container, container.find(".dnd-container"));
|
||||
container.find(".dnd-container").append(handle);
|
||||
if (container.find("[data-dnd-id]").length < 2) {
|
||||
handle.addClass("disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
Sortable.create(container.get(0), {
|
||||
filter: ".sortable-disabled",
|
||||
handle: ".dnd-sort-handle",
|
||||
onMove: function (evt) {
|
||||
return evt.related.className.indexOf('sortable-disabled') === -1;
|
||||
},
|
||||
onStart: function (evt) {
|
||||
container.addClass("sortable-dragarea");
|
||||
container.parent().addClass("sortable-sorting");
|
||||
},
|
||||
onEnd: function (evt) {
|
||||
container.removeClass("sortable-dragarea");
|
||||
container.parent().removeClass("sortable-sorting");
|
||||
|
||||
var disabledUp = container.find(".sortable-up:disabled"),
|
||||
firstUp = container.find(">tr[data-dnd-id] .sortable-up").first();
|
||||
if (disabledUp.length && disabledUp.get(0) !== firstUp.get(0)) {
|
||||
disabledUp.prop("disabled", false);
|
||||
firstUp.prop("disabled", true);
|
||||
}
|
||||
|
||||
var disabledDown = container.find(".sortable-down:disabled"),
|
||||
lastDown = container.find(">tr[data-dnd-id] .sortable-down").last();
|
||||
if (disabledDown.length && disabledDown.get(0) !== lastDown.get(0)) {
|
||||
disabledDown.prop("disabled", false);
|
||||
lastDown.prop("disabled", true);
|
||||
}
|
||||
},
|
||||
onSort: function (evt){
|
||||
var container = $(evt.to),
|
||||
ids = container.find("[data-dnd-id]").toArray().map(function (e) { return e.dataset.dndId; });
|
||||
|
||||
@@ -706,6 +706,20 @@ h1 .label {
|
||||
}
|
||||
}
|
||||
|
||||
.sortable-chosen {
|
||||
background-color: $table-bg-hover;
|
||||
}
|
||||
tbody[data-dnd-url] {
|
||||
transition: opacity 1s;
|
||||
}
|
||||
.sortable-sorting tbody:not(.sortable-dragarea) {
|
||||
opacity: .4;
|
||||
}
|
||||
tbody th {
|
||||
background: $table-bg-hover;
|
||||
}
|
||||
|
||||
|
||||
.withoutjs {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -94,12 +94,12 @@ class CategoriesTest(ItemFormTest):
|
||||
self.assertIn("Entry tickets", doc.select("table > tbody > tr")[0].text)
|
||||
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text)
|
||||
|
||||
self.client.get('/control/event/%s/%s/categories/%s/down' % (self.orga1.slug, self.event1.slug, c1.id))
|
||||
self.client.post('/control/event/%s/%s/categories/%s/down' % (self.orga1.slug, self.event1.slug, c1.id))
|
||||
doc = self.get_doc('/control/event/%s/%s/categories/' % (self.orga1.slug, self.event1.slug))
|
||||
self.assertIn("Entry tickets", doc.select("table > tbody > tr")[1].text)
|
||||
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[0].text)
|
||||
|
||||
self.client.get('/control/event/%s/%s/categories/%s/up' % (self.orga1.slug, self.event1.slug, c1.id))
|
||||
self.client.post('/control/event/%s/%s/categories/%s/up' % (self.orga1.slug, self.event1.slug, c1.id))
|
||||
doc = self.get_doc('/control/event/%s/%s/categories/' % (self.orga1.slug, self.event1.slug))
|
||||
self.assertIn("Entry tickets", doc.select("table > tbody > tr")[0].text)
|
||||
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text)
|
||||
|
||||
@@ -272,104 +272,109 @@ def test_wrong_event(perf_patch, client, env, url):
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
HTTP_POST = "post"
|
||||
HTTP_GET = "get"
|
||||
|
||||
event_permission_urls = [
|
||||
("can_change_event_settings", "live/", 200),
|
||||
("can_change_event_settings", "delete/", 200),
|
||||
("can_change_event_settings", "dangerzone/", 200),
|
||||
("can_change_event_settings", "settings/", 200),
|
||||
("can_change_event_settings", "settings/plugins", 200),
|
||||
("can_change_event_settings", "settings/payment", 200),
|
||||
("can_change_event_settings", "settings/tickets", 200),
|
||||
("can_change_event_settings", "settings/email", 200),
|
||||
("can_change_event_settings", "settings/cancel", 200),
|
||||
("can_change_event_settings", "settings/invoice", 200),
|
||||
("can_change_event_settings", "settings/widget", 200),
|
||||
("can_change_event_settings", "settings/invoice/preview", 200),
|
||||
("can_change_event_settings", "settings/tax/", 200),
|
||||
("can_change_event_settings", "settings/tax/1/", 404),
|
||||
("can_change_event_settings", "settings/tax/add", 200),
|
||||
("can_change_event_settings", "settings/tax/1/delete", 404),
|
||||
("can_change_event_settings", "comment/", 405),
|
||||
("can_change_event_settings", "live/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "delete/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "dangerzone/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/plugins", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/payment", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tickets", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/email", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/cancel", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/invoice", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/widget", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/invoice/preview", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/1/", 404, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/add", 200, HTTP_GET),
|
||||
("can_change_event_settings", "settings/tax/1/delete", 404, HTTP_GET),
|
||||
("can_change_event_settings", "comment/", 405, HTTP_GET),
|
||||
# Lists are currently not access-controlled
|
||||
# ("can_change_items", "items/", 200),
|
||||
("can_change_items", "items/add", 200),
|
||||
("can_change_items", "items/1/up", 404),
|
||||
("can_change_items", "items/1/down", 404),
|
||||
("can_change_items", "items/1/delete", 404),
|
||||
("can_change_items", "items/add", 200, HTTP_GET),
|
||||
("can_change_items", "items/1/up", 404, HTTP_POST),
|
||||
("can_change_items", "items/1/down", 404, HTTP_POST),
|
||||
("can_change_items", "items/reorder", 400, HTTP_POST),
|
||||
("can_change_items", "items/1/delete", 404, HTTP_GET),
|
||||
# ("can_change_items", "categories/", 200),
|
||||
# We don't have to create categories and similar objects
|
||||
# for testing this, it is enough to test that a 404 error
|
||||
# is returned instead of a 403 one.
|
||||
("can_change_items", "categories/2/", 404),
|
||||
("can_change_items", "categories/2/delete", 404),
|
||||
("can_change_items", "categories/2/up", 404),
|
||||
("can_change_items", "categories/2/down", 404),
|
||||
("can_change_items", "categories/add", 200),
|
||||
# ("can_change_items", "questions/", 200),
|
||||
("can_change_items", "questions/2/", 404),
|
||||
("can_change_items", "questions/2/delete", 404),
|
||||
("can_change_items", "questions/reorder", 400),
|
||||
("can_change_items", "questions/add", 200),
|
||||
# ("can_change_items", "quotas/", 200),
|
||||
("can_change_items", "quotas/2/change", 404),
|
||||
("can_change_items", "quotas/2/delete", 404),
|
||||
("can_change_items", "quotas/add", 200),
|
||||
("can_change_event_settings", "subevents/", 200),
|
||||
("can_change_event_settings", "subevents/2/", 404),
|
||||
("can_change_event_settings", "subevents/2/delete", 404),
|
||||
("can_change_event_settings", "subevents/add", 200),
|
||||
("can_view_orders", "orders/overview/", 200),
|
||||
("can_view_orders", "orders/export/", 200),
|
||||
("can_view_orders", "orders/", 200),
|
||||
("can_view_orders", "orders/FOO/", 200),
|
||||
("can_change_orders", "orders/FOO/extend", 200),
|
||||
("can_change_orders", "orders/FOO/reactivate", 302),
|
||||
("can_change_orders", "orders/FOO/contact", 200),
|
||||
("can_change_orders", "orders/FOO/transition", 405),
|
||||
("can_change_orders", "orders/FOO/checkvatid", 405),
|
||||
("can_change_orders", "orders/FOO/resend", 405),
|
||||
("can_change_orders", "orders/FOO/invoice", 405),
|
||||
("can_change_orders", "orders/FOO/change", 200),
|
||||
("can_change_orders", "orders/FOO/approve", 200),
|
||||
("can_change_orders", "orders/FOO/deny", 200),
|
||||
("can_change_orders", "orders/FOO/delete", 302),
|
||||
("can_change_orders", "orders/FOO/comment", 405),
|
||||
("can_change_orders", "orders/FOO/locale", 200),
|
||||
("can_change_orders", "orders/FOO/sendmail", 200),
|
||||
("can_change_orders", "orders/FOO/1/sendmail", 404),
|
||||
("can_change_orders", "orders/import/", 200),
|
||||
("can_change_orders", "orders/import/0ab7b081-92d3-4480-82de-2f8b056fd32f/", 404),
|
||||
("can_view_orders", "orders/FOO/answer/5/", 404),
|
||||
("can_change_orders", "cancel/", 200),
|
||||
("can_change_vouchers", "vouchers/add", 200),
|
||||
("can_change_vouchers", "vouchers/bulk_add", 200),
|
||||
("can_view_vouchers", "vouchers/", 200),
|
||||
("can_view_vouchers", "vouchers/tags/", 200),
|
||||
("can_change_vouchers", "vouchers/1234/", 404),
|
||||
("can_change_vouchers", "vouchers/1234/delete", 404),
|
||||
("can_view_orders", "waitinglist/", 200),
|
||||
("can_change_orders", "waitinglist/auto_assign", 405),
|
||||
("can_change_orders", "waitinglist/action", 405),
|
||||
("can_view_orders", "checkins/", 200),
|
||||
("can_view_orders", "checkinlists/", 200),
|
||||
("can_view_orders", "checkinlists/1/", 404),
|
||||
("can_change_event_settings", "checkinlists/add", 200),
|
||||
("can_change_event_settings", "checkinlists/1/change", 404),
|
||||
("can_change_event_settings", "checkinlists/1/delete", 404),
|
||||
("can_change_items", "categories/2/", 404, HTTP_GET),
|
||||
("can_change_items", "categories/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "categories/2/up", 404, HTTP_POST),
|
||||
("can_change_items", "categories/2/down", 404, HTTP_POST),
|
||||
("can_change_items", "categories/reorder", 400, HTTP_POST),
|
||||
("can_change_items", "categories/add", 200, HTTP_GET),
|
||||
# ("can_change_items", "questions/", 200, HTTP_GET),
|
||||
("can_change_items", "questions/2/", 404, HTTP_GET),
|
||||
("can_change_items", "questions/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "questions/reorder", 400, HTTP_POST),
|
||||
("can_change_items", "questions/add", 200, HTTP_GET),
|
||||
# ("can_change_items", "quotas/", 200, HTTP_GET),
|
||||
("can_change_items", "quotas/2/change", 404, HTTP_GET),
|
||||
("can_change_items", "quotas/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "quotas/add", 200, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/2/", 404, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/2/delete", 404, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/add", 200, HTTP_GET),
|
||||
("can_view_orders", "orders/overview/", 200, HTTP_GET),
|
||||
("can_view_orders", "orders/export/", 200, HTTP_GET),
|
||||
("can_view_orders", "orders/", 200, HTTP_GET),
|
||||
("can_view_orders", "orders/FOO/", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/extend", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/reactivate", 302, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/contact", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/transition", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/checkvatid", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/resend", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/invoice", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/change", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/approve", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/deny", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/delete", 302, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/comment", 405, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/locale", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/sendmail", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/FOO/1/sendmail", 404, HTTP_GET),
|
||||
("can_change_orders", "orders/import/", 200, HTTP_GET),
|
||||
("can_change_orders", "orders/import/0ab7b081-92d3-4480-82de-2f8b056fd32f/", 404, HTTP_GET),
|
||||
("can_view_orders", "orders/FOO/answer/5/", 404, HTTP_GET),
|
||||
("can_change_orders", "cancel/", 200, HTTP_GET),
|
||||
("can_change_vouchers", "vouchers/add", 200, HTTP_GET),
|
||||
("can_change_vouchers", "vouchers/bulk_add", 200, HTTP_GET),
|
||||
("can_view_vouchers", "vouchers/", 200, HTTP_GET),
|
||||
("can_view_vouchers", "vouchers/tags/", 200, HTTP_GET),
|
||||
("can_change_vouchers", "vouchers/1234/", 404, HTTP_GET),
|
||||
("can_change_vouchers", "vouchers/1234/delete", 404, HTTP_GET),
|
||||
("can_view_orders", "waitinglist/", 200, HTTP_GET),
|
||||
("can_change_orders", "waitinglist/auto_assign", 405, HTTP_GET),
|
||||
("can_change_orders", "waitinglist/action", 405, HTTP_GET),
|
||||
("can_view_orders", "checkins/", 200, HTTP_GET),
|
||||
("can_view_orders", "checkinlists/", 200, HTTP_GET),
|
||||
("can_view_orders", "checkinlists/1/", 404, HTTP_GET),
|
||||
("can_change_event_settings", "checkinlists/add", 200, HTTP_GET),
|
||||
("can_change_event_settings", "checkinlists/1/change", 404, HTTP_GET),
|
||||
("can_change_event_settings", "checkinlists/1/delete", 404, HTTP_GET),
|
||||
|
||||
# bank transfer
|
||||
("can_change_orders", "banktransfer/import/", 200),
|
||||
("can_change_orders", "banktransfer/job/1/", 404),
|
||||
("can_change_orders", "banktransfer/action/", 200),
|
||||
("can_change_orders", "banktransfer/refunds/", 200),
|
||||
("can_change_orders", "banktransfer/export/1/", 404),
|
||||
("can_change_orders", "banktransfer/sepa-export/1/", 404),
|
||||
("can_change_orders", "banktransfer/import/", 200, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/job/1/", 404, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/action/", 200, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/refunds/", 200, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/export/1/", 404, HTTP_GET),
|
||||
("can_change_orders", "banktransfer/sepa-export/1/", 404, HTTP_GET),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("perm,url,code", event_permission_urls)
|
||||
def test_wrong_event_permission(perf_patch, client, env, perm, url, code):
|
||||
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
|
||||
def test_wrong_event_permission(perf_patch, client, env, perm, url, code, http_method):
|
||||
t = Team(
|
||||
organizer=env[2], all_events=True
|
||||
)
|
||||
@@ -377,13 +382,16 @@ def test_wrong_event_permission(perf_patch, client, env, perm, url, code):
|
||||
t.save()
|
||||
t.members.add(env[1])
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/event/dummy/dummy/' + url)
|
||||
if http_method and http_method == HTTP_POST:
|
||||
response = client.post('/control/event/dummy/dummy/' + url)
|
||||
else:
|
||||
response = client.get('/control/event/dummy/dummy/' + url)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("perm,url,code", event_permission_urls)
|
||||
def test_limited_event_permission_for_other_event(perf_patch, client, env, perm, url, code):
|
||||
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
|
||||
def test_limited_event_permission_for_other_event(perf_patch, client, env, perm, url, code, http_method):
|
||||
event2 = Event.objects.create(
|
||||
organizer=env[2], name='Dummy', slug='dummy2',
|
||||
date_from=now(), plugins='pretix.plugins.banktransfer'
|
||||
@@ -393,7 +401,10 @@ def test_limited_event_permission_for_other_event(perf_patch, client, env, perm,
|
||||
t.limit_events.add(event2)
|
||||
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/control/event/dummy/dummy/' + url)
|
||||
if http_method and http_method == HTTP_POST:
|
||||
response = client.post('/control/event/dummy/dummy/' + url)
|
||||
else:
|
||||
response = client.get('/control/event/dummy/dummy/' + url)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
@@ -416,8 +427,8 @@ def test_current_permission(client, env):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("perm,url,code", event_permission_urls)
|
||||
def test_correct_event_permission_all_events(perf_patch, client, env, perm, url, code):
|
||||
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
|
||||
def test_correct_event_permission_all_events(perf_patch, client, env, perm, url, code, http_method):
|
||||
t = Team(organizer=env[2], all_events=True)
|
||||
setattr(t, perm, True)
|
||||
t.save()
|
||||
@@ -426,13 +437,16 @@ def test_correct_event_permission_all_events(perf_patch, client, env, perm, url,
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
response = client.get('/control/event/dummy/dummy/' + url)
|
||||
if http_method and http_method == HTTP_POST:
|
||||
response = client.post('/control/event/dummy/dummy/' + url)
|
||||
else:
|
||||
response = client.get('/control/event/dummy/dummy/' + url)
|
||||
assert response.status_code == code
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize("perm,url,code", event_permission_urls)
|
||||
def test_correct_event_permission_limited(perf_patch, client, env, perm, url, code):
|
||||
@pytest.mark.parametrize("perm,url,code,http_method", event_permission_urls)
|
||||
def test_correct_event_permission_limited(perf_patch, client, env, perm, url, code, http_method):
|
||||
t = Team(organizer=env[2])
|
||||
setattr(t, perm, True)
|
||||
t.save()
|
||||
@@ -442,7 +456,10 @@ def test_correct_event_permission_limited(perf_patch, client, env, perm, url, co
|
||||
session = client.session
|
||||
session['pretix_auth_login_time'] = int(time.time())
|
||||
session.save()
|
||||
response = client.get('/control/event/dummy/dummy/' + url)
|
||||
if http_method and http_method == HTTP_POST:
|
||||
response = client.post('/control/event/dummy/dummy/' + url)
|
||||
else:
|
||||
response = client.get('/control/event/dummy/dummy/' + url)
|
||||
assert response.status_code == code
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user