--- /dev/null
+# -*- coding: utf-8 -*-
+
+from optparse import make_option
+from django.conf import settings
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import User
+from ...models.core import Conference
+from teleforma.webclass.models import *
+
+
+
+class Command(BaseCommand):
+ help = "Store record id for conferences"
+
+ def handle(self, *args, **options):
+ bbb = BBBServer.objects.get(pk=2).get_instance()
+
+ missing_records = WebclassRecord.objects.filter(record_id__isnull=True, room_id__isnull=False)
+
+ for record in missing_records:
+ recordings = bbb.get_recordings(record.room_id).get_field('recordings')
+ if hasattr(recordings, 'get'):
+ recordings = recordings['recording']
+ if type(recordings) is XMLDictNode:
+ recordings = [recordings]
+ if recordings:
+ # get last session id from the same course
+ record.record_id = recordings[0]['recordID']
+
+ print("Add record id %s for webclass record %s" % (record.record_id, record.id))
+ record.save()
\ No newline at end of file
padding: 0em;
font-weight: bold;
font-size: 1.2em;
- }
-
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+.create-bbb-conference {
+ font-size: 0.8em;
+}
+.bbb-placeholder {
+ width: 100%;
+ height: 116px;
+ background-color: #dfdfdf;
+}
.course_content {
background-color: #FFF;
-moz-border-radius: 8px 0px 8px 8px;
<div class="course">
<div class="course_title">{{ course.title }} - Corrections de copies{% if course.description %} -
{{ course.description }}{% endif %}
+ {% if user.is_staff or user.professor.count %}<a href="{% url 'teleforma-create-cc-bbb-conference' period.id course.id %}" class="create-bbb-conference">Créer une correction de copie</a>{% endif %}
+
</div>
{% block webclass_corrections %}
{% include "webclass/inc/webclass_corrections_list.html" %}
--- /dev/null
+# Generated by Django 3.2.25 on 2025-04-24 16:40
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('webclass', '0009_auto_20250214_1201'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='webclassrecord',
+ name='room_id',
+ field=models.CharField(blank=True, max_length=255, null=True, unique=True, verbose_name='id de la conférence BBB (généré automatiquement)'),
+ ),
+ migrations.AlterField(
+ model_name='webclassrecord',
+ name='record_id',
+ field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Enregistrement BBB'),
+ ),
+ ]
--- /dev/null
+# Generated by Django 3.2.25 on 2025-04-24 16:46
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('teleforma', '0029_merge_0028_auto_20240318_1139_0028_auto_20240415_0414'),
+ ('webclass', '0010_auto_20250424_1640'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='webclassrecord',
+ name='professor',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='webclass_records', to='teleforma.professor', verbose_name='professor'),
+ ),
+ ]
period = models.ForeignKey('teleforma.Period', verbose_name=_('period'), on_delete=models.CASCADE)
course = models.ForeignKey(
'teleforma.Course', related_name='webclass_records', verbose_name=_('course'), on_delete=models.CASCADE)
- record_id = models.CharField("Enregistrement BBB", max_length=255)
+ record_id = models.CharField("Enregistrement BBB", max_length=255, blank=True, null=True)
# not used for now, but may be handy if we need to optimize performance
bbb_server = models.ForeignKey(
'BBBServer', related_name='webclass_records', verbose_name='Serveur BBB', on_delete=models.CASCADE)
created = models.DateTimeField("Date de la conférence", auto_now_add=True)
session = models.CharField(
_('session'), choices=session_choices, max_length=16, blank=True, null=True)
+
+ # Used when conference are created from webclass by teachers to retrive the record id
+ room_id = models.CharField(
+ 'id de la conférence BBB (généré automatiquement)', blank=True, null=True, max_length=255, unique=True)
+ professor = models.ForeignKey('teleforma.Professor', related_name='webclass_records', verbose_name=_('professor'), on_delete=models.SET_NULL, blank=True, null=True)
+
WEBCLASS = 'WC'
CORRECTION = 'CC'
<tr>
<td {% if forloop.first %}class="border-top" {% endif %} style="width:200px">
<a href="{% url 'teleforma-webclass-record' %}?url={{record.url}}" title="{% trans "View" %}">
- <img src="{{ record.preview }}" style="width:176px" alt="{% trans 'Click here' %}" />
- <div>Cliquez-ici</div>
+ {% if record.preview %}
+ <img src="{{ record.preview }}" style="width:176px" alt="{% trans 'Click here' %}" />
+ {% else %}
+ <img src="/static/teleforma/images/play_168.png" class="bbb-placeholder" alt="{% trans 'Click here' %}" />
+ {% endif %}
</a>
</td>
<td {% if forloop.first %}class="border-top" {% endif %} style="padding-left: 1em;">
from ..webclass.views import (WebclassAppointment,
WebclassProfessorAppointments,
- WebclassRecordsFormView, WebclassRecordView,
+ WebclassRecordsFormView, WebclassRecordView, create_cc_bbb_conference,
join_webclass, unregister)
urlpatterns = [
name="teleforma-webclass-unregister"),
url(r'^desk/webclass/(?P<pk>.*)/join/$',
join_webclass,
- name="teleforma-webclass-join")
-
+ name="teleforma-webclass-join"),
+ url(r'^desk/webclass/(?P<period_id>.*)/(?P<course_id>.*)/create_cc_bbb_conference/$',
+ create_cc_bbb_conference,
+ name="teleforma-create-cc-bbb-conference")
]
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.generic import FormView, TemplateView, View
+from bigbluebutton_api_python.exception import BBBException
+
from datetime import datetime
+import string
+import random
+
+from ..models.core import Conference, Course, Professor
from ..decorators import access_required
from ..views.core import get_courses, get_periods
from ..webclass.forms import WebclassRecordsForm
-from ..webclass.models import Webclass, WebclassSlot
+from ..webclass.models import BBBServer, Webclass, WebclassRecord, WebclassSlot
+from django.contrib.auth.models import User
class WebclassProfessorAppointments(TemplateView):
"Votre réservation a été annulé.")
# redirect to register form
return redirect(reverse("teleforma-webclass-appointments", kwargs={'pk':webclass_slot.webclass.id}))
+
+
+
+@access_required
+def create_cc_bbb_conference(request, period_id, course_id):
+ """
+ Join a bbb webclass for "correction de copie" (cc) with a random room id.
+ A cron script will later create a WebclassRecord object.
+ """
+
+ username = request.user.get_full_name()
+ is_professor = len(request.user.professor.all()) >= 1
+ is_staff = request.user.is_staff or request.user.is_superuser
+
+ if not is_professor and not is_staff:
+ raise ValueError("User is not a professor or staff")
+ course = Course.objects.get(pk=course_id)
+
+ year = datetime.now().year
+ bbb = BBBServer.objects.get(pk=2).get_instance()
+ # generate password
+ password = User.objects.make_random_password()
+ # generate random room id
+ room_id = "".join(random.choices(string.ascii_letters + string.digits, k=20))
+
+ params = {
+ 'name': "Conférence %s" % course.title,
+ 'moderatorPW': password,
+ 'attendeePW': "PWATTENDEE",
+ # 'maxParticipants':self.webclass_max_participants + 1,
+ 'welcome': "Pré-Barreau : Bienvenue sur la conférence \"%s\"." % (course.title),
+ 'record': True,
+ 'autoStartRecording':True,
+ 'muteOnStart': True,
+ 'allowModsToUnmuteUsers': True,
+ 'logo':'https://e-learning.crfpa.pre-barreau.com/static/teleforma/images/logo_pb.png',
+ 'copyright': "© %d Pré-Barreau" % year,
+ # 'guestPolicy':'ALWAYS_ACCEPT'
+ 'bannerText': "Pré-Barreau - CRFPA",
+ 'bannerColor': "#003768",
+ # 'customStyleUrl': site_url+"/static/teleforma/css/bbb.css"
+ 'logoutURL': "https://e-learning.ae.pre-barreau.com",
+ 'endWhenNoModerator': True,
+ 'meetingLayout': "VIDEO_FOCUS",
+ "notifyRecordingIsOn": True,
+ }
+
+ meta = {
+ 'origin': 'crfpa',
+ 'periodid': period_id,
+ 'courseid': course_id,
+ 'professorid': request.user.id,
+ 'type': 'cc',
+ }
+
+ try:
+ result = bbb.create_meeting(
+ room_id, params=params, meta=meta)
+ except BBBException as e:
+ print(e)
+ raise
+
+ try:
+ professor = request.user.professor.get()
+ except Professor.DoesNotExist:
+ professor = None
+
+ WebclassRecord.objects.create(
+ room_id=room_id,
+ bbb_server=BBBServer.objects.get(pk=2),
+ period_id=period_id,
+ course_id=course_id,
+ category=WebclassRecord.CORRECTION,
+ professor=professor,
+ )
+
+ params = {'userID': request.user.username}
+ return redirect(bbb.get_join_meeting_url(username, room_id, password, params))