Skip to content

Commit

Permalink
Add online video link to menu (#150)
Browse files Browse the repository at this point in the history
* send invitation for additional speaker input

* add join video button without token

* remove not related file

* update token for video join button

* rework feature add join video on menu

* fix pipeline isort/black

---------

Co-authored-by: Mario Behling <[email protected]>
Co-authored-by: lcduong <[email protected]>
  • Loading branch information
3 people authored Sep 29, 2024
1 parent 149d206 commit 7c659da
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 27 deletions.
103 changes: 81 additions & 22 deletions src/pretalx/agenda/templates/agenda/header_row.html
Original file line number Diff line number Diff line change
@@ -1,30 +1,88 @@
{% load i18n %}
{% load static %}
{% load compress %}

<nav id="schedule-nav"{% if with_margin %} class="p-3"{% endif %}>
<div class="navigation">
<a href="{{ request.event.urls.schedule }}" class="btn btn-outline-success {% if "/schedule/" in request.path %} active{% endif %}">
<i class="fa fa-calendar"></i> {% translate "Schedule" %}
</a>
{% if request.event.display_settings.schedule_display != "list" %}
<a href="{{ request.event.urls.talks }}" class="btn btn-outline-success {% if "/talk/" in request.path %} active{% endif %}">
<i class="fa fa-comments-o"></i> {% translate "Sessions" %}
</a>
{% endif %}
<a href="{{ request.event.urls.speakers }}" class="btn btn-outline-success {% if "/speaker/" in request.path %} active{% endif %}">
<i class="fa fa-group"></i> {% translate "Speakers" %}
</a>
{% if request.event.display_settings.ticket_link %}
<a href="{{ request.event.display_settings.ticket_link }}" class="btn btn-outline-success">
<i class="fa fa-ticket"></i> {% translate "Tickets" %}
</a>
{% endif %}
</div>
<div class="header-right">
{% block agenda_header_row %}
{% compress js %}
<script src="{% static "jquery/js/jquery-3.7.1.min.js" %}"></script>
<script src="{% static "agenda/js/join-online-event.js" %}"></script>
{% endcompress %}
{% endblock %}

{% block agenda_content %}
<div id="join-video-popupmodal" hidden aria-live="polite">
<div class="modal-card">
<div class="modal-card-content-join">
<div>
<h3>
{% trans "This is a ticketed event. If you ordered a ticket as a guest user, you don't have an account but can still access the ticket using the secret link in your ticket confirmation email. On the tickets page there is also a link to join online sessions." %}
</h3>
<h3>
{% trans "As a ticket holder please also check your email for the unique link to join online sessions." %}
</h3>
<p class="text">
{% trans "Can't find your ticket?" %}
<a id="resend_link" class="btn btn-default" href='{{ request.event.display_settings.ticket_link }}resend'>
{% trans "Resend the email" %}
</a>
{% trans "to receive it." %}
</p>
<p class="text">
{% trans "Want to order a ticket?" %}
<a id="ticket_link" class="btn btn-default" href='{{ request.event.display_settings.ticket_link }}'>
{% trans "Get a ticket here" %}
</a>
</p>
</div>
</div>
<div class="join-online-close">
<button id="join-online-close-button" class="btn btn-default join-online-close-button">Close</button>
</div>
</div>
</div>
<div id="join-video-popupmodal-missing-config" hidden aria-live="polite">
<div class="modal-card">
<div class="modal-card-content-join">
<div>
<h3>
{% trans "Some configurations is missing for video setting, please contact organizer." %}
</h3>
</div>
</div>
<div class="join-online-close">
<button id="join-online-close-button-missing-config" class="btn btn-default join-online-close-button">Close</button>
</div>
</div>
</div>
<nav id="schedule-nav"{% if with_margin %} class="p-3"{% endif %}>
<div class="navigation">
<a href="{{ request.event.urls.schedule }}" class="btn btn-outline-success {% if "/schedule/" in request.path %} active{% endif %}">
<i class="fa fa-calendar"></i> {% translate "Schedule" %}
</a>
{% if request.event.display_settings.schedule_display != "list" %}
<a href="{{ request.event.urls.talks }}" class="btn btn-outline-success {% if "/talk/" in request.path %} active{% endif %}">
<i class="fa fa-comments-o"></i> {% translate "Sessions" %}
</a>
{% endif %}
<a href="{{ request.event.urls.speakers }}" class="btn btn-outline-success {% if "/speaker/" in request.path %} active{% endif %}">
<i class="fa fa-group"></i> {% translate "Speakers" %}
</a>
{% if request.event.display_settings.ticket_link %}
<a href="{{ request.event.display_settings.ticket_link }}" class="btn btn-outline-success">
<i class="fa fa-group"></i> {% translate "Tickets" %}
</a>
{% endif %}

<a id="join-event-link" href='{% url "agenda:event.onlinevideo.join" event=request.event.slug %}' class="btn btn-outline-success">
<i class="fa fa-video-camera"></i> {% translate "Videos" %}
</a>
</div>
<div class="header-right">
{% if with_extra %}
<span>{% translate "Version" %} <a href="{{ request.event.urls.changelog }}">{{ schedule.version|default:"–" }}</a></span>
<details class="dropdown">
<summary class="btn btn-sm btn-outline-info">
<i class="fa fa-calendar-plus-o"></i>
<i class="fa fa-calendar-plus-o"></i>
<span class="calendar-text"> Add to Calendar </span>
<i class="fa fa-caret-down"></i>
</summary>
Expand Down Expand Up @@ -70,4 +128,5 @@
</details>
{% endif %}
</div>
</nav>
</nav>
{% endblock %}
5 changes: 5 additions & 0 deletions src/pretalx/agenda/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ def get_schedule_urls(regex_prefix, name_prefix=""):
EventSocialMediaCard.as_view(),
name="event-social",
),
path(
"online-video/join/",
talk.OnlineVideoJoin.as_view(),
name="event.onlinevideo.join",
),
]
),
),
Expand Down
103 changes: 100 additions & 3 deletions src/pretalx/agenda/views/talk.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
from urllib.parse import urlparse
import datetime as dt
from urllib.parse import unquote, urlparse

import jwt
import requests
import vobject
from django.conf import settings
from django.contrib import messages
from django.db.models import Q
from django.http import Http404, HttpResponse
from django.http import Http404, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, render
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from django.views import View
from django.views.generic import DetailView, FormView, TemplateView
from django_context_decorator import context

from pretalx.agenda.signals import register_recording_provider
from pretalx.cfp.views.event import EventPageMixin
from pretalx.common.mixins.views import PermissionRequired, SocialMediaCardMixin
from pretalx.common.mixins.views import (
EventPermissionRequired,
PermissionRequired,
SocialMediaCardMixin,
)
from pretalx.common.text.phrases import phrases
from pretalx.schedule.models import Schedule, TalkSlot
from pretalx.submission.forms import FeedbackForm
Expand Down Expand Up @@ -264,3 +272,92 @@ def get_success_url(self):
class TalkSocialMediaCard(SocialMediaCardMixin, TalkView):
def get_image(self):
return self.get_object().image


class OnlineVideoJoin(EventPermissionRequired, View):
permission_required = "agenda.view_schedule"

def get(self, request, *args, **kwargs):
# First check video is configured or not
if (
"pretalx_venueless" not in request.event.plugin_list
or not request.event.venueless_settings
or not request.event.venueless_settings.join_url
or not request.event.venueless_settings.secret
or not request.event.venueless_settings.issuer
or not request.event.venueless_settings.audience
):
return HttpResponse(status=403, content="missing_configuration")

if not request.user.is_authenticated:
# redirect to login page if user not logged in yet
return HttpResponse(status=403, content="user_not_allowed")

# prepare event data to check from ticket
if "ticket_link" not in request.event.display_settings:
return HttpResponse(status=403, content="missing_configuration")

base_url, organizer, event = self.retrieve_info_from_url(
request.event.display_settings["ticket_link"]
)

if not organizer or not event or not base_url:
return HttpResponse(status=403, content="missing_configuration")

# call to ticket to check if user order ticket yet or not
response = requests.get(
f"{base_url}/api/v1/{organizer}/{event}/customer/{request.user.code}/ticket-check"
)

if response.status_code != 200:
return HttpResponse(status=403, content="user_not_allowed")

else:
# Redirect user to online event
iat = dt.datetime.utcnow()
exp = iat + dt.timedelta(days=30)
profile = {
"display_name": request.user.name,
"fields": {
"pretalx_id": request.user.code,
},
}
if request.user.avatar_url:
profile["profile_picture"] = request.user.get_avatar_url(request.event)

payload = {
"iss": request.event.venueless_settings.issuer,
"aud": request.event.venueless_settings.audience,
"exp": exp,
"iat": iat,
"uid": request.user.code,
"profile": profile,
"traits": list(
{
f"eventyay-video-event-{request.event.slug}",
}
),
}
token = jwt.encode(
payload, request.event.venueless_settings.secret, algorithm="HS256"
)

return JsonResponse(
{
"redirect_url": "{}/#token={}".format(
request.event.venueless_settings.join_url, token
).replace("//#", "/#")
},
status=200,
)

def retrieve_info_from_url(self, url):
parsed_url = urlparse(url)
ticket_host = settings.EVENTYAY_TICKET_BASE_PATH
path = parsed_url.path
parts = path.strip("/").split("/")
if len(parts) >= 2:
organizer, event = parts[-2:]
return ticket_host, unquote(organizer), unquote(event)
else:
return ticket_host, None, None
9 changes: 9 additions & 0 deletions src/pretalx/orga/forms/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ class EventForm(ReadOnlyFlag, I18nHelpText, JsonSubfieldMixin, I18nModelForm):
),
required=False,
)
video_link = forms.URLField(
label=_("Video Live URL"),
help_text=("Online video link will be shown on event menu."),
widget=forms.TextInput(
attrs={"placeholder": " e.g: https://app.eventyay.com/video"}
),
required=False,
)
header_pattern = forms.ChoiceField(
label=_("Frontpage header pattern"),
help_text=_(
Expand Down Expand Up @@ -369,6 +377,7 @@ class Meta:
"export_html_on_release": "feature_flags",
"html_export_url": "display_settings",
"ticket_link": "display_settings",
"video_link": "display_settings",
"header_pattern": "display_settings",
"meta_noindex": "display_settings",
}
Expand Down
1 change: 1 addition & 0 deletions src/pretalx/orga/templates/orga/settings/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ <h2>{% translate "Settings" %}</h2>
{% bootstrap_field form.html_export_url layout='event' %}
{% bootstrap_field form.meta_noindex layout='event' %}
{% bootstrap_field form.ticket_link layout='event' %}
{% bootstrap_field form.video_link layout='event' %}

</fieldset>
<fieldset>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% extends "./base.html" %}
{% extends "socialaccount/base.html" %}
{% load bootstrap4 %}
{% load compress %}
{% load i18n %}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% extends "./base.html" %}
{% extends "socialaccount/base.html" %}
{% load bootstrap4 %}
{% load compress %}
{% load i18n %}
Expand Down
41 changes: 41 additions & 0 deletions src/pretalx/static/agenda/js/join-online-event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
$(function () {
var popup_window = null
var popup_check_interval = null

$("#join-event-link").on("click", function (e) {
e.preventDefault(); // prevent the default action (redirecting to the href)
var url = $(this).attr('href'); // get the href attribute
$.ajax({
"method": "GET",
"url": url,
"success": function(json) {
if(json.redirect_url) {
window.location.href = json.redirect_url;
}
},
"error": function(jqXHR, textStatus, errorThrown) {
// handle any errors that occur while making the AJAX request
$("body").addClass("has-join-popup")
if(jqXHR.responseText === 'user_not_allowed') {
// handle 'user_not_allowed' error
$("body").addClass("has-join-popup")
$("#join-video-popupmodal").removeAttr("hidden");
} else if (jqXHR.responseText === 'missing_configuration'){
// handle other errors
$("body").addClass("has-join-popup")
$("#join-video-popupmodal-missing-config").removeAttr("hidden");

}
}
});
});
$('#join-online-close-button').click(function() {
$('#join-video-popupmodal').attr('hidden', 'true');
$("body").removeClass("has-join-popup")
});
$('#join-online-close-button-missing-config').click(function() {
$('#join-video-popupmodal-missing-config').attr('hidden', 'true');
$("body").removeClass("has-join-popup")
});
})

Loading

0 comments on commit 7c659da

Please sign in to comment.