diff --git a/dockerfile-dev-with-volumes/README.adoc b/dockerfile-dev-with-volumes/README.adoc index e3f2a89a5c..4ecf9aeccd 100755 --- a/dockerfile-dev-with-volumes/README.adoc +++ b/dockerfile-dev-with-volumes/README.adoc @@ -76,12 +76,16 @@ ES_VERSION = 7 ES_URL = ['http://elasticsearch:9200/'] + CACHES = { - # … default cache config and others "default": { - "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": "redis://redis:6379/3", + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + }, + "KEY_PREFIX": "pod" }, - # Persistent cache setup for select2 (NOT DummyCache or LocMemCache). "select2": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://redis:6379/2", @@ -90,6 +94,15 @@ CACHES = { }, }, } +SESSION_ENGINE = "redis_sessions.session" +SESSION_REDIS = { + "host": "redis", + "port": 6379, + "db": 4, + "prefix": "session", + "socket_timeout": 1, + "retry_on_timeout": False, +} # Uniquement lors d’environnement conteneurisé MIGRATION_MODULES = {'flatpages': 'pod.db_migrations'} diff --git a/dockerfile-dev-with-volumes/pod/Dockerfile b/dockerfile-dev-with-volumes/pod/Dockerfile index e1a08e348c..755e9ad3b2 100755 --- a/dockerfile-dev-with-volumes/pod/Dockerfile +++ b/dockerfile-dev-with-volumes/pod/Dockerfile @@ -29,12 +29,13 @@ WORKDIR /usr/src/app COPY ./requirements.txt . COPY ./requirements-conteneur.txt . +COPY ./requirements-dev.txt . RUN mkdir /tmp/node_modules/ COPY --from=source-build-js /tmp/pod/node_modules/ /tmp/node_modules/ -RUN pip3 install --no-cache-dir -r requirements.txt \ - && pip3 install --no-cache-dir -r requirements-conteneur.txt +RUN pip3 install --no-cache-dir -r requirements-conteneur.txt \ + && pip3 install elasticsearch==7.17.7 # ENTRYPOINT : COPY ./dockerfile-dev-with-volumes/pod/my-entrypoint.sh /tmp/my-entrypoint.sh diff --git a/pod/main/context_processors.py b/pod/main/context_processors.py index 59f427a115..4dc1ea8be1 100644 --- a/pod/main/context_processors.py +++ b/pod/main/context_processors.py @@ -1,19 +1,11 @@ from django.conf import settings as django_settings from django.core.exceptions import ImproperlyConfigured -from django.db.models import Count, Sum -from django.db.models import Prefetch -from datetime import timedelta from pod.main.models import LinkFooter from django.core.exceptions import ObjectDoesNotExist -from pod.video.models import Channel -from pod.video.models import Theme -from pod.video.models import Type -from pod.video.models import Discipline -from pod.video.models import Video + from pod.main.models import Configuration from django.contrib.sites.shortcuts import get_current_site -from pod.main.models import AdditionalChannelTab MENUBAR_HIDE_INACTIVE_OWNERS = getattr( django_settings, "MENUBAR_HIDE_INACTIVE_OWNERS", False @@ -58,7 +50,11 @@ HIDE_TYPES_TAB = getattr(django_settings, "HIDE_TYPES_TAB", False) -HIDE_LANGUAGE_SELECTOR = getattr(django_settings, "HIDE_LANGUAGE_SELECTOR", False) +HIDE_LANGUAGE_SELECTOR = getattr( + django_settings, + "HIDE_LANGUAGE_SELECTOR", + False +) HIDE_TAGS = getattr(django_settings, "HIDE_TAGS", False) @@ -74,7 +70,11 @@ COOKIE_LEARN_MORE = getattr(django_settings, "COOKIE_LEARN_MORE", "") -SHOW_EVENTS_ON_HOMEPAGE = getattr(django_settings, "SHOW_EVENTS_ON_HOMEPAGE", False) +SHOW_EVENTS_ON_HOMEPAGE = getattr( + django_settings, + "SHOW_EVENTS_ON_HOMEPAGE", + False +) USE_OPENCAST_STUDIO = getattr(django_settings, "USE_OPENCAST_STUDIO", False) @@ -102,8 +102,12 @@ def context_settings(request): key="maintenance_text_short" ).value - maintenance_sheduled = Configuration.objects.get(key="maintenance_sheduled") - maintenance_sheduled = True if maintenance_sheduled.value == "1" else False + maintenance_sheduled = Configuration.objects.get( + key="maintenance_sheduled" + ) + maintenance_sheduled = True if ( + maintenance_sheduled.value == "1" + ) else False maintenance_text_sheduled = Configuration.objects.get( key="maintenance_text_sheduled" ).value @@ -150,93 +154,10 @@ def context_settings(request): return new_settings -def context_navbar(request): - channels = ( - Channel.objects.filter( - visible=True, - video__is_draft=False, - add_channels_tab=None, - site=get_current_site(request), - ) - .distinct() - .annotate(video_count=Count("video", distinct=True)) - .prefetch_related( - Prefetch( - "themes", - queryset=Theme.objects.filter( - parentId=None, channel__site=get_current_site(request) - ) - .distinct() - .annotate(video_count=Count("video", distinct=True)), - ) - ) - ) - - add_channels_tab = AdditionalChannelTab.objects.all().prefetch_related( - Prefetch( - "channel_set", - queryset=Channel.objects.filter(site=get_current_site(request)) - .distinct() - .annotate(video_count=Count("video", distinct=True)), - ) +def context_footer(request): + linkFooter = LinkFooter.objects.all().filter( + sites=get_current_site(request) ) - - all_channels = ( - Channel.objects.all() - .filter(site=get_current_site(request)) - .distinct() - .annotate(video_count=Count("video", distinct=True)) - .prefetch_related( - Prefetch( - "themes", - queryset=Theme.objects.filter(channel__site=get_current_site(request)) - .distinct() - .annotate(video_count=Count("video", distinct=True)), - ) - ) - ) - - types = ( - Type.objects.filter( - sites=get_current_site(request), - video__is_draft=False, - video__sites=get_current_site(request), - ) - .distinct() - .annotate(video_count=Count("video", distinct=True)) - ) - - disciplines = ( - Discipline.objects.filter( - site=get_current_site(request), - video__is_draft=False, - video__sites=get_current_site(request), - ) - .distinct() - .annotate(video_count=Count("video", distinct=True)) - ) - - linkFooter = LinkFooter.objects.all().filter(sites=get_current_site(request)) - - list_videos = Video.objects.filter( - encoding_in_progress=False, - is_draft=False, - sites=get_current_site(request), - ) - VIDEOS_COUNT = list_videos.count() - VIDEOS_DURATION = ( - str(timedelta(seconds=list_videos.aggregate(Sum("duration"))["duration__sum"])) - if list_videos.aggregate(Sum("duration"))["duration__sum"] - else 0 - ) - return { - "ALL_CHANNELS": all_channels, - "ADD_CHANNELS_TAB": add_channels_tab, - "CHANNELS": channels, - "TYPES": types, - "DISCIPLINES": disciplines, "LINK_FOOTER": linkFooter, - "VIDEOS_COUNT": VIDEOS_COUNT, - "VIDEOS_DURATION": VIDEOS_DURATION, } diff --git a/pod/main/test_settings.py b/pod/main/test_settings.py index 5532b99536..0f29fbdfe3 100644 --- a/pod/main/test_settings.py +++ b/pod/main/test_settings.py @@ -73,7 +73,7 @@ def get_shared_secret(): api_mate_url = "https://bigbluebutton.org/api-mate/" response = requests.get(api_mate_url) - soup = BeautifulSoup(response.text) + soup = BeautifulSoup(response.text, features="html.parser") input_val = soup.body.find("input", attrs={"id": "input-custom-server-salt"}) return input_val.get("value") diff --git a/pod/settings.py b/pod/settings.py index f6f97207a2..172b38dd2a 100644 --- a/pod/settings.py +++ b/pod/settings.py @@ -4,6 +4,7 @@ Django version: 3.2. """ import os +import importlib.util import django.conf.global_settings BASE_DIR = os.path.dirname(os.path.dirname(__file__)) @@ -114,7 +115,8 @@ "django.contrib.messages.context_processors.messages", # Local contexts "pod.main.context_processors.context_settings", - "pod.main.context_processors.context_navbar", + "pod.main.context_processors.context_footer", + "pod.video.context_processors.context_navbar", "pod.video.context_processors.context_video_settings", "pod.authentication.context_processors.context_authentication_settings", "pod.recorder.context_processors.context_recorder_settings", @@ -352,6 +354,7 @@ "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", }, + "KEY_PREFIX": "pod" }, "select2": { "BACKEND": "django_redis.cache.RedisCache", @@ -455,3 +458,16 @@ def update_settings(local_settings): locals()[variable] = the_update_settings[variable] TIME_INPUT_FORMATS = ["%H:%M", *django.conf.global_settings.TIME_INPUT_FORMATS] + +if ( + locals()['DEBUG'] is True + and importlib.util.find_spec("debug_toolbar") is not None +): + INSTALLED_APPS.append('debug_toolbar') + MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware', ] + MIDDLEWARE + DEBUG_TOOLBAR_CONFIG = { + 'SHOW_TOOLBAR_CALLBACK': 'pod.settings.show_toolbar' + } + + def show_toolbar(request): + return True diff --git a/pod/urls.py b/pod/urls.py index 587319cd74..c39d60191e 100644 --- a/pod/urls.py +++ b/pod/urls.py @@ -10,6 +10,8 @@ from django.views.i18n import JavaScriptCatalog from django.utils.translation import ugettext_lazy as _ +import importlib.util + from pod.main.views import ( contact_us, download_file, @@ -140,14 +142,18 @@ ), ] +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + if importlib.util.find_spec("debug_toolbar") is not None: + urlpatterns += [ + path("__debug__/", include("debug_toolbar.urls")), + ] + # CHANNELS urlpatterns += [ url(r"^", include("pod.video.urls-channels-video")), ] -if settings.DEBUG: - urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - # Change admin site title admin.site.site_header = _("Pod Administration") admin.site.site_title = _("Pod Administration") diff --git a/pod/video/context_processors.py b/pod/video/context_processors.py index 26ecccfca6..cdd89153a9 100644 --- a/pod/video/context_processors.py +++ b/pod/video/context_processors.py @@ -1,10 +1,65 @@ from django.conf import settings as django_settings +from pod.video.models import Channel +from pod.video.models import Theme +from pod.video.models import Type +from pod.video.models import Discipline +from pod.video.models import Video + +from django.db.models import Count, Sum +from django.db.models import Prefetch +from django.db.models import Q +from django.db.models import Exists +from django.db.models import OuterRef + +from datetime import timedelta +from django.contrib.sites.shortcuts import get_current_site +from pod.main.models import AdditionalChannelTab +from pod.video_encode_transcript.models import EncodingVideo +from pod.video_encode_transcript.models import PlaylistVideo +from pod.video_encode_transcript.models import EncodingAudio + CHUNK_SIZE = getattr(django_settings, "CHUNK_SIZE", 100000) HIDE_USER_FILTER = getattr(django_settings, "HIDE_USER_FILTER", False) OEMBED = getattr(django_settings, "OEMBED", False) USE_STATS_VIEW = getattr(django_settings, "USE_STATS_VIEW", False) +__AVAILABLE_VIDEO_FILTER__ = { + 'encoding_in_progress': False, + 'is_draft': False, + 'sites': 1, +} + + +def get_available_videos(request=None): + """Get all videos available.""" + __AVAILABLE_VIDEO_FILTER__["sites"] = get_current_site(request) + vids = Video.objects.filter(**__AVAILABLE_VIDEO_FILTER__).defer( + "video", "slug", "owner", "additional_owners", "description" + ).filter( + Q(Exists( + EncodingVideo.objects.filter( + video=OuterRef('pk'), + encoding_format="video/mp4" + ) + )) + | Q(Exists( + PlaylistVideo.objects.filter( + video=OuterRef('pk'), + name="playlist", + encoding_format="application/x-mpegURL" + ) + )) + | Q(Exists( + EncodingAudio.objects.filter( + video=OuterRef('pk'), + name="audio", + encoding_format="video/mp4" + ) + )) + ).distinct() + return vids + def context_video_settings(request): new_settings = {} @@ -13,3 +68,92 @@ def context_video_settings(request): new_settings["OEMBED"] = OEMBED new_settings["USE_STATS_VIEW"] = USE_STATS_VIEW return new_settings + + +def context_navbar(request): + channels = ( + Channel.objects.filter( + visible=True, + video__is_draft=False, + add_channels_tab=None, + site=get_current_site(request), + ) + .distinct() + .annotate(video_count=Count("video", distinct=True)) + .prefetch_related( + Prefetch( + "themes", + queryset=Theme.objects.filter( + parentId=None, channel__site=get_current_site(request) + ) + .distinct() + .annotate(video_count=Count("video", distinct=True)), + ) + ) + ) + + add_channels_tab = AdditionalChannelTab.objects.all().prefetch_related( + Prefetch( + "channel_set", + queryset=Channel.objects.filter(site=get_current_site(request)) + .distinct() + .annotate(video_count=Count("video", distinct=True)), + ) + ) + + all_channels = ( + Channel.objects.all() + .filter(site=get_current_site(request)) + .distinct() + .annotate(video_count=Count("video", distinct=True)) + .prefetch_related( + Prefetch( + "themes", + queryset=Theme.objects.filter( + channel__site=get_current_site(request) + ) + .distinct() + .annotate(video_count=Count("video", distinct=True)), + ) + ) + ) + + types = ( + Type.objects.filter( + sites=get_current_site(request), + video__is_draft=False, + video__sites=get_current_site(request), + ) + .distinct() + .annotate(video_count=Count("video", distinct=True)) + ) + + disciplines = ( + Discipline.objects.filter( + site=get_current_site(request), + video__is_draft=False, + video__sites=get_current_site(request), + ) + .distinct() + .annotate(video_count=Count("video", distinct=True)) + ) + + list_videos = get_available_videos(request) + VIDEOS_COUNT = list_videos.count() + VIDEOS_DURATION = ( + str(timedelta(seconds=list_videos.aggregate( + Sum("duration") + )["duration__sum"])) + if list_videos.aggregate(Sum("duration"))["duration__sum"] + else 0 + ) + + return { + "ALL_CHANNELS": all_channels, + "ADD_CHANNELS_TAB": add_channels_tab, + "CHANNELS": channels, + "TYPES": types, + "DISCIPLINES": disciplines, + "VIDEOS_COUNT": VIDEOS_COUNT, + "VIDEOS_DURATION": VIDEOS_DURATION, + } diff --git a/pod/video/feeds.py b/pod/video/feeds.py index 6f645203c1..ac0caac7e4 100644 --- a/pod/video/feeds.py +++ b/pod/video/feeds.py @@ -9,7 +9,7 @@ from django.shortcuts import get_object_or_404 from django.utils.html import format_html -from pod.video.views import get_videos_list +from .context_processors import get_available_videos from pod.video_encode_transcript.models import EncodingAudio from pod.video.models import Channel @@ -153,7 +153,7 @@ def get_object(self, request, slug_c=None, slug_t=None): ) self.feed_url = request.build_absolute_uri() - videos_list = get_videos_list() + videos_list = get_available_videos() if slug_c: channel = get_object_or_404( diff --git a/pod/video/rest_views.py b/pod/video/rest_views.py index 9671134ca1..af0beb0539 100644 --- a/pod/video/rest_views.py +++ b/pod/video/rest_views.py @@ -11,15 +11,13 @@ from .models import Channel, Theme from .models import Type, Discipline, Video from .models import ViewCount -from .utils import get_available_videos +from .context_processors import get_available_videos # commented for v3 # from .remote_encode import start_store_remote_encoding_video import json -__VIDEOS__ = get_available_videos() - # Serializers define the API representation. @@ -218,7 +216,7 @@ def user_videos(self, request): ) if request.GET.get("encoded") and request.GET.get("encoded") == "true": user_videos = user_videos.exclude( - pk__in=[vid.id for vid in __VIDEOS__ if not vid.encoded] + pk__in=[vid.id for vid in user_videos if not vid.encoded] ) if request.GET.get("search_title") and request.GET.get("search_title") != "": user_videos = user_videos.filter( @@ -267,9 +265,9 @@ class DublinCoreView(APIView): max_page_size = 1000 def get(self, request, format=None): - list_videos = __VIDEOS__ + list_videos = get_available_videos(request) if request.GET: - list_videos = __VIDEOS__.filter(**request.GET.dict()) + list_videos = list_videos.filter(**request.GET.dict()) xmlcontent = '\n' xmlcontent += ( "