Skip to content

Commit

Permalink
Merge pull request #863 from EsupPortail/develop
Browse files Browse the repository at this point in the history
#3.3.0

- Import external video from url, youtube, peertube and BigBlueButton
- Change xapi actor to deal with Moodle
- Update template to BS5.3 and improve compliance for W3C
- Use redis to cache session and improve logging
- refactor of encoding/transcripting to move it in separate application
- Fixbug on categories, recorder, user liste, tags cloud
  • Loading branch information
ptitloup committed Jun 20, 2023
2 parents 705905e + a704ace commit 1b27faa
Show file tree
Hide file tree
Showing 249 changed files with 9,287 additions and 4,786 deletions.
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[report]
# Here you can exclude a file from coverage testing

# nb : you can also add a "# pragma: no cover"
# nb: you can also add a "# pragma: no cover"
# on each function you don't want to be covered
[run]
source = pod/
Expand Down
5 changes: 5 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Before sending your pull request, make sure the following are done :

* [ ] You have read our [contribution guidelines](https://github.com/EsupPortail/Esup-Pod/blob/master/CONTRIBUTING.md).
* [ ] Your PR targets the `develop` branch.
* [ ] The title of your PR starts with `[WIP]` or `[DONE]`.
68 changes: 48 additions & 20 deletions CONFIGURATION_FR.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
## Information générale


La plateforme Esup-Pod se base sur le framework Django écrit en Python.<br/>
Elle supporte les versions 3.7, 3.8 et 3.9 de Python.<br/>
La plateforme Esup-Pod se base sur le framework Django écrit en Python.<br>
Elle supporte les versions 3.7, 3.8 et 3.9 de Python.<br>

**Django Version : 3.2 LTS**<br/>
**Django Version : 3.2 LTS**<br>

> La documentation complète du framework : [https://docs.djangoproject.com/fr/3.2/]() (ou [https://docs.djangoproject.com/en/3.2/]())<br><br/>
> L’ensemble des variables de configuration du framework est accessible à cette adresse : [https://docs.djangoproject.com/fr/3.2/ref/settings/]()<br/>
> La documentation complète du framework : [https://docs.djangoproject.com/fr/3.2/]() (ou [https://docs.djangoproject.com/en/3.2/]())<br><br>
> L’ensemble des variables de configuration du framework est accessible à cette adresse : [https://docs.djangoproject.com/fr/3.2/ref/settings/]()<br>
Voici les configurations des applications tierces utilisées par Esup-Pod.<br/>
Voici les configurations des applications tierces utilisées par Esup-Pod.<br>


- `CAS`
Expand Down Expand Up @@ -440,8 +440,8 @@ Voici les configurations des applications tierces utilisées par Esup-Pod.<br/>
>> Répertoire par défaut pour le téléversement des vidéos. <br>

### Langue
Par défaut, Esup-Pod est fournie en Francais et en anglais.<br/>
Vous pouvez tout à fait rajouter des langues comme vous le souhaitez. Il faudra pour cela créer un fichier de langue et traduire chaque entrée.<br/>
Par défaut, Esup-Pod est fournie en Francais et en anglais.<br>
Vous pouvez tout à fait rajouter des langues comme vous le souhaitez. Il faudra pour cela créer un fichier de langue et traduire chaque entrée.<br>

- `LANGUAGES`

Expand Down Expand Up @@ -1388,6 +1388,22 @@ Vous pouvez tout à fait rajouter des langues comme vous le souhaitez. Il faudra
### Configuration application enrichment
### Configuration application d'import vidéo
Application Import_video permettant d'importer des vidéos externes dans Pod.<br>
Mettre `USE_IMPORT_VIDEO` à True pour activer cette application.<br>
- `RESTRICT_EDIT_IMPORT_VIDEO_ACCESS_TO_STAFF_ONLY`
> valeur par défaut : `True`
>> Seuls les utilisateurs "staff" pourront importer des vidéos <br>
- `USE_IMPORT_VIDEO`
> valeur par défaut : `True`
>> Activation de l’application d'import des vidéos <br>
### Configuration application live
- `AFFILIATION_EVENT`
Expand Down Expand Up @@ -1552,6 +1568,12 @@ Vous pouvez tout à fait rajouter des langues comme vous le souhaitez. Il faudra
>> Utilisation du système de diffusion de Webinaires en lien avec BigBlueButton - [TODO] À retirer dans les futures versions de Pod <br>
- `USE_IMPORT_VIDEO`
> valeur par défaut : `True`
>> Activation de l’application d'import des vidéos <br>
- `USE_MEETING`
> valeur par défaut : `False`
Expand All @@ -1570,11 +1592,17 @@ Vous pouvez tout à fait rajouter des langues comme vous le souhaitez. Il faudra
>> Version courante du projet <br>
- `HOMEPAGE_VIEW_VIDEOS_FROM_NON_VISIBLE_CHANNELS`
> valeur par défaut : `False`
>> Affiche les vidéos de chaines non visibles sur la page d'accueil <br>
### Configuration application meeting
Application Meeting pour la gestion de reunion avec BBB.<br/>
Mettre `USE_MEETING` à True pour activer cette application.<br/>
`BBB_API_URL` et `BBB_SECRET_KEY` sont obligatoires pour faire fonctionner l’application<br/>
Application Meeting pour la gestion de reunion avec BBB.<br>
Mettre `USE_MEETING` à True pour activer cette application.<br>
`BBB_API_URL` et `BBB_SECRET_KEY` sont obligatoires pour faire fonctionner l’application<br>
- `BBB_API_URL`
Expand Down Expand Up @@ -2173,19 +2201,19 @@ Mettre `USE_MEETING` à True pour activer cette application.<br/>
>> Vous pouvez créer des catégories pour pouvoir ranger vos propres vidéos. <br>
>> Les catégories sont liées à l’utilisateur. <br>
- `USE_FAVORITES`
> valeur par défaut : `True`
>> Activation des vidéos favorites. Permet aux utilisateurs d'ajouter des vidéos dans leurs favoris. <br>
- `USE_OBSOLESCENCE`
> valeur par défaut : `False`
>> Activation de l’obsolescence des video. Permet d’afficher la date de suppression de la video <br>
>> dans le formulaire d’edition et dans la partie admin. <br>
- `USE_FAVORITES`
> valeur par défaut : `True`
>> Activation des vidéos favorites. Permet aux utilisateurs d'ajouter des vidéos dans leurs favoris. <br>
- `USE_STATS_VIEW`
> valeur par défaut : `False`
Expand Down Expand Up @@ -2600,9 +2628,9 @@ Mettre `USE_MEETING` à True pour activer cette application.<br/>
### Configuration application xapi
Application pour l’envoi d‘instructions xAPI à un LRS.<br/>
Aucune instruction ne persiste dans Pod, elles sont toutes envoyées au LRS paramétré.<br/>
Attention, il faut configurer Celery pour l’envoi des instructions.<br/>
Application pour l’envoi d‘instructions xAPI à un LRS.<br>
Aucune instruction ne persiste dans Pod, elles sont toutes envoyées au LRS paramétré.<br>
Attention, il faut configurer Celery pour l’envoi des instructions.<br>
- `USE_XAPI`
Expand Down
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ The process described here has several goals:
Please follow these steps to have your contribution considered by the maintainers:

0. Follow the [styleguides](#styleguides) below.
1. After you submit your pull request, verify that all [status checks](https://help.github.com/articles/about-status-checks/) are passing <details><summary>What if the status checks are failing?</summary>If a status check is failing, and you believe that the failure is unrelated to your change, please leave a comment on the pull request explaining why you believe the failure is unrelated. A maintainer will re-run the status check for you. If we conclude that the failure was a false positive, then we will open an issue to track that problem with our status check suite.</details>
1. Make sure that your pull request targets the `develop` branch.
2. Prefix the title of your pull request with one of the following :
* `[WIP]` if your pull request is still a work in progress.
* `[DONE]` if you are done with your patch.
3. After you submit your pull request, verify that all [status checks](https://help.github.com/articles/about-status-checks/) are passing <details><summary>What if the status checks are failing?</summary>If a status check is failing, and you believe that the failure is unrelated to your change, please leave a comment on the pull request explaining why you believe the failure is unrelated. A maintainer will re-run the status check for you. If we conclude that the failure was a false positive, then we will open an issue to track that problem with our status check suite.</details>

While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.

Expand Down
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ createDB:
find . -path "*/migrations/*.pyc" -delete
make updatedb
make migrate
python3 manage.py loaddata pod/video/fixtures/initial_data.json
python3 manage.py loaddata pod/main/fixtures/initial_data.json
python3 manage.py loaddata initial_data

# Mise à jour des fichiers de langue
lang:
Expand Down
2 changes: 2 additions & 0 deletions pod/authentication/apps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.apps import AppConfig
from django.db.models.signals import post_migrate
from django.core.exceptions import ObjectDoesNotExist
from django.utils.translation import gettext_lazy as _


def create_groupsite_if_not_exists(g):
Expand Down Expand Up @@ -33,6 +34,7 @@ def set_default_site(sender, **kwargs):
class AuthConfig(AppConfig):
name = "pod.authentication"
default_auto_field = "django.db.models.BigAutoField"
verbose_name = _("Authentication")

def ready(self):
post_migrate.connect(set_default_site, sender=self)
77 changes: 26 additions & 51 deletions pod/authentication/populatedCASbackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def get_ldap_conn():
logger.error("LDAPBindError, credentials incorrect: {0}".format(err))
return None
except LDAPSocketOpenError as err:
logger.error("LDAPSocketOpenError : %s" % err)
logger.error("LDAPSocketOpenError: %s" % err)
return None


Expand Down Expand Up @@ -206,61 +206,36 @@ def create_accessgroups(user, tree_or_entry, auth_type):
assign_accessgroups(groups_element, user)


def get_entry_value(entry, attribute, default):
"""Retrieve the value of the given attribute from the LDAP entry."""
if (
USER_LDAP_MAPPING_ATTRIBUTES.get(attribute)
and entry[USER_LDAP_MAPPING_ATTRIBUTES[attribute]]
):
if attribute == "last_name" and isinstance(
entry[USER_LDAP_MAPPING_ATTRIBUTES[attribute]].value, list
):
return entry[USER_LDAP_MAPPING_ATTRIBUTES[attribute]].value[0]
elif attribute == "affiliations":
return entry[USER_LDAP_MAPPING_ATTRIBUTES[attribute]].values
else:
return entry[USER_LDAP_MAPPING_ATTRIBUTES[attribute]].value
else:
return default


def populate_user_from_entry(user, owner, entry):
"""Populate user and owner objects from the LDAP entry."""
if DEBUG:
print(entry)
user.email = (
entry[USER_LDAP_MAPPING_ATTRIBUTES["mail"]].value
if (
USER_LDAP_MAPPING_ATTRIBUTES.get("mail")
and entry[USER_LDAP_MAPPING_ATTRIBUTES["mail"]]
)
else ""
)
user.first_name = (
entry[USER_LDAP_MAPPING_ATTRIBUTES["first_name"]].value
if (
USER_LDAP_MAPPING_ATTRIBUTES.get("first_name")
and entry[USER_LDAP_MAPPING_ATTRIBUTES["first_name"]]
)
else ""
)
user.last_name = ""
if (
USER_LDAP_MAPPING_ATTRIBUTES.get("last_name")
and entry[USER_LDAP_MAPPING_ATTRIBUTES["last_name"]]
):
user.last_name = (
entry[USER_LDAP_MAPPING_ATTRIBUTES["last_name"]].value[0]
if (isinstance(entry[USER_LDAP_MAPPING_ATTRIBUTES["last_name"]].value, list))
else entry[USER_LDAP_MAPPING_ATTRIBUTES["last_name"]].value
)
user.email = get_entry_value(entry, "mail", "")
user.first_name = get_entry_value(entry, "first_name", "")
user.last_name = get_entry_value(entry, "last_name", "")
user.save()
owner.affiliation = (
entry[USER_LDAP_MAPPING_ATTRIBUTES["primaryAffiliation"]].value
if (
USER_LDAP_MAPPING_ATTRIBUTES.get("primaryAffiliation")
and entry[USER_LDAP_MAPPING_ATTRIBUTES["primaryAffiliation"]]
)
else DEFAULT_AFFILIATION
)
owner.establishment = (
entry[USER_LDAP_MAPPING_ATTRIBUTES["establishment"]].value
if (
USER_LDAP_MAPPING_ATTRIBUTES.get("establishment")
and entry[USER_LDAP_MAPPING_ATTRIBUTES["establishment"]]
)
else ""
)
owner.affiliation = get_entry_value(entry, "primaryAffiliation", DEFAULT_AFFILIATION)
owner.establishment = get_entry_value(entry, "establishment", "")
owner.save()
affiliations = (
entry[USER_LDAP_MAPPING_ATTRIBUTES["affiliations"]].values
if (
USER_LDAP_MAPPING_ATTRIBUTES.get("affiliations")
and entry[USER_LDAP_MAPPING_ATTRIBUTES["affiliations"]]
)
else []
)
affiliations = get_entry_value(entry, attribute="affiliations", default=[])
for affiliation in affiliations:
if affiliation in AFFILIATION_STAFF:
user.is_staff = True
Expand Down
8 changes: 4 additions & 4 deletions pod/authentication/templates/userpicture/userpicture.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{% load i18n %}
<div class="modal fade" id="userpictureModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal fade" id="userpictureModal" tabindex="-1" role="dialog" aria-labelledby="userpictureLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form method="post" action="{% url 'userpicture' %}" id="userpicture_form">
<div class="modal-header">
<h2 class="modal-title" id="exampleModalLabel">{% trans "Change your picture" %}</h2>
<h2 class="modal-title" id="userpictureLabel">{% trans "Change your picture" %}</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans 'Close' %}"></button>
</div>
<div class="modal-body">
Expand Down Expand Up @@ -40,10 +40,10 @@ <h2 class="modal-title" id="exampleModalLabel">{% trans "Change your picture" %}
{% endspaceless %}
{% endfor %}
{% if frontOwnerForm.instance.id %}
<input type="hidden" id="user_id" name="user_id" value="{{frontOwnerForm.instance.id}}"/>
<input type="hidden" id="user_id" name="user_id" value="{{frontOwnerForm.instance.id}}">
{% endif %}
{% if frontOwnerForm.instance.userpicture %}
<input type="hidden" id="userpictureurl" name="userpictureurl" value="{{frontOwnerForm.instance.userpicture.file.url}}"/>
<input type="hidden" id="userpictureurl" name="userpictureurl" value="{{frontOwnerForm.instance.userpicture.file.url}}">
{% endif %}
{{frontOwnerForm.media}}
</div>
Expand Down
18 changes: 9 additions & 9 deletions pod/authentication/tests/test_populated.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ def setUp(self):
print(" ---> SetUp of PopulatedShibTestCase: OK!")

def _authenticate_shib_user(self, u):
"""Simulate shibboleth header"""
"""Simulate shibboleth header."""
fake_shib_header = {
"REMOTE_USER": u["username"],
self.hmap["username"]: u["username"],
Expand All @@ -455,13 +455,13 @@ def _authenticate_shib_user(self, u):
fake_shib_header[self.hmap["affiliation"]] = u["affiliations"].split(";")[0]
fake_shib_header[self.hmap["affiliations"]] = u["affiliations"]

""" Get valid shib_meta from simulated shibboleth header """
"""Get valid shib_meta from simulated shibboleth header """
request = RequestFactory().get("/", REMOTE_USER=u["username"])
request.META.update(**fake_shib_header)
shib_meta, error = shibmiddleware.ShibbMiddleware.parse_attributes(request)
self.assertFalse(error, "Generating shibboleth attribute mapping contains errors")

""" Check user authentication """
"""Check user authentication """
user = ShibbBackend.authenticate(
ShibbBackend(),
request=request,
Expand Down Expand Up @@ -489,7 +489,7 @@ def test_make_profile(self):
self.assertEqual(user.first_name, "John")
self.assertEqual(user.last_name, "Do")

""" Test if user can be staff if SHIBBOLETH_STAFF_ALLOWED_DOMAINS is None """
"""Test if user can be staff if SHIBBOLETH_STAFF_ALLOWED_DOMAINS is None """
settings.SHIBBOLETH_STAFF_ALLOWED_DOMAINS = None
reload(shibmiddleware)
shibmiddleware.ShibbMiddleware.make_profile(
Expand All @@ -500,7 +500,7 @@ def test_make_profile(self):
owner = Owner.objects.get(user__username="[email protected]")
self.assertEqual(owner.affiliation, "teacher")

""" Test if user can be staff when SHIBBOLETH_STAFF_ALLOWED_DOMAINS
"""Test if user can be staff when SHIBBOLETH_STAFF_ALLOWED_DOMAINS
is restricted """
settings.SHIBBOLETH_STAFF_ALLOWED_DOMAINS = (
"univ-a.fr",
Expand All @@ -514,7 +514,7 @@ def test_make_profile(self):
)
self.assertFalse(user.is_staff)

""" Test if user become staff when SHIBBOLETH_STAFF_ALLOWED_DOMAINS
"""Test if user become staff when SHIBBOLETH_STAFF_ALLOWED_DOMAINS
is restrict and contains his domain """
settings.SHIBBOLETH_STAFF_ALLOWED_DOMAINS = ("univ.fr",)
reload(shibmiddleware)
Expand All @@ -523,7 +523,7 @@ def test_make_profile(self):
)
self.assertTrue(user.is_staff)

""" Test if same user with new unstaffable affiliation keep his staff status """
"""Test if same user with new unstaffable affiliation keep his staff status """
for a in UNSTAFFABLE_AFFILIATIONS:
self.assertFalse(a in AFFILIATION_STAFF)
user, shib_meta = self._authenticate_shib_user(
Expand All @@ -540,12 +540,12 @@ def test_make_profile(self):
)
self.assertTrue(user.is_staff) # Staff status is not remove

""" Test if the main affiliation of this same user
"""Test if the main affiliation of this same user
with new unstaffable affiliation has changed """
owner = Owner.objects.get(user__username="[email protected]")
self.assertEqual(owner.affiliation, "member")

""" Test if a new user with same unstaffable affiliations has no staff status"""
"""Test if a new user with same unstaffable affiliations has no staff status"""
user, shib_meta = self._authenticate_shib_user(
{
"username": "[email protected]",
Expand Down
Loading

0 comments on commit 1b27faa

Please sign in to comment.