Skip to content

Commit 4220ae9

Browse files
committed
Squashed commit of the following:
commit 3251cfd Author: github-actions <[email protected]> Date: Thu Jan 25 09:47:54 2024 +0000 Fixup. Format code with Prettier commit 9a492e4 Author: pampletousse <[email protected]> Date: Thu Jan 25 10:47:32 2024 +0100 [DONE] Pampletousse/feature download qrcode (EsupPortail#1015) * Add download button for qr code + fix border red too big * Mutualize qrcode generation and display between video and live(event) * Add same template modification to live event * Try to mutualize qr code generation between video and event * Add event slug to downloaded file name * éAdd alternative text to parameters * PEP8 conformity * Fix PEP8 E303 blank line * Fix PEP8 F811 * Uniformize QR code designation * Generate translations for QR Code managment * éAdd types into functions and doc + normalize id in template * Fix translations * Fix translation video into event in event-info template * Delete fuzzy translations * Add return types on functions in register tags (video and event) * Add quotes for alt in qr code img tag --------- Co-authored-by: pampletousse <[email protected]>
1 parent 86cf95b commit 4220ae9

File tree

10 files changed

+192
-68
lines changed

10 files changed

+192
-68
lines changed

pod/live/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs):
139139
def qrcode(self, obj):
140140
return obj.qrcode
141141

142-
qrcode.short_description = _("QR Code")
142+
qrcode.short_description = _("QR code")
143143
qrcode.allow_tags = True
144144

145145
class Media:

pod/live/models.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
"""Esup-Pod "live" models."""
2-
import base64
32
import hashlib
4-
import io
5-
import qrcode
63
import os
74

85
from ckeditor.fields import RichTextField
@@ -21,12 +18,12 @@
2118
from django.urls import reverse
2219
from django.utils import timezone
2320
from django.utils.html import format_html
24-
from django.utils.safestring import mark_safe
2521
from django.utils.translation import ugettext_lazy as _
2622

2723
from pod.main.lang_settings import ALL_LANG_CHOICES as __ALL_LANG_CHOICES__
2824
from pod.main.lang_settings import PREF_LANG_CHOICES as __PREF_LANG_CHOICES__
2925
from django.utils.translation import get_language
26+
from pod.main.utils import generate_qrcode
3027
from pod.authentication.models import AccessGroup
3128
from pod.main.models import get_nextautoincrement
3229
from pod.video.models import Video, Type
@@ -272,25 +269,8 @@ def is_recording_admin(self):
272269

273270
@property
274271
def qrcode(self, request=None):
275-
url_scheme = "https" if SECURE_SSL_REDIRECT else "http"
276-
url_immediate_event = reverse("live:event_immediate_edit", args={self.id})
277-
data = "".join(
278-
[
279-
url_scheme,
280-
"://",
281-
get_current_site(request).domain,
282-
url_immediate_event,
283-
]
284-
)
285-
img = qrcode.make(data)
286-
buffer = io.BytesIO()
287-
img.save(buffer, format="PNG")
288-
img_str = base64.b64encode(buffer.getvalue()).decode("utf-8")
289272
alt = _("QR code to record immediately an event")
290-
return mark_safe(
291-
f'<img src="data:image/png;base64, {img_str}" '
292-
+ f'width="300px" height="300px" alt={alt}>'
293-
)
273+
return generate_qrcode("live:event_immediate_edit", self.id, alt, request)
294274

295275
def set_broadcaster_file(self, filename):
296276
trans_folder = os.path.join(MEDIA_ROOT, LIVE_TRANSCRIPTIONS_FOLDER)

pod/live/templates/live/event-info.html

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{% load static %}
33
{% load tagging_tags %}
44
{% load thumbnail %}
5+
{% load event_tags %}
56

67
<div class="tab-content w-100" id="video-meta">
78
{% if event.description %}
@@ -58,7 +59,7 @@ <h3 class="meta-title">{% trans 'Type:' %}</h3>
5859
</div>
5960

6061
{% if event.is_draft == False or event.owner == request.user or request.user in event.additional_owners.all or request.user.is_superuser %} <!-- Début modale -->
61-
<div class="modal fade" id="share" tabindex="-1" aria-labelledby="shareLabel" aria-hidden="true" {% if event.is_draft %}style="border:1px solid red"{% endif %}>
62+
<div class="modal fade" id="share" tabindex="-1" aria-labelledby="shareLabel" aria-hidden="true">
6263
<div class="modal-dialog">
6364
<div class="modal-content">
6465
<div class="modal-header">
@@ -70,7 +71,7 @@ <h2 class="modal-title h5" id="shareLabel">
7071
<div class="modal-body">
7172

7273
{% if event.is_draft %}
73-
<div class="card text-white bg-danger mb-3">
74+
<div class="card text-white border-danger mb-3">
7475
<div class="card-body">
7576
{% blocktrans %}Please note that your event is in draft mode.<br>The following links contain a key allowing access. Anyone with this links can access it.{% endblocktrans %}
7677
</div>
@@ -117,17 +118,16 @@ <h2 class="modal-title h5" id="shareLabel">
117118
<fieldset class="pod-share-fieldset">
118119
<legend><i class="bi bi-link-45deg" aria-hidden="true"></i>&nbsp;{% trans 'Share the link' %}</legend>
119120
<div class="form-group">
120-
<label for="txtpartage">{% trans 'Use this link to share the video:' %}</label>
121+
<label for="txtpartage">{% trans 'Use this link to share the event:' %}</label>
121122
<input class="form-control" type="text" name="txtpartage" id="txtpartage" value="{% if request.is_secure %}https{% else %}http{% endif %}://{{ request.META.HTTP_HOST }}{% url 'live:event' slug=event.slug %}{% if event.is_draft == True %}{{ event.get_hashkey }}/{% endif %}">
122123
</div>
123-
<div class="form-group">
124-
<label>{% trans 'QR code for this link:' %}&nbsp;
125-
<a href="#" class="btn pod-btn pod-btn-social m-1" title="{% trans 'Warning, it use google API' %}" role="button" data-bs-toggle="collapse" data-bs-target="#qrcode" aria-expanded="false" aria-controls="qrcode">
126-
<i class="bi bi-eye" aria-hidden="true"></i>
127-
</a>
128-
</label>
129-
<img src="//chart.apis.google.com/chart?cht=qr&amp;chs=200x200&amp;chl={% if request.is_secure %}https{% else %}http{% endif %}://{{ request.META.HTTP_HOST }}{% url 'live:event' slug=event.slug %}{% if event.is_draft == True %}{{ event.get_hashkey }}/{% endif %}" alt="qrcode" id="qrcode" loading="lazy">
130-
</div>
124+
<div class="form-group m-2">
125+
{% get_event_qrcode event.id as qrcode %}
126+
<label>{% trans 'QR code for this link:' %}&nbsp;</label><br>
127+
{{ qrcode }}
128+
<br>
129+
<button id="btn-download-qr-code" type="submit" data-slug="{{ event.slug }}" class="btn btn-primary my-2" title="{% trans 'Download this QR code' %}">{% trans 'Download' %}</button>
130+
</div>
131131
</fieldset>
132132
</div> <!-- End modal body-->
133133
</div> <!-- End modal content-->

pod/live/templatetags/event_tags.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from django.template.defaultfilters import register
22
from django.utils import timezone
33

4+
from django.utils.translation import ugettext_lazy as _
45
from pod.live.models import Event
56
from pod.live.views import can_manage_event
7+
from pod.main.utils import generate_qrcode
68

79

810
@register.simple_tag(takes_context=True)
@@ -23,3 +25,18 @@ def get_next_events(context, broadcaster_id=None, limit_nb=4):
2325
@register.filter
2426
def can_manage_event_filter(user):
2527
return can_manage_event(user)
28+
29+
30+
@register.simple_tag(name="get_event_qrcode")
31+
def get_event_qrcode(event_id: int) -> str:
32+
"""Get the event generated QR code.
33+
34+
Args:
35+
event_id (int): Identifier of event object
36+
37+
Returns:
38+
string: HTML-formed generated qrcode
39+
40+
"""
41+
alt = _("QR code event's link")
42+
return generate_qrcode("live:event_immediate_edit", event_id, alt)

pod/locale/fr/LC_MESSAGES/django.po

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3035,8 +3035,8 @@ msgid "QR code to record immediately an event"
30353035
msgstr "QR code pour la programmation d’un évènement immédiat"
30363036

30373037
#: pod/live/admin.py
3038-
msgid "QR Code"
3039-
msgstr "QR Code"
3038+
msgid "QR code"
3039+
msgstr "QR code"
30403040

30413041
#: pod/live/admin.py pod/live/models.py pod/recorder/models.py
30423042
#: pod/video/models.py
@@ -3661,9 +3661,8 @@ msgid "Share the link"
36613661
msgstr "Partager le lien"
36623662

36633663
#: pod/live/templates/live/event-info.html
3664-
#: pod/video/templates/videos/video-info.html
3665-
msgid "Use this link to share the video:"
3666-
msgstr "Utiliser ce lien pour partager la vidéo :"
3664+
msgid "Use this link to share the event:"
3665+
msgstr "Utiliser ce lien pour partager l'évènement :"
36673666

36683667
#: pod/live/templates/live/event-info.html
36693668
#: pod/video/templates/videos/video-info.html
@@ -3672,8 +3671,14 @@ msgstr "QR code pour le lien :"
36723671

36733672
#: pod/live/templates/live/event-info.html
36743673
#: pod/video/templates/videos/video-info.html
3675-
msgid "Warning, it use google API"
3676-
msgstr "Attention, utilise une API Google"
3674+
msgid "Download this QR code"
3675+
msgstr "Télécharger ce QR code"
3676+
3677+
#: pod/live/templates/live/event-info.html
3678+
#: pod/podfile/templates/podfile/list_folder_files.html
3679+
#: pod/video/templates/videos/video-info.html
3680+
msgid "Download"
3681+
msgstr "Télécharger"
36773682

36783683
#: pod/live/templates/live/event-script.html
36793684
msgid "Recording not done: "
@@ -3948,6 +3953,10 @@ msgstr "Évènements à venir"
39483953
msgid "Past events"
39493954
msgstr "Évènements passés"
39503955

3956+
#: pod/live/templatetags/event_tags.py
3957+
msgid "QR code event's link:"
3958+
msgstr "QR code pour le lien de l'évènement :"
3959+
39513960
#: pod/live/utils.py
39523961
#, python-format
39533962
msgid "Registration of event #%(content_id)s"
@@ -4823,7 +4832,7 @@ msgstr ""
48234832
"droite, mode sombre ou dyslexie etc.), gérer la session (authentification) "
48244833
"et analyser le trafic du site (pour certaines instances)."
48254834

4826-
#: pod/main/templates/base.html
4835+
#: pod/main/templates/base.html pod/video/templates/videos/add_video.html
48274836
msgid "Learn more"
48284837
msgstr "En savoir plus"
48294838

@@ -6572,10 +6581,6 @@ msgstr "Partager le dossier « %(folder_name)s » avec un autre utilisateur"
65726581
msgid "Upload Files"
65736582
msgstr "Téléverser des fichiers"
65746583

6575-
#: pod/podfile/templates/podfile/list_folder_files.html
6576-
msgid "Download"
6577-
msgstr "Télécharger"
6578-
65796584
#: pod/podfile/templates/podfile/list_folder_files.html
65806585
msgid "Delete file"
65816586
msgstr "Supprimer le fichier"
@@ -8411,8 +8416,8 @@ msgstr ""
84118416
"interactive H5P :"
84128417

84138418
#: pod/video/templates/videos/video-info.html
8414-
msgid "QR code"
8415-
msgstr "QR code"
8419+
msgid "Use this link to share the video:"
8420+
msgstr "Utiliser ce lien pour partager la vidéo :"
84168421

84178422
#: pod/video/templates/videos/video_collaborate.html
84188423
msgid "Collaborate"
@@ -8606,6 +8611,10 @@ msgstr "Afficher les statistiques de visualisation de toutes les vidéos"
86068611
msgid ": "
86078612
msgstr " : "
86088613

8614+
#: pod/video/templatetags/video_tags.py
8615+
msgid "QR code video's link:"
8616+
msgstr "QR code pour le lien de la vidéo :"
8617+
86098618
#: pod/video/templatetags/video_tags.py
86108619
msgid "This content is not password protected."
86118620
msgstr "Ce contenu n'est pas protégé par un mot de passe."

pod/locale/nl/LC_MESSAGES/django.po

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2843,7 +2843,7 @@ msgid "QR code to record immediately an event"
28432843
msgstr ""
28442844

28452845
#: pod/live/admin.py
2846-
msgid "QR Code"
2846+
msgid "QR code"
28472847
msgstr ""
28482848

28492849
#: pod/live/admin.py pod/live/models.py pod/recorder/models.py
@@ -3428,8 +3428,7 @@ msgid "Share the link"
34283428
msgstr ""
34293429

34303430
#: pod/live/templates/live/event-info.html
3431-
#: pod/video/templates/videos/video-info.html
3432-
msgid "Use this link to share the video:"
3431+
msgid "Use this link to share the event:"
34333432
msgstr ""
34343433

34353434
#: pod/live/templates/live/event-info.html
@@ -3439,7 +3438,13 @@ msgstr ""
34393438

34403439
#: pod/live/templates/live/event-info.html
34413440
#: pod/video/templates/videos/video-info.html
3442-
msgid "Warning, it use google API"
3441+
msgid "Download this QR code"
3442+
msgstr ""
3443+
3444+
#: pod/live/templates/live/event-info.html
3445+
#: pod/podfile/templates/podfile/list_folder_files.html
3446+
#: pod/video/templates/videos/video-info.html
3447+
msgid "Download"
34433448
msgstr ""
34443449

34453450
#: pod/live/templates/live/event-script.html
@@ -3702,6 +3707,10 @@ msgstr ""
37023707
msgid "Past events"
37033708
msgstr ""
37043709

3710+
#: pod/live/templatetags/event_tags.py
3711+
msgid "QR code event's link"
3712+
msgstr ""
3713+
37053714
#: pod/live/utils.py
37063715
#, python-format
37073716
msgid "Registration of event #%(content_id)s"
@@ -4567,7 +4576,7 @@ msgid ""
45674576
"analyze site traffic."
45684577
msgstr ""
45694578

4570-
#: pod/main/templates/base.html
4579+
#: pod/main/templates/base.html pod/video/templates/videos/add_video.html
45714580
msgid "Learn more"
45724581
msgstr ""
45734582

@@ -6209,10 +6218,6 @@ msgstr ""
62096218
msgid "Upload Files"
62106219
msgstr ""
62116220

6212-
#: pod/podfile/templates/podfile/list_folder_files.html
6213-
msgid "Download"
6214-
msgstr ""
6215-
62166221
#: pod/podfile/templates/podfile/list_folder_files.html
62176222
msgid "Delete file"
62186223
msgstr ""
@@ -7896,7 +7901,7 @@ msgid ""
78967901
msgstr ""
78977902

78987903
#: pod/video/templates/videos/video-info.html
7899-
msgid "QR code"
7904+
msgid "Use this link to share the video:"
79007905
msgstr ""
79017906

79027907
#: pod/video/templates/videos/video_collaborate.html
@@ -7935,6 +7940,25 @@ msgstr ""
79357940
msgid "Add a new video"
79367941
msgstr ""
79377942

7943+
#: pod/video/templates/videos/video_edit.html
7944+
#, python-format
7945+
msgid ""
7946+
"\n"
7947+
" By default, the deletion date of your video is set to "
7948+
"%(counter)s year, in accordance with your profile. As a teacher, you can "
7949+
"modify this date. If you are a student and wish to extend this period, add a "
7950+
"teacher as an additional video owner\n"
7951+
" "
7952+
msgid_plural ""
7953+
"\n"
7954+
" By default, the deletion date of your video is set to "
7955+
"%(counter)s years, in accordance with your profile. As a teacher, you can "
7956+
"modify this date. If you are a student and wish to extend this period, add a "
7957+
"teacher as an additional video owner\n"
7958+
" "
7959+
msgstr[0] ""
7960+
msgstr[1] ""
7961+
79387962
#: pod/video/templates/videos/video_edit.html
79397963
#: pod/video/templates/videos/video_page_content.html
79407964
msgid "The video is currently waiting for encoding."
@@ -8085,6 +8109,10 @@ msgstr ""
80858109
msgid ": "
80868110
msgstr ""
80878111

8112+
#: pod/video/templatetags/video_tags.py
8113+
msgid "QR code video's link"
8114+
msgstr ""
8115+
80888116
#: pod/video/templatetags/video_tags.py
80898117
msgid "This content is not password protected."
80908118
msgstr ""

pod/main/static/js/main.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,38 @@ document.addEventListener("hidden.bs.collapse", (e) => {
300300
if (e.target.id === "qrcode") e.target.setAttribute("src", "");
301301
});
302302

303+
if (document.getElementById("btn-download-qr-code") !== null) {
304+
document
305+
.getElementById("btn-download-qr-code")
306+
.addEventListener("click", (e) => {
307+
let nameOfDownload = e.target.dataset.slug + "-qrcode.png";
308+
downloadImage(document.getElementById("qrcode").src, nameOfDownload);
309+
});
310+
}
311+
312+
/**
313+
* Download image function with url
314+
*
315+
* @param imageSrc Source of image
316+
* @param nameOfDownload Given name for download
317+
* @returns {Promise<void>}
318+
*/
319+
async function downloadImage(imageSrc, nameOfDownload = "default.png") {
320+
const response = await fetch(imageSrc);
321+
const blobImage = await response.blob();
322+
const href = URL.createObjectURL(blobImage);
323+
324+
const anchorElement = document.createElement("a");
325+
anchorElement.href = href;
326+
anchorElement.download = nameOfDownload;
327+
328+
document.body.appendChild(anchorElement);
329+
anchorElement.click();
330+
331+
document.body.removeChild(anchorElement);
332+
window.URL.revokeObjectURL(href);
333+
}
334+
303335
document.addEventListener("change", (e) => {
304336
if (e.target.id !== "displaytime") return;
305337
let displayTime = document.getElementById("displaytime");

0 commit comments

Comments
 (0)