feat: add fily type and max user media uplod limits

This commit is contained in:
Markos Gogoulos 2025-08-19 11:35:49 +03:00 committed by GitHub
parent e9f862a0ff
commit 8cbeb72dd2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 98 additions and 27 deletions

View File

@ -1,14 +1,22 @@
from django.conf import settings from django.conf import settings
from rest_framework import permissions from rest_framework import permissions
from rest_framework.exceptions import PermissionDenied
from files.methods import is_mediacms_editor, is_mediacms_manager from files.methods import (
is_mediacms_editor,
is_mediacms_manager,
user_allowed_to_upload,
)
class IsAuthorizedToAdd(permissions.BasePermission): class IsAuthorizedToAdd(permissions.BasePermission):
def has_permission(self, request, view): def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS: if request.method in permissions.SAFE_METHODS:
return True return True
return user_allowed_to_upload(request) if not user_allowed_to_upload(request):
raise PermissionDenied("You don't have permission to upload media, or have reached max number of media uploads.")
return True
class IsAuthorizedToAddComment(permissions.BasePermission): class IsAuthorizedToAddComment(permissions.BasePermission):
@ -55,26 +63,6 @@ class IsUserOrEditor(permissions.BasePermission):
return obj.user == request.user return obj.user == request.user
def user_allowed_to_upload(request):
"""Any custom logic for whether a user is allowed
to upload content lives here
"""
if request.user.is_anonymous:
return False
if request.user.is_superuser:
return True
if settings.CAN_ADD_MEDIA == "all":
return True
elif settings.CAN_ADD_MEDIA == "email_verified":
if request.user.email_is_verified:
return True
elif settings.CAN_ADD_MEDIA == "advancedUser":
if request.user.advancedUser:
return True
return False
def user_allowed_to_comment(request): def user_allowed_to_comment(request):
"""Any custom logic for whether a user is allowed """Any custom logic for whether a user is allowed
to comment lives here to comment lives here

View File

@ -226,7 +226,7 @@ POST_UPLOAD_AUTHOR_MESSAGE_UNLISTED_NO_COMMENTARY = ""
# only in case where unlisted workflow is used and no commentary # only in case where unlisted workflow is used and no commentary
# exists # exists
CANNOT_ADD_MEDIA_MESSAGE = "" CANNOT_ADD_MEDIA_MESSAGE = "User cannot add media, or maximum number of media uploads has been reached."
# mp4hls command, part of Bento4 # mp4hls command, part of Bento4
MP4HLS_COMMAND = "/home/mediacms.io/mediacms/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/bin/mp4hls" MP4HLS_COMMAND = "/home/mediacms.io/mediacms/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/bin/mp4hls"
@ -501,9 +501,14 @@ ALLOW_CUSTOM_MEDIA_URLS = False
# Whether to allow anonymous users to list all users # Whether to allow anonymous users to list all users
ALLOW_ANONYMOUS_USER_LISTING = True ALLOW_ANONYMOUS_USER_LISTING = True
# Maximum number of media a user can upload
NUMBER_OF_MEDIA_USER_CAN_UPLOAD = 100
# ffmpeg options # ffmpeg options
FFMPEG_DEFAULT_PRESET = "medium" # see https://trac.ffmpeg.org/wiki/Encode/H.264 FFMPEG_DEFAULT_PRESET = "medium" # see https://trac.ffmpeg.org/wiki/Encode/H.264
ALLOWED_MEDIA_UPLOAD_TYPES = ["video", "audio", "image", "pdf"]
try: try:
# keep a local_settings.py file for local overrides # keep a local_settings.py file for local overrides
from .local_settings import * # noqa from .local_settings import * # noqa

View File

@ -26,6 +26,8 @@
- [23. SAML setup](#23-saml-setup) - [23. SAML setup](#23-saml-setup)
- [24. Identity Providers setup](#24-identity-providers-setup) - [24. Identity Providers setup](#24-identity-providers-setup)
- [25. Custom urls](#25-custom-urls) - [25. Custom urls](#25-custom-urls)
- [26. Allowed files](#26-allowed-files)
- [27. User upload limits](#27-user-upload-limits)
## 1. Welcome ## 1. Welcome
@ -976,3 +978,21 @@ Visiting the admin, you will see the Identity Providers tab and you can add one.
## 25. Custom urls ## 25. Custom urls
To enable custom urls, set `ALLOW_CUSTOM_MEDIA_URLS = True` on settings.py or local_settings.py To enable custom urls, set `ALLOW_CUSTOM_MEDIA_URLS = True` on settings.py or local_settings.py
This will enable editing the URL of the media, while editing a media. If the URL is already taken you get a message you cannot update this. This will enable editing the URL of the media, while editing a media. If the URL is already taken you get a message you cannot update this.
## 26. Allowed files
MediaCMS performs identification attempts on new file uploads and only allows certain file types specified in the `ALLOWED_MEDIA_UPLOAD_TYPES` setting. By default, only ["video", "audio", "image", "pdf"] files are allowed.
When a file is not identified as one of these allowed types, the file gets removed from the system and there's an entry indicating that this is not a supported media type.
If you want to change the allowed file types, edit the `ALLOWED_MEDIA_UPLOAD_TYPES` list in your `settings.py` or `local_settings.py` file.
## 27. User upload limits
MediaCMS allows you to set a maximum number of media files that each user can upload. This is controlled by the `NUMBER_OF_MEDIA_USER_CAN_UPLOAD` setting in `settings.py` or `local_settings.py`. By default, this is set to 100 media items per user.
When a user reaches this limit, they will no longer be able to upload new media until they delete some of their existing content. This limit applies regardless of the user's role or permissions in the system.
To change the maximum number of uploads allowed per user, modify the `NUMBER_OF_MEDIA_USER_CAN_UPLOAD` value in your settings file:
```
NUMBER_OF_MEDIA_USER_CAN_UPLOAD = 5
```

View File

@ -401,6 +401,32 @@ def clean_comment(raw_comment):
return cleaned_comment return cleaned_comment
def user_allowed_to_upload(request):
"""Any custom logic for whether a user is allowed
to upload content lives here
"""
if request.user.is_anonymous:
return False
if is_mediacms_editor(request.user):
return True
# Check if user has reached the maximum number of uploads
if hasattr(settings, 'NUMBER_OF_MEDIA_USER_CAN_UPLOAD'):
if models.Media.objects.filter(user=request.user).count() >= settings.NUMBER_OF_MEDIA_USER_CAN_UPLOAD:
return False
if settings.CAN_ADD_MEDIA == "all":
return True
elif settings.CAN_ADD_MEDIA == "email_verified":
if request.user.email_is_verified:
return True
elif settings.CAN_ADD_MEDIA == "advancedUser":
if request.user.advancedUser:
return True
return False
def kill_ffmpeg_process(filepath): def kill_ffmpeg_process(filepath):
"""Kill ffmpeg process that is processing a specific file """Kill ffmpeg process that is processing a specific file
@ -606,3 +632,7 @@ def copy_media(media_id):
None None
""" """
pass pass
def is_media_allowed_type(media):
return media.media_type in settings.ALLOWED_MEDIA_UPLOAD_TYPES

View File

@ -336,6 +336,15 @@ class Media(models.Model):
video duration, encode video duration, encode
""" """
self.set_media_type() self.set_media_type()
from ..methods import is_media_allowed_type
if not is_media_allowed_type(self):
helpers.rm_file(self.media_file.path)
if self.state == "public":
self.state = "unlisted"
self.save(update_fields=["state"])
return False
if self.media_type == "video": if self.media_type == "video":
self.set_thumbnail(force=True) self.set_thumbnail(force=True)
if settings.DO_NOT_TRANSCODE_VIDEO: if settings.DO_NOT_TRANSCODE_VIDEO:

View File

@ -159,6 +159,7 @@ class MediaList(APIView):
) )
def post(self, request, format=None): def post(self, request, format=None):
# Add new media # Add new media
serializer = MediaSerializer(data=request.data, context={"request": request}) serializer = MediaSerializer(data=request.data, context={"request": request})
if serializer.is_valid(): if serializer.is_valid():
media_file = request.data["media_file"] media_file = request.data["media_file"]

View File

@ -8,8 +8,8 @@ from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.shortcuts import render from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from cms.permissions import user_allowed_to_upload
from cms.version import VERSION from cms.version import VERSION
from files.methods import user_allowed_to_upload
from users.models import User from users.models import User
from .. import helpers from .. import helpers
@ -26,6 +26,7 @@ from ..methods import (
create_video_trim_request, create_video_trim_request,
get_user_or_session, get_user_or_session,
handle_video_chapters, handle_video_chapters,
is_media_allowed_type,
is_mediacms_editor, is_mediacms_editor,
) )
from ..models import Category, Media, Playlist, Subtitle, Tag, VideoTrimRequest from ..models import Category, Media, Playlist, Subtitle, Tag, VideoTrimRequest
@ -238,6 +239,10 @@ def edit_media(request):
if not (request.user.has_contributor_access_to_media(media) or is_mediacms_editor(request.user)): if not (request.user.has_contributor_access_to_media(media) or is_mediacms_editor(request.user)):
return HttpResponseRedirect("/") return HttpResponseRedirect("/")
if not is_media_allowed_type(media):
return HttpResponseRedirect(media.get_absolute_url())
if request.method == "POST": if request.method == "POST":
form = MediaMetadataForm(request.user, request.POST, request.FILES, instance=media) form = MediaMetadataForm(request.user, request.POST, request.FILES, instance=media)
if form.is_valid(): if form.is_valid():
@ -577,6 +582,7 @@ def view_media(request):
if video_msg and media.user == request.user: if video_msg and media.user == request.user:
messages.add_message(request, messages.INFO, video_msg) messages.add_message(request, messages.INFO, video_msg)
context["is_media_allowed_type"] = is_media_allowed_type(media)
return render(request, "cms/media.html", context) return render(request, "cms/media.html", context)

View File

@ -119,7 +119,7 @@
<br> <br>
<a href='/contact'>Contact</a> the admin owners for more information. <a href='/contact'>Contact</a> portal owners for more information.
{% endif %} {% endif %}

View File

@ -126,7 +126,19 @@
<link href="{% static "css/media.css" %}" rel="stylesheet"> <link href="{% static "css/media.css" %}" rel="stylesheet">
{%endblock topimports %} {%endblock topimports %}
{% block content %}<div id="page-media"></div>{% endblock content %} {% block content %}
{% if is_media_allowed_type %}
<div id="page-media"></div>
{% else %}
<div class="user-action-form-wrap">
<div class="user-action-form-inner">
This media type is not supported.
</div>
</div>
{% endif %}
{% endblock content %}
{% block bottomimports %} {% block bottomimports %}
<script src="{% static "js/media.js" %}?v={{ VERSION }}"></script> <script src="{% static "js/media.js" %}?v={{ VERSION }}"></script>

View File

@ -8,8 +8,8 @@ from django.core.files import File
from django.http import JsonResponse from django.http import JsonResponse
from django.views import generic from django.views import generic
from cms.permissions import user_allowed_to_upload
from files.helpers import rm_file from files.helpers import rm_file
from files.methods import user_allowed_to_upload
from files.models import Media from files.models import Media
from .fineuploader import ChunkedFineUploader from .fineuploader import ChunkedFineUploader