mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-03-07 20:58:35 -05:00
wtv
This commit is contained in:
@@ -574,12 +574,32 @@ class MediaBulkUserActions(APIView):
|
||||
|
||||
elif action == "add_to_category":
|
||||
category_uids = request.data.get('category_uids', [])
|
||||
if not category_uids:
|
||||
return Response({"detail": "category_uids is required for add_to_category action"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
lti_context_id = request.data.get('lti_context_id')
|
||||
|
||||
if not category_uids and not lti_context_id:
|
||||
return Response({"detail": "category_uids or lti_context_id is required for add_to_category action"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
categories = Category.objects.none()
|
||||
|
||||
# Prioritize category_uids
|
||||
if category_uids:
|
||||
# Filter categories by UID and ensure they are NOT RBAC categories
|
||||
categories = Category.objects.filter(uid__in=category_uids, is_rbac_category=False)
|
||||
elif lti_context_id:
|
||||
# Filter categories by lti_context_id and ensure they ARE RBAC categories
|
||||
potential_categories = Category.objects.filter(lti_context_id=lti_context_id, is_rbac_category=True)
|
||||
|
||||
# Check user access (must have contributor access)
|
||||
valid_category_ids = []
|
||||
for cat in potential_categories:
|
||||
if request.user.has_contributor_access_to_category(cat):
|
||||
valid_category_ids.append(cat.id)
|
||||
|
||||
if valid_category_ids:
|
||||
categories = Category.objects.filter(id__in=valid_category_ids)
|
||||
|
||||
categories = Category.objects.filter(uid__in=category_uids)
|
||||
if not categories:
|
||||
return Response({"detail": "No matching categories found"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response({"detail": "No matching categories found or access denied"}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
added_count = 0
|
||||
for category in categories:
|
||||
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { ApiUrlContext, LinksConsumer, MemberContext } from '../utils/contexts';
|
||||
import { PageStore, ProfilePageStore } from '../utils/stores';
|
||||
import { ProfilePageActions, PageActions } from '../utils/actions';
|
||||
import { inEmbeddedApp, inSelectMediaEmbedMode, translateString } from '../utils/helpers/';
|
||||
import { inEmbeddedApp, inSelectMediaEmbedMode, associateMediaWithLtiCategory, translateString } from '../utils/helpers/';
|
||||
import { MediaListWrapper } from '../components/MediaListWrapper';
|
||||
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
||||
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
||||
@@ -213,6 +213,9 @@ export class ProfileMediaPage extends Page {
|
||||
newSelectedMedia.add(mediaId);
|
||||
console.log('Selected media item:', mediaId);
|
||||
|
||||
// Associate media with the current LTI course category (fire-and-forget)
|
||||
associateMediaWithLtiCategory(mediaId);
|
||||
|
||||
// Send postMessage to parent window (Moodle TinyMCE plugin)
|
||||
if (window.parent !== window) {
|
||||
// Construct the embed URL
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFi
|
||||
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
|
||||
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
|
||||
import { BulkActionsModals } from '../components/BulkActionsModals';
|
||||
import { inEmbeddedApp, inSelectMediaEmbedMode, translateString } from '../utils/helpers';
|
||||
import { inEmbeddedApp, inSelectMediaEmbedMode, associateMediaWithLtiCategory, translateString } from '../utils/helpers';
|
||||
import { withBulkActions } from '../utils/hoc/withBulkActions';
|
||||
|
||||
import { Page } from './_Page';
|
||||
@@ -357,6 +357,9 @@ class ProfileSharedByMePage extends Page {
|
||||
newSelectedMedia.add(mediaId);
|
||||
console.log('Selected media item:', mediaId);
|
||||
|
||||
// Associate media with the current LTI course category (fire-and-forget)
|
||||
associateMediaWithLtiCategory(mediaId);
|
||||
|
||||
// Send postMessage to parent window (Moodle TinyMCE plugin)
|
||||
if (window.parent !== window) {
|
||||
// Construct the embed URL
|
||||
|
||||
@@ -10,7 +10,7 @@ import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListA
|
||||
import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFilters';
|
||||
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
|
||||
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
|
||||
import { inEmbeddedApp, inSelectMediaEmbedMode, translateString } from '../utils/helpers';
|
||||
import { inEmbeddedApp, inSelectMediaEmbedMode, associateMediaWithLtiCategory, translateString } from '../utils/helpers';
|
||||
|
||||
import { Page } from './_Page';
|
||||
|
||||
@@ -355,6 +355,9 @@ export class ProfileSharedWithMePage extends Page {
|
||||
newSelectedMedia.add(mediaId);
|
||||
console.log('Selected media item:', mediaId);
|
||||
|
||||
// Associate media with the current LTI course category (fire-and-forget)
|
||||
associateMediaWithLtiCategory(mediaId);
|
||||
|
||||
// Send postMessage to parent window (Moodle TinyMCE plugin)
|
||||
if (window.parent !== window) {
|
||||
// Construct the embed URL
|
||||
|
||||
@@ -33,3 +33,49 @@ export function isSelectMediaMode() {
|
||||
export function inSelectMediaEmbedMode() {
|
||||
return inEmbeddedApp() && isSelectMediaMode();
|
||||
}
|
||||
|
||||
export function getLtiContextId(): string | null {
|
||||
try {
|
||||
const params = new URL(globalThis.location.href).searchParams;
|
||||
const contextId = params.get('lti_context_id');
|
||||
|
||||
if (contextId) {
|
||||
sessionStorage.setItem('lti_context_id', contextId);
|
||||
return contextId;
|
||||
}
|
||||
|
||||
return sessionStorage.getItem('lti_context_id');
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function associateMediaWithLtiCategory(mediaId: string): void {
|
||||
const ltiContextId = getLtiContextId();
|
||||
|
||||
if (!ltiContextId || !mediaId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const csrfMatch = document.cookie.match(/(?:^|;\s*)csrftoken=([^;]+)/);
|
||||
const csrfToken = csrfMatch ? csrfMatch[1] : '';
|
||||
|
||||
fetch('/api/v1/media/user/bulk_actions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrfToken,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
action: 'add_to_category',
|
||||
media_ids: [mediaId],
|
||||
lti_context_id: ltiContextId,
|
||||
}),
|
||||
}).then(response => {
|
||||
if (!response.ok) {
|
||||
console.warn('[MediaCMS LTI] Failed to associate media with course category:', response.statusText);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.warn('[MediaCMS LTI] Failed to associate media with course category:', error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@ export * from './quickSort';
|
||||
export * from './requests';
|
||||
export { translateString } from './translate';
|
||||
export { replaceString } from './replacementStrings';
|
||||
export { inEmbeddedApp, inSelectMediaEmbedMode, isSelectMediaMode } from './embeddedApp';
|
||||
export { inEmbeddedApp, inSelectMediaEmbedMode, isSelectMediaMode, associateMediaWithLtiCategory } from './embeddedApp';
|
||||
|
||||
@@ -7,6 +7,7 @@ Allows instructors to select media from MediaCMS library and embed in Moodle cou
|
||||
import time
|
||||
import traceback
|
||||
import uuid
|
||||
from urllib.parse import quote
|
||||
|
||||
import jwt
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
@@ -37,6 +38,12 @@ class SelectMediaView(View):
|
||||
def get(self, request):
|
||||
"""Display media selection interface - redirects to user's profile page"""
|
||||
profile_url = f"/user/{request.user.username}?mode=lms_embed_mode&action=select_media"
|
||||
|
||||
lti_session = request.session.get('lti_session', {})
|
||||
lti_context_id = lti_session.get('context_id', '')
|
||||
if lti_context_id:
|
||||
profile_url += f"<i_context_id={quote(str(lti_context_id))}"
|
||||
|
||||
return HttpResponseRedirect(profile_url)
|
||||
|
||||
@method_decorator(csrf_exempt)
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user