Compare commits

..

7 Commits

Author SHA1 Message Date
Markos Gogoulos
0b9a203123 revert head changes 2025-02-13 20:31:19 +02:00
Sven-Thorsten Dietrich
5cbd815496 fix: Fix Docker WARN: FromAsCasing (#1196)
Fixes: L27 'as' and 'FROM' keywords' casing do not match

Signed-off-by: Sven-Thorsten Dietrich <thebigcorporation@gmail.com>
2025-02-13 13:57:14 +02:00
Markos Gogoulos
3a8cacc847 feat: Bulk fixes (#1195)
remove ckeditor - not in use
add more strict default password validators
set Django admin as configurable URL
add nginx HSTS and CSP headers
enable moving from private to unlisted in the PORTAL_WORKFLOW private
on default comments listing, show only comments for public media
in case of a private media, dont expose any unneeded metadata
2025-02-13 13:41:53 +02:00
Markos Gogoulos
5402ee7bc5 fix: crispy forms (#1194) 2025-02-12 14:27:27 +02:00
Markos Gogoulos
a6a2b50c8d remove redundant message 2025-02-10 22:25:24 +02:00
Markos Gogoulos
23e48a8bb7 remove redundant message 2025-02-10 22:24:42 +02:00
Markos Gogoulos
313cd9cbc6 fix issue with static files in dev 2025-02-10 22:04:14 +02:00
15 changed files with 119 additions and 125 deletions

View File

@@ -24,7 +24,7 @@ RUN mkdir -p /home/mediacms.io/bento4 && \
rm Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip
############ RUNTIME IMAGE ############
FROM python:3.13-bookworm as runtime-image
FROM python:3.13-bookworm AS runtime_image
SHELL ["/bin/bash", "-c"]

View File

@@ -23,9 +23,9 @@ INSTALLED_APPS = [
'debug_toolbar',
'mptt',
'crispy_forms',
"crispy_bootstrap5",
'uploader.apps.UploaderConfig',
'djcelery_email',
'ckeditor',
'drf_yasg',
'corsheaders',
]
@@ -46,5 +46,5 @@ MIDDLEWARE = [
DEBUG = True
CORS_ORIGIN_ALLOW_ALL = True
# STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static_files/'),)
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
STATIC_ROOT = os.path.join(BASE_DIR, 'static_collected')

View File

@@ -232,7 +232,7 @@ CANNOT_ADD_MEDIA_MESSAGE = ""
MP4HLS_COMMAND = "/home/mediacms.io/mediacms/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/bin/mp4hls"
# highly experimental, related with remote workers
ADMIN_TOKEN = "c2b8e1838b6128asd333ddc5e24"
ADMIN_TOKEN = ""
# this is used by remote workers to push
# encodings once they are done
# USE_BASIC_HTTP = True
@@ -247,35 +247,6 @@ ADMIN_TOKEN = "c2b8e1838b6128asd333ddc5e24"
# uncomment the two lines related to htpasswd
CKEDITOR_CONFIGS = {
"default": {
"toolbar": "Custom",
"width": "100%",
"toolbar_Custom": [
["Styles"],
["Format"],
["Bold", "Italic", "Underline"],
["HorizontalRule"],
[
"NumberedList",
"BulletedList",
"-",
"Outdent",
"Indent",
"-",
"JustifyLeft",
"JustifyCenter",
"JustifyRight",
"JustifyBlock",
],
["Link", "Unlink"],
["Image"],
["RemoveFormat", "Source"],
],
}
}
AUTH_USER_MODEL = "users.User"
LOGIN_REDIRECT_URL = "/"
@@ -304,9 +275,9 @@ INSTALLED_APPS = [
"debug_toolbar",
"mptt",
"crispy_forms",
"crispy_bootstrap5",
"uploader.apps.UploaderConfig",
"djcelery_email",
"ckeditor",
"drf_yasg",
]
@@ -348,11 +319,15 @@ WSGI_APPLICATION = "cms.wsgi.application"
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
"OPTIONS": {
"user_attributes": ("username", "email", "first_name", "last_name"),
"max_similarity": 0.7,
},
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
"OPTIONS": {
"min_length": 5,
"min_length": 7,
},
},
{
@@ -543,3 +518,13 @@ SPRITE_NUM_SECS = 10
SLIDESHOW_ITEMS = 30
# this calculation is redundant most probably, setting as an option
CALCULATE_MD5SUM = False
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
# allow option to override the default admin url
# keep the trailing slash
DJANGO_ADMIN_URL = "admin/"
# CSRF_COOKIE_SECURE = True
# SESSION_COOKIE_SECURE = True

View File

@@ -1,4 +1,5 @@
import debug_toolbar
from django.conf import settings
from django.conf.urls import include
from django.contrib import admin
from django.urls import path, re_path
@@ -25,7 +26,7 @@ urlpatterns = [
re_path(r"^", include("users.urls")),
re_path(r"^accounts/", include("allauth.urls")),
re_path(r"^api-auth/", include("rest_framework.urls")),
path("admin/", admin.site.urls),
path(settings.DJANGO_ADMIN_URL, admin.site.urls),
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
path('docs/api/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),

View File

@@ -49,7 +49,7 @@ server {
ssl_dhparam /etc/nginx/dhparams/dhparams.pem;
ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_ecdh_curve secp521r1:secp384r1;
ssl_prefer_server_ciphers on;

View File

@@ -34,5 +34,7 @@ def stuff(request):
ret["RSS_URL"] = "/rss"
ret["TRANSLATION"] = get_translation(request.LANGUAGE_CODE)
ret["REPLACEMENTS"] = get_translation_strings(request.LANGUAGE_CODE)
if request.user.is_superuser:
ret["DJANGO_ADMIN_URL"] = settings.DJANGO_ADMIN_URL
return ret

View File

@@ -119,12 +119,16 @@ def get_next_state(user, current_state, next_state):
if next_state not in ["public", "private", "unlisted"]:
next_state = settings.PORTAL_WORKFLOW # get default state
if is_mediacms_editor(user):
# allow any transition
return next_state
if settings.PORTAL_WORKFLOW == "private":
next_state = "private"
if next_state in ["private", "unlisted"]:
next_state = next_state
else:
next_state = current_state
if settings.PORTAL_WORKFLOW == "unlisted":
# don't allow to make media public in this case

View File

@@ -675,6 +675,9 @@ class MediaActions(APIView):
def get(self, request, friendly_token, format=None):
# show date and reason for each time media was reported
media = self.get_object(friendly_token)
if not (request.user == media.user or is_mediacms_editor(request.user) or is_mediacms_manager(request.user)):
return Response({"detail": "not allowed"}, status=status.HTTP_400_BAD_REQUEST)
if isinstance(media, Response):
return media
@@ -928,9 +931,10 @@ class PlaylistDetail(APIView):
serializer = PlaylistDetailSerializer(playlist, context={"request": request})
playlist_media = PlaylistMedia.objects.filter(playlist=playlist).prefetch_related("media__user")
playlist_media = PlaylistMedia.objects.filter(playlist=playlist, media__state="public").prefetch_related("media__user")
playlist_media = [c.media for c in playlist_media]
playlist_media_serializer = MediaSerializer(playlist_media, many=True, context={"request": request})
ret = serializer.data
ret["playlist_media"] = playlist_media_serializer.data
@@ -1195,7 +1199,7 @@ class CommentList(APIView):
def get(self, request, format=None):
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
paginator = pagination_class()
comments = Comment.objects.filter()
comments = Comment.objects.filter(media__state="public").order_by("-add_date")
comments = comments.prefetch_related("user")
comments = comments.prefetch_related("media")
params = self.request.query_params

View File

@@ -12,11 +12,10 @@ markdown==3.7
django-filter==24.3
filetype==1.2.0
django-mptt==0.16.0
django-crispy-forms==2.3
crispy-bootstrap5==2024.10
requests==2.32.3
django-celery-email==3.0.0
m3u8==6.0.0
django-ckeditor==6.7.2
django-debug-toolbar==5.0.1
django-login-required-middleware==0.9.0
pre-commit==4.1.0

View File

@@ -17,7 +17,6 @@
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button class="primaryAction" type="submit">Sign In</button>
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">Forgot Password?</a>
</form>
</div>

View File

@@ -140,7 +140,6 @@
{% csrf_token %}
{{ form.as_p }}
<input type="hidden" name="next" value="{{ redirect_url }}" />
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">Forgot Password?</a>
<button class="primaryAction" type="submit">Sign In</button>
</form>

View File

@@ -7,8 +7,6 @@
{% block headermeta %}{% endblock headermeta %}
{% block innercontent %}
<script type="text/javascript" src="{% static "ckeditor/ckeditor-init.js" %}"></script>
<script type="text/javascript" src="{% static "ckeditor/ckeditor/ckeditor.js" %}"></script>
<div class="user-action-form-wrap">
<div class="user-action-form-inner">

View File

@@ -20,100 +20,105 @@
<meta property="og:type" content="website">
{% endif %}
{% if media_object.media_type == "video" %}
{% if media_object.state != "private" %}
<meta property="og:image" content="{{FRONTEND_HOST}}{{media_object.poster_url}}">
{% if media_object.media_type == "video" %}
<meta name="twitter:card" content="summary_large_image">
<meta property="og:image" content="{{FRONTEND_HOST}}{{media_object.poster_url}}">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "VideoObject",
"name": "{{media_object.title}} - {{PORTAL_NAME}}",
"url": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}",
"description": "{% if media_object.summary %}{{media_object.summary}}{% else %}{{media_object.description}}{% endif %}",
"thumbnailUrl": [
"{{FRONTEND_HOST}}{{media_object.poster_url}}"
],
"uploadDate": "{{media_object.add_date}}",
"dateModified": "{{media_object.edit_date}}",
"embedUrl": "{{FRONTEND_HOST}}/embed?m={{media}}",
"duration": "T{{media_object.duration}}S",
"potentialAction": {
"@type": "ViewAction",
"target": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}"
<meta name="twitter:card" content="summary_large_image">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "VideoObject",
"name": "{{media_object.title}} - {{PORTAL_NAME}}",
"url": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}",
"description": "{% if media_object.summary %}{{media_object.summary}}{% else %}{{media_object.description}}{% endif %}",
"thumbnailUrl": [
"{{FRONTEND_HOST}}{{media_object.poster_url}}"
],
"uploadDate": "{{media_object.add_date}}",
"dateModified": "{{media_object.edit_date}}",
"embedUrl": "{{FRONTEND_HOST}}/embed?m={{media}}",
"duration": "T{{media_object.duration}}S",
"potentialAction": {
"@type": "ViewAction",
"target": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}"
}
}
}
</script>
</script>
{% elif media_object.media_type == "audio" %}
{% elif media_object.media_type == "audio" %}
<meta property="og:image" content="{{FRONTEND_HOST}}{{media_object.poster_url}}">
<meta property="og:image" content="{{FRONTEND_HOST}}{{media_object.poster_url}}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:card" content="summary_large_image">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "AudioObject",
"name": "{{media_object.title}} - {{PORTAL_NAME}}",
"url": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}",
"description": "{% if media_object.summary %}{{media_object.summary}}{% else %}{{media_object.description}}{% endif %}",
"uploadDate": "{{media_object.add_date}}",
"dateModified": "{{media_object.edit_date}}",
"duration": "T{{media_object.duration}}S",
"potentialAction": {
"@type": "ViewAction",
"target": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}"
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "AudioObject",
"name": "{{media_object.title}} - {{PORTAL_NAME}}",
"url": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}",
"description": "{% if media_object.summary %}{{media_object.summary}}{% else %}{{media_object.description}}{% endif %}",
"uploadDate": "{{media_object.add_date}}",
"dateModified": "{{media_object.edit_date}}",
"duration": "T{{media_object.duration}}S",
"potentialAction": {
"@type": "ViewAction",
"target": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}"
}
}
}
</script>
</script>
{% elif media_object.media_type == "image" %}
{% elif media_object.media_type == "image" %}
<meta property="og:image" content="{{FRONTEND_HOST}}{{media_object.original_media_url}}">
<meta property="og:image" content="{{FRONTEND_HOST}}{{media_object.original_media_url}}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:card" content="summary_large_image">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "ImageObject",
"name": "{{media_object.title}} - {{PORTAL_NAME}}",
"url": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}",
"description": "{% if media_object.summary %}{{media_object.summary}}{% else %}{{media_object.description}}{% endif %}",
"uploadDate": "{{media_object.add_date}}",
"dateModified": "{{media_object.edit_date}}",
"potentialAction": {
"@type": "ViewAction",
"target": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}"
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "ImageObject",
"name": "{{media_object.title}} - {{PORTAL_NAME}}",
"url": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}",
"description": "{% if media_object.summary %}{{media_object.summary}}{% else %}{{media_object.description}}{% endif %}",
"uploadDate": "{{media_object.add_date}}",
"dateModified": "{{media_object.edit_date}}",
"potentialAction": {
"@type": "ViewAction",
"target": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}"
}
}
}
</script>
</script>
{% else %}
<meta name="twitter:card" content="summary">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "MediaObject",
"name": "{{media_object.title}} - {{PORTAL_NAME}}",
"url": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}",
"description": "{% if media_object.summary %}{{media_object.summary}}{% else %}{{media_object.description}}{% endif %}",
"uploadDate": "{{media_object.add_date}}",
"dateModified": "{{media_object.edit_date}}",
"potentialAction": {
"@type": "ViewAction",
"target": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}"
}
}
</script>
{% endif %}
{% else %}
<meta name="twitter:card" content="summary">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "MediaObject",
"name": "{{media_object.title}} - {{PORTAL_NAME}}",
"url": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}",
"description": "{% if media_object.summary %}{{media_object.summary}}{% else %}{{media_object.description}}{% endif %}",
"uploadDate": "{{media_object.add_date}}",
"dateModified": "{{media_object.edit_date}}",
"potentialAction": {
"@type": "ViewAction",
"target": "{{FRONTEND_HOST}}{{media_object.get_absolute_url}}"
}
}
</script>
{% endif %}
{% endblock headermeta %}
{% block topimports %}

View File

@@ -3,8 +3,6 @@
{% block headtitle %}Edit profile - {% endblock headtitle %}
{% block innercontent %}
<script type="text/javascript" src="{% static "ckeditor/ckeditor-init.js" %}"></script>
<script type="text/javascript" src="{% static "ckeditor/ckeditor/ckeditor.js" %}"></script>
<div class="user-action-form-wrap">
<div class="user-action-form-inner">

View File

@@ -22,7 +22,7 @@ MediaCMS.url = {
editChannel: "{{user.default_channel_edit_url}}",
changePassword: "/accounts/password/change/",
/* Administration pages */
{% if IS_MEDIACMS_ADMIN %}admin: '/admin',{% endif %}
{% if IS_MEDIACMS_ADMIN %}admin: '/{{DJANGO_ADMIN_URL}}',{% endif %}
/* Management pages */
{% if IS_MEDIACMS_EDITOR %}manageMedia: "/manage/media",{% endif %}
{% if IS_MEDIACMS_MANAGER %}manageUsers: "/manage/users",{% endif %}