This commit is contained in:
Markos Gogoulos
2026-04-26 16:59:10 +03:00
parent 8d47941568
commit d96620d0da
7 changed files with 47 additions and 49 deletions
+1
View File
@@ -667,3 +667,4 @@ if USE_LTI:
CSRF_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True
# SESSION_ENGINE = "django.contrib.sessions.backends.cached_db" # SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
# Consider using cached_db for reliability if sessions are lost between many LTI launches # Consider using cached_db for reliability if sessions are lost between many LTI launches
RELATED_MEDIA_STRATEGY = "no_related"
+1 -1
View File
@@ -1 +1 @@
VERSION = "8.99912" VERSION = "8.99914"
+3 -6
View File
@@ -138,8 +138,9 @@ class MediaPublishForm(forms.ModelForm):
self.was_shared = self.instance.is_shared if self.instance.pk else False self.was_shared = self.instance.is_shared if self.instance.pk else False
is_embed_mode = self._check_embed_mode() is_embed_mode = self._check_embed_mode()
if not is_embed_mode:
self.fields.pop('shared') self.fields["shared"].initial = self.was_shared
self.initial["shared"] = self.was_shared
if not is_mediacms_editor(user): if not is_mediacms_editor(user):
for field in ["featured", "reported_times", "is_reviewed"]: for field in ["featured", "reported_times", "is_reviewed"]:
@@ -153,10 +154,6 @@ class MediaPublishForm(forms.ModelForm):
valid_states.append(self.instance.state) valid_states.append(self.instance.state)
self.fields["state"].choices = [(state, dict(MEDIA_STATES).get(state, state)) for state in valid_states] self.fields["state"].choices = [(state, dict(MEDIA_STATES).get(state, state)) for state in valid_states]
if is_embed_mode:
self.fields["shared"].initial = self.was_shared
self.initial["shared"] = self.was_shared
if getattr(settings, 'USE_RBAC', False) and 'category' in self.fields: if getattr(settings, 'USE_RBAC', False) and 'category' in self.fields:
if is_mediacms_editor(user): if is_mediacms_editor(user):
pass pass
+2
View File
@@ -238,6 +238,8 @@ def show_related_media(media, request=None, limit=100):
return show_related_media_calculated(media, request, limit) return show_related_media_calculated(media, request, limit)
elif settings.RELATED_MEDIA_STRATEGY == "author": elif settings.RELATED_MEDIA_STRATEGY == "author":
return show_related_media_author(media, request, limit) return show_related_media_author(media, request, limit)
elif settings.RELATED_MEDIA_STRATEGY == "no_related":
return []
return show_related_media_content(media, request, limit) return show_related_media_content(media, request, limit)
+2 -9
View File
@@ -509,16 +509,9 @@ class MediaBulkUserActions(APIView):
m.save(update_fields=["state", "listable"]) m.save(update_fields=["state", "listable"])
shared = request.data.get('shared', None) remove_sharing = request.data.get('remove_sharing', False)
if shared is True: if remove_sharing:
for m in media:
MediaPermission.objects.get_or_create(
media=m,
user=request.user,
defaults={'owner_user': request.user, 'permission': 'owner'},
)
elif shared is False or (shared is None and state == 'private'):
MediaPermission.objects.filter(media__in=media).delete() MediaPermission.objects.filter(media__in=media).delete()
for m in media: for m in media:
rbac_cats = m.category.filter(is_rbac_category=True) rbac_cats = m.category.filter(is_rbac_category=True)
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect } from 'react';
import './BulkActionPublishStateModal.scss'; import './BulkActionPublishStateModal.scss';
import { translateString } from '../utils/helpers/'; import { translateString } from '../utils/helpers/';
@@ -29,31 +29,29 @@ export const BulkActionPublishStateModal: React.FC<BulkActionPublishStateModalPr
sessionStorage.getItem('lms_embed_mode') === 'true' || sessionStorage.getItem('lms_embed_mode') === 'true' ||
new URLSearchParams(window.location.search).get('mode') === 'lms_embed_mode'; new URLSearchParams(window.location.search).get('mode') === 'lms_embed_mode';
const availableStates = isLmsEmbedMode ? PUBLISH_STATES.filter((s) => s.value !== 'public') : PUBLISH_STATES; const availableStates = isLmsEmbedMode ? PUBLISH_STATES.filter((s) => s.value !== 'public') : PUBLISH_STATES;
const defaultState = availableStates[0].value;
const [selectedState, setSelectedState] = useState(defaultState); const [selectedState, setSelectedState] = useState('');
const [shared, setShared] = useState<boolean | null>(null); const [removeSharing, setRemoveSharing] = useState(false);
const [acknowledged, setAcknowledged] = useState(false);
const [isProcessing, setIsProcessing] = useState(false); const [isProcessing, setIsProcessing] = useState(false);
const sharedRef = useRef<HTMLInputElement>(null);
useEffect(() => { useEffect(() => {
if (!isOpen) { if (!isOpen) {
setSelectedState(defaultState); setSelectedState('');
setShared(null); setRemoveSharing(false);
setAcknowledged(false);
} }
}, [isOpen]); }, [isOpen]);
useEffect(() => {
if (sharedRef.current) {
sharedRef.current.indeterminate = shared === null;
}
}, [shared]);
const handleSubmit = async () => { const handleSubmit = async () => {
if (!selectedState) { if (!selectedState) {
onError(translateString('Please select a publish state')); onError(translateString('Please select a publish state'));
return; return;
} }
if (removeSharing && !acknowledged) {
onError(translateString('Please acknowledge the sharing removal'));
return;
}
setIsProcessing(true); setIsProcessing(true);
@@ -63,8 +61,8 @@ export const BulkActionPublishStateModal: React.FC<BulkActionPublishStateModalPr
media_ids: selectedMediaIds, media_ids: selectedMediaIds,
state: selectedState, state: selectedState,
}; };
if (shared !== null) { if (removeSharing) {
body.shared = shared; body.remove_sharing = true;
} }
const response = await fetch('/api/v1/media/user/bulk_actions', { const response = await fetch('/api/v1/media/user/bulk_actions', {
@@ -93,13 +91,6 @@ export const BulkActionPublishStateModal: React.FC<BulkActionPublishStateModalPr
if (!isOpen) return null; if (!isOpen) return null;
const sharedNote =
shared === null
? translateString('Sharing status will not be changed.')
: shared
? translateString('Selected media will be marked as shared.')
: translateString('Sharing will be removed from all selected media.');
return ( return (
<div className="publish-state-modal-overlay"> <div className="publish-state-modal-overlay">
<div className="publish-state-modal"> <div className="publish-state-modal">
@@ -119,6 +110,9 @@ export const BulkActionPublishStateModal: React.FC<BulkActionPublishStateModalPr
onChange={(e) => setSelectedState(e.target.value)} onChange={(e) => setSelectedState(e.target.value)}
disabled={isProcessing} disabled={isProcessing}
> >
<option value="" disabled>
{translateString('— select —')}
</option>
{availableStates.map((state) => ( {availableStates.map((state) => (
<option key={state.value} value={state.value}> <option key={state.value} value={state.value}>
{state.label} {state.label}
@@ -127,23 +121,34 @@ export const BulkActionPublishStateModal: React.FC<BulkActionPublishStateModalPr
</select> </select>
</div> </div>
{isLmsEmbedMode && ( <div className="shared-selector">
<div className="shared-selector">
<label className="shared-selector-label"> <label className="shared-selector-label">
<input <input
ref={sharedRef}
type="checkbox" type="checkbox"
checked={shared === true} checked={removeSharing}
onChange={(e) => setShared(e.target.checked)} onChange={(e) => {
setRemoveSharing(e.target.checked);
if (!e.target.checked) setAcknowledged(false);
}}
disabled={isProcessing} disabled={isProcessing}
/> />
{translateString('Shared')} {translateString('Remove Sharing')}
</label> </label>
<p className={`shared-selector-note${shared === false ? ' shared-selector-note--warn' : ''}`}> <p className="shared-selector-note shared-selector-note--warn">
{sharedNote} {translateString('Sharing will be removed from all selected media.')}
</p> </p>
{removeSharing && (
<label className="shared-selector-label shared-selector-acknowledge">
<input
type="checkbox"
checked={acknowledged}
onChange={(e) => setAcknowledged(e.target.checked)}
disabled={isProcessing}
/>
{translateString('I understand that this will remove all existing sharing for this media.')}
</label>
)}
</div> </div>
)}
</div> </div>
<div className="publish-state-modal-footer"> <div className="publish-state-modal-footer">
@@ -153,7 +158,7 @@ export const BulkActionPublishStateModal: React.FC<BulkActionPublishStateModalPr
<button <button
className="publish-state-btn publish-state-btn-submit" className="publish-state-btn publish-state-btn-submit"
onClick={handleSubmit} onClick={handleSubmit}
disabled={isProcessing} disabled={isProcessing || (removeSharing && !acknowledged)}
> >
{isProcessing ? translateString('Processing...') : translateString('Submit')} {isProcessing ? translateString('Processing...') : translateString('Submit')}
</button> </button>
File diff suppressed because one or more lines are too long