Skip to content

Commit c361ed5

Browse files
authored
Eventyay Common: Create an event dashboard (#505)
* Add dashboard eventyay common * Add custom css * Change background * Add component link for eventyay_common * Update css style * Fix isort * Add custom style * Add alert pop up, add line break * Resolve conversation: update template url * Refactor code eventyay_common * Refactor context and navigation * Add missing url return * Fix css error * Update tickets text * Resolve conversations * Fix isort warning * Update modal * Fix urljoin
1 parent 9efdd17 commit c361ed5

File tree

16 files changed

+801
-135
lines changed

16 files changed

+801
-135
lines changed

src/pretix/control/templates/pretixcontrol/event/component_link.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{% load i18n %}
22
<div class="navigation-button">
33
{% if request.organizer and request.event %}
4-
<a href='{% url "eventyay_common:event.update" organizer=request.organizer.slug event=request.event.slug %}' class="header-nav btn btn-outline-success">
4+
<a href='{% url "eventyay_common:event.index" organizer=request.organizer.slug event=request.event.slug %}' class="header-nav btn btn-outline-success">
55
<i class="fa fa-home"></i> {% trans "Home" %}
66
</a>
77
<a href="#" class="header-nav btn btn-outline-success active">
88
<i class="fa fa-ticket"></i> {% trans "Tickets" %}
99
</a>
1010
{% if is_talk_event_created %}
11-
<a href="{{ talk_edit_url }}" class="header-nav btn btn-outline-success">
11+
<a href="{{ request.event.talk_dashboard_url }}" class="header-nav btn btn-outline-success">
1212
<i class="fa fa-group"></i> {% trans "Talk" %}
1313
</a>
1414
{% endif %}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
{% load i18n %}
2-
<div class="panel-heading">
3-
<h3 class="panel-title">
4-
{% trans "Event organizer" %}
5-
</h3>
6-
</div>
7-
<div class="panel-body timeline">
8-
<div class="info-row">
9-
{% trans "This event is organized by" %} <strong><a href="{% url 'control:organizer' request.organizer.slug %}">{{ request.organizer }}</a></strong>
2+
<div class="panel panel-default items widget-container widget-small no-padding last-column">
3+
<div class="panel-heading">
4+
<h3 class="panel-title">
5+
{% trans "Event organizer" %}
6+
</h3>
107
</div>
11-
<div class="info-row">
12-
{% trans "Teams of the organizer are" %}
13-
<span></span>
14-
{% for id, name in organizer_teams %}
15-
<strong><a href="{% url 'control:organizer.team' request.organizer.slug id %}">{{ name }}</a></strong>
16-
{% if not forloop.last %}, {% endif %}
17-
{% endfor %}
8+
<div class="panel-body timeline overide-panel-body">
9+
<div class="info-row">
10+
{% trans "This event is organized by" %} <strong><a href="{% url 'control:organizer' request.organizer.slug %}">{{ request.organizer }}</a></strong>
11+
</div>
12+
<div class="info-row">
13+
{% trans "Teams of the organizer are" %}
14+
<span></span>
15+
{% for id, name in organizer_teams %}
16+
<strong><a href="{% url 'control:organizer.team' request.organizer.slug id %}">{{ name }}</a></strong>
17+
{% if not forloop.last %}, {% endif %}
18+
{% endfor %}
19+
</div>
1820
</div>
1921
</div>
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,36 @@
11
{% load i18n %}
2-
<div class="panel-heading">
3-
<h3 class="panel-title">
4-
{% trans "Your timeline" %}
5-
</h3>
6-
</div>
7-
<div class="panel-body timeline">
8-
{% regroup timeline by date as tl_list %}
9-
{% for day in tl_list %}
10-
<div class="row {% if day.grouper < today %}text-muted{% endif %}">
11-
<div class="col-date">
12-
<strong>{{ day.grouper|date:"SHORT_DATE_FORMAT" }}</strong>
13-
</div>
14-
<div class="col-event">
15-
{% for e in day.list %}
16-
<strong class="">{{ e.time|date:"TIME_FORMAT" }}</strong>
17-
&nbsp;
18-
<span class="{% if e.time < nearly_now %}text-muted{% endif %}">
19-
{{ e.entry.description }}
20-
</span>
21-
{% if e.entry.edit_url %}
2+
<div class="panel panel-default items widget-container widget-small no-padding column">
3+
<div class="panel-heading">
4+
<h3 class="panel-title">
5+
{% trans "Your timeline" %}
6+
</h3>
7+
</div>
8+
<div class="panel-body timeline overide-panel-body">
9+
{% regroup timeline by date as tl_list %}
10+
{% for day in tl_list %}
11+
<div class="row {% if day.grouper < today %}text-muted{% endif %}">
12+
<div class="col-date">
13+
<strong>{{ day.grouper|date:"SHORT_DATE_FORMAT" }}</strong>
14+
</div>
15+
<div class="col-event">
16+
{% for e in day.list %}
17+
<strong class="">{{ e.time|date:"TIME_FORMAT" }}</strong>
2218
&nbsp;
23-
<a href="{{ e.entry.edit_url }}" class="text-muted">
24-
<span class="fa fa-edit"></span>
25-
</a>
26-
{% endif %}
27-
{% if forloop.revcounter > 1 %}
28-
<br/>
29-
{% endif %}
30-
{% endfor %}
19+
<span class="{% if e.time < nearly_now %}text-muted{% endif %}">
20+
{{ e.entry.description }}
21+
</span>
22+
{% if e.entry.edit_url %}
23+
&nbsp;
24+
<a href="{{ e.entry.edit_url }}" class="text-muted">
25+
<span class="fa fa-edit"></span>
26+
</a>
27+
{% endif %}
28+
{% if forloop.revcounter > 1 %}
29+
<br/>
30+
{% endif %}
31+
{% endfor %}
32+
</div>
3133
</div>
32-
</div>
33-
{% endfor %}
34+
{% endfor %}
35+
</div>
3436
</div>

src/pretix/control/templates/pretixcontrol/event/index.html

+2-6
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,9 @@ <h3 class="panel-title">
110110
{% endif %}
111111
<div class="dashboard custom">
112112
{% if not request.event.has_subevents or subevent %}
113-
<div class="panel panel-default items widget-container widget-small no-padding column"">
114-
{% include "pretixcontrol/event/fragment_timeline.html" %}
115-
</div>
113+
{% include "pretixcontrol/event/fragment_timeline.html" %}
116114
{% endif %}
117-
<div class="panel panel-default items widget-container widget-small no-padding last-column"">
118-
{% include "pretixcontrol/event/fragment_info_box.html" %}
119-
</div>
115+
{% include "pretixcontrol/event/fragment_info_box.html" %}
120116
</div>
121117
<div class="dashboard">
122118
{% for w in widgets %}

src/pretix/eventyay_common/context.py

+93-71
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,120 @@
1-
from importlib import import_module
1+
import logging
2+
from urllib.parse import urljoin
23

34
from django.conf import settings
45
from django.db.models import Q
5-
from django.urls import Resolver404, get_script_prefix, resolve, reverse
6-
from django.utils.translation import gettext_lazy as _
6+
from django.http import HttpRequest
7+
from django.urls import Resolver404, get_script_prefix, resolve
8+
from django_scopes import scope
79

810
from pretix.base.models.auth import StaffSession
911
from pretix.base.settings import GlobalSettingsObject
10-
from pretix.control.navigation import merge_in
11-
from pretix.control.signals import nav_global
12+
from pretix.eventyay_common.navigation import (
13+
get_event_navigation, get_global_navigation,
14+
)
1215

13-
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
16+
from ..helpers.plugin_enable import is_video_enabled
17+
from ..multidomain.urlreverse import get_event_domain
18+
from .views.event import EventCreatedFor
1419

20+
logger = logging.getLogger(__name__)
1521

16-
def contextprocessor(request):
17-
"""
18-
Adds data to all template contexts
19-
"""
20-
if not hasattr(request, '_eventyay_common_default_context'):
22+
23+
def contextprocessor(request: HttpRequest):
24+
if not hasattr(request, "_eventyay_common_default_context"):
2125
request._eventyay_common_default_context = _default_context(request)
2226
return request._eventyay_common_default_context
2327

2428

25-
def _default_context(request):
29+
def _default_context(request: HttpRequest):
2630
try:
2731
url = resolve(request.path_info)
2832
except Resolver404:
2933
return {}
3034

31-
if not request.path.startswith(get_script_prefix() + 'common'):
35+
if not request.path.startswith(f"{get_script_prefix()}common"):
3236
return {}
3337
ctx = {
34-
'url_name': url.url_name,
35-
'settings': settings,
36-
'django_settings': settings,
37-
'DEBUG': settings.DEBUG,
38+
"url_name": url.url_name,
39+
"settings": settings,
40+
"django_settings": settings,
41+
"DEBUG": settings.DEBUG,
42+
"talk_hostname": settings.TALK_HOSTNAME,
3843
}
39-
if getattr(request, 'event', None) and hasattr(request, 'organizer') and request.user.is_authenticated:
40-
ctx['nav_items'] = get_global_navigation(request)
41-
42-
elif request.user.is_authenticated:
43-
ctx['nav_items'] = get_global_navigation(request)
4444

4545
gs = GlobalSettingsObject()
46-
ctx['global_settings'] = gs.settings
47-
48-
if request.user.is_authenticated:
49-
ctx['staff_session'] = request.user.has_active_staff_session(request.session.session_key)
50-
ctx['staff_need_to_explain'] = (
51-
StaffSession.objects.filter(user=request.user, date_end__isnull=False).filter(
52-
Q(comment__isnull=True) | Q(comment="")
46+
ctx["global_settings"] = gs.settings
47+
48+
if not request.user.is_authenticated:
49+
return ctx
50+
51+
ctx["nav_items"] = get_global_navigation(request)
52+
ctx["staff_session"] = request.user.has_active_staff_session(
53+
request.session.session_key
54+
)
55+
ctx["staff_need_to_explain"] = (
56+
StaffSession.objects.filter(user=request.user, date_end__isnull=False).filter(
57+
Q(comment__isnull=True) | Q(comment="")
58+
)
59+
if request.user.is_staff and settings.PRETIX_ADMIN_AUDIT_COMMENTS
60+
else StaffSession.objects.none()
61+
)
62+
63+
# Verify if the request includes an event
64+
event = getattr(request, "event", None)
65+
if not event:
66+
return ctx
67+
68+
ctx["talk_edit_url"] = urljoin(settings.TALK_HOSTNAME, f"orga/event/{event.slug}")
69+
ctx["is_video_enabled"] = is_video_enabled(event)
70+
ctx["is_talk_event_created"] = False
71+
if (
72+
event.settings.create_for == EventCreatedFor.BOTH.value
73+
or event.settings.talk_schedule_public is not None
74+
):
75+
ctx["is_talk_event_created"] = True
76+
77+
# Verify if the request includes an organizer
78+
organizer = getattr(request, "organizer", None)
79+
if not organizer:
80+
return ctx
81+
82+
ctx["nav_items"] = get_event_navigation(request, event)
83+
ctx["has_domain"] = get_event_domain(event, fallback=True) is not None
84+
if not event.testmode:
85+
with scope(organizer=organizer):
86+
complain_testmode_orders = event.cache.get("complain_testmode_orders")
87+
if complain_testmode_orders is None:
88+
complain_testmode_orders = event.orders.filter(testmode=True).exists()
89+
event.cache.set(
90+
"complain_testmode_orders", complain_testmode_orders, 30
91+
)
92+
ctx["complain_testmode_orders"] = (
93+
complain_testmode_orders
94+
and request.user.has_event_permission(
95+
organizer, event, "can_view_orders", request=request
5396
)
54-
if request.user.is_staff and settings.PRETIX_ADMIN_AUDIT_COMMENTS else StaffSession.objects.none()
5597
)
56-
57-
ctx['talk_hostname'] = settings.TALK_HOSTNAME
98+
else:
99+
ctx["complain_testmode_orders"] = False
100+
101+
if not event.live and ctx["has_domain"]:
102+
child_sess_key = f"child_session_{event.pk}"
103+
child_sess = request.session.get(child_sess_key)
104+
105+
if not child_sess:
106+
request.session[child_sess_key] = request.session.session_key
107+
else:
108+
ctx["new_session"] = child_sess
109+
request.session["event_access"] = True
110+
111+
if request.GET.get("subevent", ""):
112+
subevent_id = request.GET.get("subevent", "").strip()
113+
try:
114+
pk = int(subevent_id)
115+
# Do not use .get() for lazy evaluation
116+
ctx["selected_subevents"] = event.subevents.filter(pk=pk)
117+
except ValueError as e:
118+
logger.error("Error parsing subevent ID: %s", e)
58119

59120
return ctx
60-
61-
62-
def get_global_navigation(request):
63-
url = request.resolver_match
64-
if not url:
65-
return []
66-
nav = [
67-
{
68-
'label': _('Dashboard'),
69-
'url': reverse('eventyay_common:dashboard'),
70-
'active': (url.url_name == 'dashboard'),
71-
'icon': 'dashboard',
72-
},
73-
{
74-
'label': _('My Events'),
75-
'url': reverse('eventyay_common:events'),
76-
'active': 'events' in url.url_name,
77-
'icon': 'calendar',
78-
},
79-
{
80-
'label': _('Organizers'),
81-
'url': reverse('eventyay_common:organizers'),
82-
'active': 'organizers' in url.url_name,
83-
'icon': 'group',
84-
},
85-
{
86-
'label': _('Account'),
87-
'url': reverse('eventyay_common:account'),
88-
'active': 'account' in url.url_name,
89-
'icon': 'user',
90-
}
91-
92-
]
93-
94-
merge_in(nav, sorted(
95-
sum((list(a[1]) for a in nav_global.send(request, request=request)), []),
96-
key=lambda r: (1 if r.get('parent') else 0, r['label'])
97-
))
98-
return nav

0 commit comments

Comments
 (0)