• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

EsupPortail / Esup-Pod / 25740886384

12 May 2026 02:25PM UTC coverage: 69.122%. First build
25740886384

Pull #1427

github

web-flow
Bump urllib3 from 2.6.3 to 2.7.0 (#1444)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.6.3 to 2.7.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.6.3...2.7.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.7.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #1427: [Release] 4.3.0

173 of 199 new or added lines in 6 files covered. (86.93%)

13203 of 19101 relevant lines covered (69.12%)

0.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.07
/pod/video_encode_transcript/utils.py
1
"""Esup-Pod video encoding and transcripting utilities."""
2

3
import logging
1✔
4
import os
1✔
5
import time
1✔
6

7
import bleach
1✔
8
from django.conf import settings
1✔
9
from django.core.mail import (
1✔
10
    EmailMultiAlternatives,
11
    mail_admins,
12
    mail_managers,
13
    send_mail,
14
)
15
from django.urls import reverse
1✔
16
from django.utils.translation import gettext_lazy as _
1✔
17
from pod.progressive_web_app.utils import notify_user
1✔
18
from pod.video.models import Video
1✔
19

20
from .models import EncodingLog, EncodingStep
1✔
21

22
DEBUG = getattr(settings, "DEBUG", True)
1✔
23
logger = logging.getLogger(__name__)
1✔
24
if DEBUG:
1✔
25
    logger.setLevel(logging.DEBUG)
1✔
26

27
TEMPLATE_VISIBLE_SETTINGS = getattr(
1✔
28
    settings,
29
    "TEMPLATE_VISIBLE_SETTINGS",
30
    {
31
        "TITLE_SITE": "Pod",
32
        "TITLE_ETB": "University name",
33
        "LOGO_SITE": "img/logoPod.svg",
34
        "LOGO_ETB": "img/esup-pod.svg",
35
        "LOGO_PLAYER": "img/pod_favicon.svg",
36
        "LINK_PLAYER": "",
37
        "LINK_PLAYER_NAME": _("Home"),
38
        "FOOTER_TEXT": ("",),
39
        "FAVICON": "img/pod_favicon.svg",
40
        "CSS_OVERRIDE": "",
41
        "PRE_HEADER_TEMPLATE": "",
42
        "POST_FOOTER_TEMPLATE": "",
43
        "TRACKING_TEMPLATE": "",
44
    },
45
)
46

47
__TITLE_SITE__ = (
1✔
48
    TEMPLATE_VISIBLE_SETTINGS["TITLE_SITE"]
49
    if (TEMPLATE_VISIBLE_SETTINGS.get("TITLE_SITE"))
50
    else "Pod"
51
)
52

53
DEFAULT_FROM_EMAIL = getattr(settings, "DEFAULT_FROM_EMAIL", "noreply@univ.fr")
1✔
54
DEFAULT_PLACEHOLDER_EMAIL_HOST = "smtp.univ.fr"
1✔
55
DEFAULT_PLACEHOLDER_ADMINS = (("Name", "adminmail@univ.fr"),)
1✔
56

57
USE_ESTABLISHMENT_FIELD = getattr(settings, "USE_ESTABLISHMENT_FIELD", False)
1✔
58

59
MANAGERS = getattr(settings, "MANAGERS", {})
1✔
60

61
SECURE_SSL_REDIRECT = getattr(settings, "SECURE_SSL_REDIRECT", False)
1✔
62
VIDEOS_DIR = getattr(settings, "VIDEOS_DIR", "videos")
1✔
63

64

65
# ##########################################################################
66
# ENCODE VIDEO: GENERIC FUNCTIONS
67
# ##########################################################################
68

69

70
def change_encoding_step(video_id: int, num_step: int, desc: str) -> None:
1✔
71
    """Change encoding step."""
72
    encoding_step, created = EncodingStep.objects.get_or_create(
1✔
73
        video=Video.objects.get(id=video_id)
74
    )
75
    encoding_step.num_step = num_step
1✔
76
    encoding_step.desc_step = desc[:255]
1✔
77
    encoding_step.save()
1✔
78
    logger.debug("Video: %s - step: %d - desc: %s" % (video_id, num_step, desc))
1✔
79

80

81
def add_encoding_log(video_id, log) -> None:
1✔
82
    """Add message in video_id encoding log."""
83
    encoding_log, created = EncodingLog.objects.get_or_create(
1✔
84
        video=Video.objects.get(id=video_id)
85
    )
86
    if created:
1✔
87
        encoding_log.log = log
1✔
88
    else:
89
        encoding_log.log += "\n\n%s" % log
1✔
90
    encoding_log.save()
1✔
91
    logger.debug(log)
1✔
92

93

94
def check_file(path_file) -> bool:
1✔
95
    """Check if path_file is accessible and is not null."""
96
    if os.access(path_file, os.F_OK) and os.stat(path_file).st_size > 0:
1✔
97
        return True
1✔
98
    return False
1✔
99

100

101
def create_outputdir(video_id, video_path):
1✔
102
    """ENCODE VIDEO: CREATE OUTPUT DIR."""
103
    dirname = os.path.dirname(video_path)
×
104
    output_dir = os.path.join(dirname, "%04d" % video_id)
×
105
    if not os.path.exists(output_dir):
×
106
        os.makedirs(output_dir)
×
107
    return output_dir
×
108

109

110
###############################################################
111
# EMAIL
112
###############################################################
113

114

115
def _admin_failure_emails_are_enabled() -> bool:
1✔
116
    """Return True when admin alert emails should be sent.
117

118
    The project ships with placeholder SMTP/admin settings. When those defaults
119
    are still in place, trying to send a failure email only triggers an
120
    unnecessary SMTP connection attempt.
121
    """
122
    admins = tuple(getattr(settings, "ADMINS", ()) or ())
1✔
123
    if not admins:
1✔
124
        return False
1✔
125
    if admins == DEFAULT_PLACEHOLDER_ADMINS:
1✔
126
        return False
1✔
127

128
    email_host = str(getattr(settings, "EMAIL_HOST", "") or "").strip()
1✔
129
    if not email_host:
1✔
130
        return False
1✔
131
    if email_host == DEFAULT_PLACEHOLDER_EMAIL_HOST:
1✔
NEW
132
        return False
×
133

134
    return True
1✔
135

136

137
def send_email_item(msg, item, item_id) -> None:
1✔
138
    """Send email notification when encoding fails for a specific item."""
139
    if not _admin_failure_emails_are_enabled():
1✔
140
        logger.warning(
1✔
141
            "Skipping admin alert email for %s %s because SMTP/admin email settings are not configured.",
142
            item,
143
            item_id,
144
        )
145
        return
1✔
146

147
    subject = "[" + __TITLE_SITE__ + "] Error Encoding %s id: %s" % (item, item_id)
1✔
148
    message = "Error Encoding %s id: %s\n%s" % (item, item_id, msg)
1✔
149
    html_message = "<p>Error Encoding %s id: %s</p><p>%s</p>" % (
1✔
150
        item,
151
        item_id,
152
        msg.replace("\n", "<br>"),
153
    )
154
    mail_admins(subject, message, fail_silently=False, html_message=html_message)
1✔
155

156

157
def send_email_recording(msg, recording_id) -> None:
1✔
158
    """Send email notification when recording encoding failed."""
159
    send_email_item(msg, "Recording", recording_id)
×
160

161

162
def send_email_encoding(video_to_encode) -> None:
1✔
163
    """Send email on encoding completion."""
164
    subject_prefix = _("Encoding")
1✔
165
    send_notification_email(video_to_encode, subject_prefix)
1✔
166

167

168
def send_notification_encoding(video_to_encode) -> None:
1✔
169
    """Send push notification on encoding completion."""
170
    subject_prefix = _("Encoding")
×
171
    send_notification(video_to_encode, subject_prefix)
×
172

173

174
def send_email(msg, video_id) -> None:
1✔
175
    """Send email notification when video encoding failed."""
176
    send_email_item(msg, "Video", video_id)
1✔
177

178

179
def send_email_transcript(video_to_encode) -> None:
1✔
180
    """Send email on transcripting completion."""
181
    subject_prefix = _("The transcripting of content")
×
182
    send_notification_email(video_to_encode, subject_prefix)
×
183

184

185
def send_notification_email(video_to_encode, subject_prefix) -> None:
1✔
186
    """Send email notification on video encoding or transcripting completion."""
187
    logger.debug("SEND EMAIL ON %s COMPLETION" % subject_prefix.upper())
1✔
188
    url_scheme = "https" if SECURE_SSL_REDIRECT else "http"
1✔
189
    content_url = "%s:%s" % (url_scheme, video_to_encode.get_full_url())
1✔
190
    subject = "[%s] %s" % (
1✔
191
        __TITLE_SITE__,
192
        _("%(subject)s #%(content_id)s completed")
193
        % {"subject": subject_prefix, "content_id": video_to_encode.id},
194
    )
195

196
    html_message = (
1✔
197
        '<p>%s</p><p>%s</p><p>%s<br><a href="%s"><i>%s</i></a>\
198
                </p><p>%s</p>'
199
        % (
200
            _("Hello,"),
201
            _(
202
                "%(content_type)s ā€œ%(content_title)sā€ has been %(action)s"
203
                + ", and is now available on %(site_title)s."
204
            )
205
            % {
206
                "content_type": (
207
                    _("The content")
208
                    if subject_prefix == _("The transcripting of content")
209
                    else _("The video")
210
                ),
211
                "content_title": "<b>%s</b>" % video_to_encode.title,
212
                "action": (
213
                    _("automatically transcripted")
214
                    if (subject_prefix == _("The transcripting of content"))
215
                    else _("encoded to Web formats")
216
                ),
217
                "site_title": __TITLE_SITE__,
218
            },
219
            _("You will find it here:"),
220
            content_url,
221
            content_url,
222
            _("Regards."),
223
        )
224
    )
225

226
    full_html_message = html_message + "<br>%s%s<br>%s%s" % (
1✔
227
        _("Post by:"),
228
        video_to_encode.owner,
229
        _("the:"),
230
        video_to_encode.date_added,
231
    )
232

233
    message = bleach.clean(html_message, tags=[], strip=True)
1✔
234
    full_message = bleach.clean(full_html_message, tags=[], strip=True)
1✔
235

236
    from_email = DEFAULT_FROM_EMAIL
1✔
237
    to_email = []
1✔
238
    to_email.append(video_to_encode.owner.email)
1✔
239

240
    if (
1✔
241
        USE_ESTABLISHMENT_FIELD
242
        and MANAGERS
243
        and video_to_encode.owner.owner.establishment.lower() in dict(MANAGERS)
244
    ):
245
        bcc_email = []
×
246
        video_estab = video_to_encode.owner.owner.establishment.lower()
×
247
        manager = dict(MANAGERS)[video_estab]
×
248
        if isinstance(manager, (list, tuple)):
×
249
            bcc_email = manager
×
250
        elif isinstance(manager, str):
×
251
            bcc_email.append(manager)
×
252
        msg = EmailMultiAlternatives(
×
253
            subject, message, from_email, to_email, bcc=bcc_email
254
        )
255
        msg.attach_alternative(html_message, "text/html")
×
256
        msg.send()
×
257
    else:
258
        mail_managers(
1✔
259
            subject,
260
            full_message,
261
            fail_silently=False,
262
            html_message=full_html_message,
263
        )
264
        if not DEBUG:
1✔
265
            send_mail(
×
266
                subject,
267
                message,
268
                from_email,
269
                to_email,
270
                fail_silently=False,
271
                html_message=html_message,
272
            )
273

274

275
def send_notification(video_to_encode, subject_prefix) -> None:
1✔
276
    """Send push notification on video encoding or transcripting completion."""
277
    subject = "[%s] %s" % (
×
278
        __TITLE_SITE__,
279
        _("%(subject)s #%(content_id)s completed")
280
        % {"subject": subject_prefix, "content_id": video_to_encode.id},
281
    )
282
    message = _(
×
283
        "%(content_type)s ā€œ%(content_title)sā€ has been %(action)s"
284
        + ", and is now available on %(site_title)s."
285
    ) % {
286
        "content_type": (
287
            _("content") if subject_prefix == _("Transcripting") else _("video")
288
        ),
289
        "content_title": video_to_encode.title,
290
        "action": (
291
            _("automatically transcripted")
292
            if (subject_prefix == _("Transcripting"))
293
            else _("encoded to Web formats")
294
        ),
295
        "site_title": __TITLE_SITE__,
296
    }
297

298
    notify_user(
×
299
        video_to_encode.owner,
300
        subject,
301
        message,
302
        url=reverse("video:video", args=(video_to_encode.slug,)),
303
    )
304

305

306
def time_to_seconds(a_time) -> int:
1✔
307
    """Convert a time to seconds."""
308
    seconds = time.strptime(str(a_time), "%H:%M:%S")
1✔
309
    seconds = seconds.tm_sec + seconds.tm_min * 60 + seconds.tm_hour * 3600
1✔
310
    return seconds
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc