Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement an organizer customer account and fee system | Task management #452

Open
wants to merge 8 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ dependencies = [
'PyJWT~=2.8.0',
'exhibitors @ git+https://github.com/fossasia/eventyay-tickets-exhibitors.git@master',
'pyvat==1.3.18',
'django_celery_beat==2.7.0',
'cron-descriptor==1.4.5'
]

[project.optional-dependencies]
Expand Down
34 changes: 34 additions & 0 deletions src/pretix/control/forms/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from django.utils.functional import cached_property
from django.utils.timezone import get_current_timezone, make_aware, now
from django.utils.translation import gettext, gettext_lazy as _, pgettext_lazy
from django_celery_beat.models import CrontabSchedule

from pretix.base.channels import get_all_sales_channels
from pretix.base.forms.widgets import (
Expand Down Expand Up @@ -1626,3 +1627,36 @@ def __init__(self, *args, **kwargs):
self.fields['subevent'].widget.choices = self.fields['subevent'].choices
elif 'subevent':
del self.fields['subevent']


class TaskFilterForm(forms.Form):
name = forms.CharField(
label=_('Task name'),
required=False,
widget=forms.TextInput(attrs={'placeholder': _('Search task name')})
)
status = forms.ChoiceField(
label=_('Status'),
choices=[
('', _('All')),
('enabled', _('Enabled')),
('disabled', _('Disabled'))
],
required=False
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def filter_qs(self, qs):
fdata = self.cleaned_data

if fdata.get('name'):
qs = qs.filter(name__icontains=fdata.get('name'))

if fdata.get('status') == 'enabled':
qs = qs.filter(enabled=True)
elif fdata.get('status') == 'disabled':
qs = qs.filter(enabled=False)

return qs
6 changes: 6 additions & 0 deletions src/pretix/control/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,12 @@ def get_admin_navigation(request):
'active': 'organizers' in url.url_name,
'icon': 'group',
},
{
'label': _('Task management'),
'url': reverse('control:admin.task_management'),
'active': 'task_management' in url.url_name,
'icon': 'tasks',
},
{
'label': _('Users'),
'url': reverse('control:admin.users'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{% extends "pretixcontrol/admin/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load urlreplace %}
{% load eventurl %}

{% block title %}{% trans "Task management" %}{% endblock %}

{% block content %}
<h1>{% trans "Task management" %}</h1>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans "Filter" %}</h3>
</div>
<div class="panel-body">
<form class="" action="" method="get">
<div class="row filter-form">
<div class="col-md-3 col-sm-6 col-xs-12">
{% bootstrap_field filter_form.name layout='inline' %}
</div>
<div class="col-md-3 col-sm-6 col-xs-12">
{% bootstrap_field filter_form.status layout='inline' %}
</div>
{% for mf in meta_fields %}
<div class="col-md-3 col-sm-6 col-xs-12">
{% bootstrap_field mf layout='inline' %}
</div>
{% endfor %}
</div>
<div class="text-right">
<button class="btn btn-primary" type="submit">
<span class="fa fa-filter"></span>
<span class="hidden-md">{% trans "Filter" %}</span>
</button>
</div>
</form>
</div>
</div>
<div class="table-responsive">
<table class="table table-condensed table-hover table-quotas">
<thead>
<tr>
<th>{% trans "Id" %}</th>
<th>{% trans "Task name" %}</th>
<th>{% trans "Run at" %}</th>
<th>{% trans "Last run at" %}</th>
<th>{% trans "Total run count" %}</th>
<th>{% trans "Enabled" %}</th>
</tr>
</thead>
<tbody>
{% if tasks %}
{% for task in tasks %}
<tr>
<td data-label="{% trans 'Id' %}">
<strong>{{ task.id }}</strong>
</td>
<td data-label="{% trans 'Task name' %}">{{ task.name }}</td>
<td data-label="{% trans 'Run at' %}">{{ task.run_at }}</td>
<td data-label="{% trans 'Last run at' %}">{{ task.formatted_last_run_at }}</td>
<td data-label="{% trans 'Total run count' %}">{{ task.total_run_count }}</td>
<td data-label="{% trans 'Enabled' %}">
<form method="post" action="{% url 'control:admin.task_management' %}" class="task-form">
{% csrf_token %}
<input type="hidden" name="task_id" value="{{ task.id }}">
<input type="hidden" name="enabled" value="{{ task.enabled|lower }}">
<div class="form-check">
<input class="form-check-input task-checkbox"
type="checkbox"
data-form-id="{{ task.id }}"
{% if task.enabled %}checked{% endif %}>
</div>
</form>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="7" class="text-center mt-5">
{% trans "No tasks found." %}
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
{% include "pretixcontrol/pagination.html" %}
{% endblock %}
1 change: 1 addition & 0 deletions src/pretix/control/templates/pretixcontrol/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<script type="text/javascript" src="{% static "are-you-sure/jquery.are-you-sure.js" %}"></script>
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/popover.js" %}"></script>
<script type="text/javascript" src="{% static "utils/js/utils.js" %}"></script>
<script type="text/javascript" src="{% static "task_management/js/task_management.js" %}"></script>
{% endcompress %}
{{ html_head|safe }}

Expand Down
2 changes: 2 additions & 0 deletions src/pretix/control/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@
url(r'^$', admin.AdminDashboard.as_view(), name='admin.dashboard'),
url(r'^organizers/$', admin.OrganizerList.as_view(), name='admin.organizers'),
url(r'^events/$', admin.AdminEventList.as_view(), name='admin.events'),
url(r'^task_management', admin.TaskList.as_view(), name='admin.task_management'),
url(r'^sudo/(?P<id>\d+)/$', user.EditStaffSession.as_view(), name='admin.user.sudo.edit'),
url(r'^sudo/sessions/$', user.StaffSessionList.as_view(), name='admin.user.sudo.list'),
url(r'^users/$', users.UserListView.as_view(), name='admin.users'),
Expand All @@ -346,6 +347,7 @@
url(r'^global/settings/$', global_settings.GlobalSettingsView.as_view(), name='admin.global.settings'),
url(r'^global/update/$', global_settings.UpdateCheckView.as_view(), name='admin.global.update'),
url(r'^global/message/$', global_settings.MessageView.as_view(), name='admin.global.message'),

])),
url(r'^event/(?P<organizer>[^/]+)/$', RedirectView.as_view(pattern_name='control:organizer'), name='event.organizerredirect'),
]
86 changes: 85 additions & 1 deletion src/pretix/control/views/admin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
from zoneinfo import ZoneInfo

from cron_descriptor import Options, get_description
from django.conf import settings
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils.formats import date_format
from django.utils.functional import cached_property
from django.views.generic import ListView, TemplateView
from django_celery_beat.models import PeriodicTask, PeriodicTasks

from pretix.base.models import Organizer
from pretix.control.forms.filter import OrganizerFilterForm
from pretix.control.forms.filter import OrganizerFilterForm, TaskFilterForm
from pretix.control.permissions import AdministratorPermissionRequiredMixin
from pretix.control.views import PaginationMixin
from pretix.control.views.main import EventList
Expand Down Expand Up @@ -43,3 +53,77 @@ def filter_form(self):
class AdminEventList(EventList):
""" Inherit from EventList to add a custom template for the admin event list. """
template_name = 'pretixcontrol/admin/events/index.html'


class TaskList(PaginationMixin, ListView):
template_name = 'pretixcontrol/admin/task_management/task_management.html'
context_object_name = 'tasks'
model = PeriodicTask

@cached_property
def filter_form(self):
return TaskFilterForm(data=self.request.GET)

def get_queryset(self):
queryset = (
super()
.get_queryset()
.exclude(name='celery.backend_cleanup')
.select_related('crontab')
)

if self.filter_form.is_valid():
queryset = self.filter_form.filter_qs(queryset)

return queryset

def process_task_data(self, task):
if task.last_run_at is None:
task.formatted_last_run_at = '-'
else:
local_timezone = ZoneInfo(settings.TIME_ZONE)
task.formatted_last_run_at = date_format(
task.last_run_at.astimezone(local_timezone),
format="M. d, Y, g:i a"
)

task.name = task.name.replace("_", " ").capitalize()

options = Options()
options.locale_code = settings.LANGUAGE_CODE
options.verbose = True
schedule = task.crontab
cron_expression = f"{schedule.minute} {schedule.hour} {schedule.day_of_month} {schedule.month_of_year} {schedule.day_of_week}"
task.run_at = get_description(cron_expression, options)

return task

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

context['tasks'] = [
self.process_task_data(task)
for task in context['tasks']
]

context['filter_form'] = self.filter_form
return context

def post(self, request, *args, **kwargs):
task_id = request.POST.get('task_id')
current_enabled = request.POST.get('enabled') == 'true'

if task_id:
task = get_object_or_404(PeriodicTask, id=task_id)
new_status = not current_enabled

PeriodicTask.objects.filter(id=task_id).update(enabled=new_status)
PeriodicTasks.changed(task)

status_text = 'enabled' if new_status else 'disabled'
messages.success(
self.request,
f'The task {task.name} has been successfully {status_text}.'
)

return HttpResponseRedirect(reverse('control:admin.task_management'))
Loading
Loading