Skip to content

Commit

Permalink
[DONE] Feature: Webinar management in the meetings module (#1092)
Browse files Browse the repository at this point in the history
* Delete useless templates (replaced by pod/live/templates/meeting/meeting_live_form.html)

* Delete useless code for webinar chat and monitoring

* Manages the sending of messages for live webinars

* Add webinar parameters: USE_MEETING_WEBINAR, MEETING_WEBINAR_SIPMEDIAGW_URL, MEETING_WEBINAR_SIPMEDIAGW_TOKEN, MEETING_WEBINAR_FIELDS, MEETING_WEBINAR_AFFILIATION, MEETING_WEBINAR_GROUP_ADMIN

* Manage USE_MEETING_WEBINAR parameter

* Add configuration needed to test webinars

* Add webinars fields, LivestreamAdmin and IngesterAdmin classes

* Manage webinars fields and rules

* Add webinars fields, Livestream and Ingester classes

* Add 2 CSS classes for meeting card

* Add actions buttons to manage a webinar (restart a live, stop a live, stop webinar (meeting and live))

* Manage webinars (no reccurrence available, guest policy = Always accept...)

* Manage webinars, add webinar actions buttons, display correction

* Add some webinars tests

* Add URLs for manage webinars

* Code reordering

* Manages webinars views and refactor some code

* Add filter aside for meeting

* Add webinar utils tests

* Management of webinars for the Meeting module and SIPMediaGW API

* Utils to manage webinars for Meeting module

* Manages the sending of messages for live webinars (eplace pod/live/templates/bbb/bbb_form.html)

* Add REST meeting views

* Add REST meeting views

* Add needed translations to manage webinars

* Modify translations to manage webinars

* Add REST meeting views

* Use d-none class

* Manage spaces and label for textarea

* Add a line at the end of the file

* Modify translations

* Changes in Pydoc

* Remove useless spaces

* Remove useless spaces

* Correct show_chat init

* [DONE] Add a submit button on the add video page (#1088)

* Add a submit button on the add video page, to let user choose if he want to upload or not, and have more time to choose transcription lang
+ Add a required checkbox for legal notice

* undo typo in previous commit

* Replace deprecated `docker-compose` (v1) by `docker compose` (v2)
+ php code formatting

* Compiled .mo files

* Minor corrections

* add required star on legal notice checkbox

* Auto-update configuration files

* Close p before ol

* Remove show_chat parameter

* Remove show_chat parameter

* Modify translations (replace ingester by live gateway) to manage webinars

* Remove show_chat parameter

* Add LiveGateway route

* Remove show_chat parameter and replace ingester by live gateway

* Add LiveGateway route

* Remove show_chat parameter

* Replace ingester by live gateway to test webinars

* Remove show_chat parameter and replace ingester by live gateway

* Merge translations

* Merge

---------

Co-authored-by: Olivier Bado-Faustin <bado@unice.fr>
Co-authored-by: github-actions <github-actions@github.com>
  • Loading branch information
3 people authored Apr 12, 2024
1 parent a49094e commit 8f66ae9
Show file tree
Hide file tree
Showing 32 changed files with 2,952 additions and 465 deletions.
23 changes: 0 additions & 23 deletions pod/live/templates/bbb/bbb_form.html

This file was deleted.

41 changes: 0 additions & 41 deletions pod/live/templates/live/direct.html
Original file line number Diff line number Diff line change
Expand Up @@ -259,46 +259,5 @@ <h2 class="card-title pod-card__title h4">
if ($("#divvideoplayer")) { $("#divvideoplayer").css("display", "block"); }
})
</script>
{% if display_chat %}
<script>
// Send question for BBB live
$(document).ready(function () {
$('.send-message').click(function (e) {
e.preventDefault();
var message = $('#message').val();
$.ajax
({
type: "GET",
url: "{% url 'bbb:live_publish_chat' id=broadcaster.id %}",
data: { "message": message },
success: function (data) {
$('#live_bbb_chat_form')[0].reset();
if (data.is_sent) {
// message_sent
displayReturnMessage("info", data.message_return);
} else {
// error_no_broadcaster_found: Message not sent: no broadcaster found
// error_no_connection: Message not sent: no connection to REDIS
displayReturnMessage("error", data.message_return);
}
}
});
});
});
function displayReturnMessage(level, returnCode) {
let returnMessage = "";
if (level == "info"){
$("#message_return").attr('class', 'alert alert-info');
} else {
$("#message_return").attr('class', 'alert alert-warning');
}
if (returnCode == "message_sent") { returnMessage = "{% trans 'Message sent' %}";}
if (returnCode == "error_no_broadcaster_found") { returnMessage = "{% trans 'Message not sent: no broadcaster found' %}";}
if (returnCode == "error_no_connection") { returnMessage = "{% trans 'Message not sent: connection problem (REDIS)' %}";}
$("#message_return").html(returnMessage);
$("#message_return").show("slow").delay(3000).hide("slow");
}
</script>
{% endif %}

{% endblock more_script %}
122 changes: 61 additions & 61 deletions pod/live/templates/live/event-script.html
Original file line number Diff line number Diff line change
Expand Up @@ -684,69 +684,69 @@
{% endif %}
}

// BBB message sending
{% if display_chat %}
function displayReturnMessage(level, returnCode) {
let toReturn = "";
let returnElement = document.getElementById("message_return");
if (level === "info") {
returnElement.classList.add('alert');
returnElement.classList.add('alert-info');
} else {
returnElement.classList.add('alert');
returnElement.classList.add('alert-warning');
}
if (returnCode === "message_sent") {
toReturn = "{% trans 'Message sent' %}";
}
if (returnCode === "error_no_broadcaster_found") {
toReturn = "{% trans 'Message not sent: no broadcaster found' %}";
}
if (returnCode === "error_no_connection") {
toReturn = "{% trans 'Message not sent: connection problem (REDIS)' %}";
}

returnElement.innerHTML = toReturn;
returnElement.style.display = "block";
setTimeout(function() {
returnElement.style.display = "none";
}, 3000)
}
// Webinar message sending
{% if enable_chat %}
/**
* Display if message was sent, or not, to the server.
*/
function displayReturnMessage(level, returnCode) {
let toReturn = "";
let returnElement = document.getElementById("message_return");
if (level === "info") {
returnElement.classList.add('alert', 'alert-info');
} else {
returnElement.classList.add('alert', 'alert-danger');
}
if (returnCode === "message_sent") {
toReturn = "{% trans 'Message sent' %}";
}
if (returnCode === "error") {
toReturn = "{% trans 'Message not sent' %}";
}

function sendBBBMessage(e) {
e.preventDefault();
let message = document.getElementById("message").value;
fetch("{% url 'bbb:live_publish_chat' id=event.broadcaster.id %}", {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
"X-CSRFToken": '{{ csrf_token }}'
},
body: JSON.stringify({"message": message}),
}).then((response) => {
if (response.ok)
return response.json();
else
return Promise.reject(response);
}).then((data) => {
document.getElementById('live_bbb_chat_form').reset();
if (data.is_sent) {
// message_sent
displayReturnMessage("info", data.message_return);
} else {
// error_no_broadcaster_found: Message not sent: no broadcaster found
// error_no_connection: Message not sent: no connection to REDIS
displayReturnMessage("error", data.message_return);
}
}).catch((error) => {
console.log("{% trans 'Error calling' %} 'sendBBBMessage' " + error);
});
}
returnElement.innerHTML = toReturn;
returnElement.classList.remove("d-none");
setTimeout(function() {
returnElement.classList.add("d-none");
}, 3000)
}

/**
* Send a message to a webinar live.
* */
function sendWebinarMessage(e) {
e.preventDefault();
let message = document.getElementById("message").value;
fetch("{% url 'meeting:live_publish_chat' id=event.id %}", {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
"X-CSRFToken": '{{ csrf_token }}'
},
body: JSON.stringify({"message": message}),
}).then((response) => {
if (response.ok)
return response.json();
else
return Promise.reject(response);
}).then((data) => {
document.getElementById('live_meeting_chat_form').reset();
console.info(data);
if (data.res) {
// Message_sent
displayReturnMessage("info", data.message_return);
} else {
displayReturnMessage("error", data.message_return);
}
}).catch((error) => {
console.log("{% trans 'Error calling' %} 'sendWebinarMessage' " + error);
});
}

document.getElementById('bbb-send-message').onclick = function ($this) {
sendBBBMessage($this);
};
document.getElementById('webinar-send-message').onclick = function ($this) {
sendWebinarMessage($this);
};

{% endif %}

Expand Down
4 changes: 2 additions & 2 deletions pod/live/templates/live/event.html
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ <h1 class="h2" id="livename" data-eventid="{{ event.id }}"><i class="bi bi-broad
</iframe>
{% endif %}

{% if USE_BBB and USE_BBB_LIVE and display_chat %}
{% include "bbb/bbb_form.html" %}
{% if USE_MEETING and USE_MEETING_WEBINAR and enable_chat %}
{% include "meeting/meeting_live_form.html" %}
{% endif %}

<div id="viewers-list"><ul id="viewers-ul"></ul></div>
Expand Down
27 changes: 27 additions & 0 deletions pod/live/templates/meeting/meeting_live_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% load i18n %}

<div id="container-fluid" class="tab-pane fade active show pod-live-info">
<div class="row">
<h2>{% trans 'Send message' %}</h2>
{% if user.is_authenticated %}
<form method="post" action="" id="live_meeting_chat_form">
{% csrf_token %}
<div class="form-group">
<p>
{% trans 'You can send a message to the webinar presenters (100 characters maximum).' %}
{% trans 'It will be displayed after 10 to 30 seconds on the live stream.' %}
</p>
<label class="col-form-label" for="message">{% trans "Message" %}</label>
<textarea name="message" rows="2" cols="70" maxlength="100" class="form-control" id="message"></textarea>
</div>

<div id="message_return" style="float:right; width:30%"></div>

<br><button type="submit" id="webinar-send-message" class="btn btn-primary">{% trans 'Submit' %}</button>
</form>
{% else %}
<div class="form-group">{% trans 'You must be authenticated to send a message.' %}</div>
{% endif %}
</div>
</div>
<div id="container-fluid" class="tab-pane fade active show pod-live-info"></div>
30 changes: 11 additions & 19 deletions pod/live/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
from pod.meeting.models import Livestream
from rest_framework import status

from pod.bbb.models import Livestream
from .forms import EventPasswordForm, EventForm, EventDeleteForm, EventImmediateForm
from .models import (
Building,
Expand All @@ -55,8 +54,8 @@

HEARTBEAT_DELAY = getattr(settings, "HEARTBEAT_DELAY", 45)

USE_BBB = getattr(settings, "USE_BBB", False)
USE_BBB_LIVE = getattr(settings, "USE_BBB_LIVE", False)
USE_MEETING = getattr(settings, "USE_MEETING", False)
USE_MEETING_WEBINAR = getattr(settings, "USE_MEETING_WEBINAR", False)

DEFAULT_EVENT_PATH = getattr(settings, "DEFAULT_EVENT_PATH", "")
DEFAULT_EVENT_THUMBNAIL = getattr(
Expand Down Expand Up @@ -124,18 +123,11 @@ def direct(request, slug):
"%s?%sreferrer=%s"
% (settings.LOGIN_URL, iframe_param, request.get_full_path())
)
# Search if broadcaster is used to display a BBB streaming live
# for which students can send message from this live page
display_chat = False
if USE_BBB and USE_BBB_LIVE:
livestreams_list = Livestream.objects.filter(broadcaster_id=broadcaster.id)
for livestream in livestreams_list:
display_chat = livestream.enable_chat

return render(
request,
"live/direct.html",
{
"display_chat": display_chat,
"display_event_btn": can_manage_event(request.user),
"broadcaster": broadcaster,
"heartbeat_delay": HEARTBEAT_DELAY,
Expand Down Expand Up @@ -340,20 +332,20 @@ def render_event_template(request, evemnt, user_owns_event):
},
)

# Search if broadcaster is used to display a BBB streaming live
# Search if livestream is used to display a webinar streaming live
# for which students can send message from this live page
display_chat = False
if USE_BBB and USE_BBB_LIVE:
livestreams_list = Livestream.objects.filter(broadcaster_id=evemnt.broadcaster_id)
for livestream in livestreams_list:
display_chat = livestream.enable_chat
enable_chat = False
if USE_MEETING and USE_MEETING_WEBINAR:
livestream = Livestream.objects.filter(event=evemnt).first()
if livestream:
enable_chat = livestream.meeting.enable_chat

return render(
request,
template_event,
{
"event": evemnt,
"display_chat": display_chat,
"enable_chat": enable_chat,
"can_record": (
user_owns_event
and evemnt.broadcaster.piloting_implementation
Expand Down
Binary file modified pod/locale/fr/LC_MESSAGES/django.mo
Binary file not shown.
Loading

0 comments on commit 8f66ae9

Please sign in to comment.