mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-05-02 03:00:12 -04:00
this
This commit is contained in:
@@ -9,8 +9,7 @@ repos:
|
|||||||
- id: isort
|
- id: isort
|
||||||
args: ["--profile", "black"]
|
args: ["--profile", "black"]
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 23.1.0
|
rev: 24.10.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
language_version: python3
|
language_version: python3
|
||||||
additional_dependencies: [ 'click==8.0.4' ]
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
VERSION = "8.93"
|
VERSION = "8.97"
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ class MediaList(APIView):
|
|||||||
conditions |= Q(category__in=rbac_categories)
|
conditions |= Q(category__in=rbac_categories)
|
||||||
|
|
||||||
media = base_queryset.filter(conditions).exclude(user=request.user).distinct()
|
media = base_queryset.filter(conditions).exclude(user=request.user).distinct()
|
||||||
|
include_sharing_info = True
|
||||||
elif author_param:
|
elif author_param:
|
||||||
user_queryset = User.objects.all()
|
user_queryset = User.objects.all()
|
||||||
user = get_object_or_404(user_queryset, username=author_param)
|
user = get_object_or_404(user_queryset, username=author_param)
|
||||||
@@ -268,7 +269,7 @@ class MediaList(APIView):
|
|||||||
if include_sharing_info:
|
if include_sharing_info:
|
||||||
prefetch_related_objects(
|
prefetch_related_objects(
|
||||||
page,
|
page,
|
||||||
Prefetch('permissions', queryset=MediaPermission.objects.select_related('user')),
|
Prefetch('permissions', queryset=MediaPermission.objects.select_related('user').exclude(user=request.user)),
|
||||||
Prefetch('category', queryset=Category.objects.filter(is_rbac_category=True).prefetch_related('rbac_groups'), to_attr='rbac_categories_prefetched'),
|
Prefetch('category', queryset=Category.objects.filter(is_rbac_category=True).prefetch_related('rbac_groups'), to_attr='rbac_categories_prefetched'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+41
-11
@@ -7,6 +7,7 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.core.mail import EmailMessage
|
from django.core.mail import EmailMessage
|
||||||
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.utils.html import mark_safe, strip_tags
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
from cms.version import VERSION
|
from cms.version import VERSION
|
||||||
@@ -262,20 +263,42 @@ def video_chapters(request, friendly_token):
|
|||||||
data = request_data.get("chapters")
|
data = request_data.get("chapters")
|
||||||
if data is None:
|
if data is None:
|
||||||
return JsonResponse({'success': False, 'error': 'Request must contain "chapters" array'}, status=400)
|
return JsonResponse({'success': False, 'error': 'Request must contain "chapters" array'}, status=400)
|
||||||
|
if not isinstance(data, list):
|
||||||
|
return JsonResponse({'success': False, 'error': '"chapters" must be an array'}, status=400)
|
||||||
|
if len(data) > 200:
|
||||||
|
return JsonResponse({'success': False, 'error': 'Too many chapters (max 200)'}, status=400)
|
||||||
|
|
||||||
chapters = []
|
chapters = []
|
||||||
for _, chapter_data in enumerate(data):
|
for chapter_data in data:
|
||||||
|
if not isinstance(chapter_data, dict):
|
||||||
|
continue
|
||||||
start_time = chapter_data.get('startTime')
|
start_time = chapter_data.get('startTime')
|
||||||
end_time = chapter_data.get('endTime')
|
end_time = chapter_data.get('endTime')
|
||||||
chapter_title = chapter_data.get('chapterTitle')
|
chapter_title = chapter_data.get('chapterTitle')
|
||||||
if start_time and end_time and chapter_title:
|
|
||||||
chapters.append(
|
if not isinstance(start_time, (int, float)):
|
||||||
{
|
continue
|
||||||
'startTime': start_time,
|
if not isinstance(end_time, (int, float)):
|
||||||
'endTime': end_time,
|
continue
|
||||||
'chapterTitle': chapter_title,
|
if not isinstance(chapter_title, str) or not chapter_title.strip():
|
||||||
}
|
continue
|
||||||
)
|
|
||||||
|
start_time = float(start_time)
|
||||||
|
end_time = float(end_time)
|
||||||
|
if start_time < 0 or end_time < 0 or start_time >= end_time:
|
||||||
|
continue
|
||||||
|
|
||||||
|
chapter_title = strip_tags(chapter_title).strip()[:500]
|
||||||
|
if not chapter_title:
|
||||||
|
continue
|
||||||
|
|
||||||
|
chapters.append(
|
||||||
|
{
|
||||||
|
'startTime': start_time,
|
||||||
|
'endTime': end_time,
|
||||||
|
'chapterTitle': chapter_title,
|
||||||
|
}
|
||||||
|
)
|
||||||
except Exception as e: # noqa
|
except Exception as e: # noqa
|
||||||
return JsonResponse({'success': False, 'error': 'Request data must be a list of video chapters with startTime, endTime, chapterTitle'}, status=400)
|
return JsonResponse({'success': False, 'error': 'Request data must be a list of video chapters with startTime, endTime, chapterTitle'}, status=400)
|
||||||
|
|
||||||
@@ -449,11 +472,18 @@ def edit_chapters(request):
|
|||||||
if not (is_mediacms_editor(request.user) or request.user.has_contributor_access_to_media(media)):
|
if not (is_mediacms_editor(request.user) or request.user.has_contributor_access_to_media(media)):
|
||||||
return HttpResponseRedirect("/")
|
return HttpResponseRedirect("/")
|
||||||
|
|
||||||
chapters = media.chapter_data
|
_html_escapes = str.maketrans({'<': r'\u003C', '>': r'\u003E', '&': r'\u0026'})
|
||||||
|
chapters_json = mark_safe(json.dumps(media.chapter_data).translate(_html_escapes))
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"cms/edit_chapters.html",
|
"cms/edit_chapters.html",
|
||||||
{"media_object": media, "add_subtitle_url": media.add_subtitle_url, "media_file_path": helpers.url_from_path(media.media_file.path), "media_id": media.friendly_token, "chapters": chapters},
|
{
|
||||||
|
"media_object": media,
|
||||||
|
"add_subtitle_url": media.add_subtitle_url,
|
||||||
|
"media_file_path": helpers.url_from_path(media.media_file.path),
|
||||||
|
"media_id": media.friendly_token,
|
||||||
|
"chapters": chapters_json,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ class NavMenuInlineTabs extends React.PureComponent {
|
|||||||
</li>
|
</li>
|
||||||
) : null}
|
) : null}
|
||||||
{this.props.onToggleSharingClick &&
|
{this.props.onToggleSharingClick &&
|
||||||
['media', 'shared_by_me'].includes(this.props.type) ? (
|
['media', 'shared_by_me', 'shared_with_me'].includes(this.props.type) ? (
|
||||||
<li className="media-sharing-toggle">
|
<li className="media-sharing-toggle">
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export function ProfileMediaSharing(props) {
|
|||||||
<div ref={innerContainerRef} className="mi-filters-row-inner">
|
<div ref={innerContainerRef} className="mi-filters-row-inner">
|
||||||
{hasUsers ? (
|
{hasUsers ? (
|
||||||
<div className="mi-filter mi-filter-full-width">
|
<div className="mi-filter mi-filter-full-width">
|
||||||
<div className="mi-filter-title">{translateString('SHARED WITH USERS')}</div>
|
<div className="mi-filter-title">{translateString('USERS SHARING')}</div>
|
||||||
<div className="mi-filter-options mi-filter-options-horizontal mi-sharing-filter-options">
|
<div className="mi-filter-options mi-filter-options-horizontal mi-sharing-filter-options">
|
||||||
<FilterOptions id="shared_user" options={usersOptions} selected={selectedUser} onSelect={onUserSelect} />
|
<FilterOptions id="shared_user" options={usersOptions} selected={selectedUser} onSelect={onUserSelect} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import ProfilePagesContent from '../components/profile-page/ProfilePagesContent'
|
|||||||
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
|
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
|
||||||
import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFilters';
|
import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFilters';
|
||||||
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
|
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
|
||||||
|
import { ProfileMediaSharing } from '../components/search-filters/ProfileMediaSharing';
|
||||||
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
|
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
|
||||||
import { inEmbeddedApp, inSelectMediaEmbedMode } from '../utils/helpers';
|
import { inEmbeddedApp, inSelectMediaEmbedMode } from '../utils/helpers';
|
||||||
|
|
||||||
@@ -45,11 +46,16 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
hiddenFilters: true,
|
hiddenFilters: true,
|
||||||
hiddenTags: true,
|
hiddenTags: true,
|
||||||
hiddenSorting: true,
|
hiddenSorting: true,
|
||||||
|
hiddenSharing: true,
|
||||||
filterArgs: '',
|
filterArgs: '',
|
||||||
availableTags: [],
|
availableTags: [],
|
||||||
selectedTag: 'all',
|
selectedTag: 'all',
|
||||||
selectedSort: 'date_added_desc',
|
selectedSort: 'date_added_desc',
|
||||||
selectedMedia: new Set(), // For select media mode
|
selectedMedia: new Set(), // For select media mode
|
||||||
|
sharedUsers: [],
|
||||||
|
sharedGroups: [],
|
||||||
|
selectedSharingType: null,
|
||||||
|
selectedSharingValue: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.authorDataLoad = this.authorDataLoad.bind(this);
|
this.authorDataLoad = this.authorDataLoad.bind(this);
|
||||||
@@ -59,9 +65,11 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
|
this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
|
||||||
this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
|
this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
|
||||||
this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
|
this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
|
||||||
|
this.onToggleSharingClick = this.onToggleSharingClick.bind(this);
|
||||||
this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
|
this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
|
||||||
this.onTagSelect = this.onTagSelect.bind(this);
|
this.onTagSelect = this.onTagSelect.bind(this);
|
||||||
this.onSortSelect = this.onSortSelect.bind(this);
|
this.onSortSelect = this.onSortSelect.bind(this);
|
||||||
|
this.onSharingSelect = this.onSharingSelect.bind(this);
|
||||||
this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
|
this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
|
||||||
this.handleMediaSelection = this.handleMediaSelection.bind(this);
|
this.handleMediaSelection = this.handleMediaSelection.bind(this);
|
||||||
|
|
||||||
@@ -175,6 +183,7 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
hiddenFilters: !this.state.hiddenFilters,
|
hiddenFilters: !this.state.hiddenFilters,
|
||||||
hiddenTags: true,
|
hiddenTags: true,
|
||||||
hiddenSorting: true,
|
hiddenSorting: true,
|
||||||
|
hiddenSharing: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,6 +192,7 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
hiddenFilters: true,
|
hiddenFilters: true,
|
||||||
hiddenTags: !this.state.hiddenTags,
|
hiddenTags: !this.state.hiddenTags,
|
||||||
hiddenSorting: true,
|
hiddenSorting: true,
|
||||||
|
hiddenSharing: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +201,16 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
hiddenFilters: true,
|
hiddenFilters: true,
|
||||||
hiddenTags: true,
|
hiddenTags: true,
|
||||||
hiddenSorting: !this.state.hiddenSorting,
|
hiddenSorting: !this.state.hiddenSorting,
|
||||||
|
hiddenSharing: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onToggleSharingClick() {
|
||||||
|
this.setState({
|
||||||
|
hiddenFilters: true,
|
||||||
|
hiddenTags: true,
|
||||||
|
hiddenSorting: true,
|
||||||
|
hiddenSharing: !this.state.hiddenSharing,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,6 +223,8 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
|
publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
|
||||||
sort_by: this.state.selectedSort,
|
sort_by: this.state.selectedSort,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
|
sharing_type: this.state.selectedSharingType,
|
||||||
|
sharing_value: this.state.selectedSharingValue,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -216,6 +238,23 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
|
publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
|
||||||
sort_by: sortBy,
|
sort_by: sortBy,
|
||||||
tag: this.state.selectedTag,
|
tag: this.state.selectedTag,
|
||||||
|
sharing_type: this.state.selectedSharingType,
|
||||||
|
sharing_value: this.state.selectedSharingValue,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSharingSelect(type, value) {
|
||||||
|
this.setState({ selectedSharingType: type, selectedSharingValue: value }, () => {
|
||||||
|
this.onFiltersUpdate({
|
||||||
|
media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
|
||||||
|
upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
|
||||||
|
duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
|
||||||
|
publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
|
||||||
|
sort_by: this.state.selectedSort,
|
||||||
|
tag: this.state.selectedTag,
|
||||||
|
sharing_type: type,
|
||||||
|
sharing_value: value,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -229,6 +268,8 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
sort_by: null,
|
sort_by: null,
|
||||||
ordering: null,
|
ordering: null,
|
||||||
t: null,
|
t: null,
|
||||||
|
shared_user: null,
|
||||||
|
shared_group: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (updatedArgs.media_type) {
|
switch (updatedArgs.media_type) {
|
||||||
@@ -290,6 +331,12 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
args.t = updatedArgs.tag;
|
args.t = updatedArgs.tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updatedArgs.sharing_type === 'user' && updatedArgs.sharing_value) {
|
||||||
|
args.shared_user = updatedArgs.sharing_value;
|
||||||
|
} else if (updatedArgs.sharing_type === 'group' && updatedArgs.sharing_value) {
|
||||||
|
args.shared_group = updatedArgs.sharing_value;
|
||||||
|
}
|
||||||
|
|
||||||
const newArgs = [];
|
const newArgs = [];
|
||||||
|
|
||||||
for (let arg in args) {
|
for (let arg in args) {
|
||||||
@@ -341,6 +388,12 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
.filter((tag) => tag);
|
.filter((tag) => tag);
|
||||||
this.setState({ availableTags: tags });
|
this.setState({ availableTags: tags });
|
||||||
}
|
}
|
||||||
|
if (responseData && responseData.shared_users !== undefined) {
|
||||||
|
this.setState({
|
||||||
|
sharedUsers: responseData.shared_users || [],
|
||||||
|
sharedGroups: responseData.shared_groups || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMediaSelection(mediaId, isSelected) {
|
handleMediaSelection(mediaId, isSelected) {
|
||||||
@@ -411,9 +464,11 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
onToggleFiltersClick={this.onToggleFiltersClick}
|
onToggleFiltersClick={this.onToggleFiltersClick}
|
||||||
onToggleTagsClick={this.onToggleTagsClick}
|
onToggleTagsClick={this.onToggleTagsClick}
|
||||||
onToggleSortingClick={this.onToggleSortingClick}
|
onToggleSortingClick={this.onToggleSortingClick}
|
||||||
|
onToggleSharingClick={this.onToggleSharingClick}
|
||||||
hasActiveFilters={hasActiveFilters}
|
hasActiveFilters={hasActiveFilters}
|
||||||
hasActiveTags={this.state.selectedTag !== 'all'}
|
hasActiveTags={this.state.selectedTag !== 'all'}
|
||||||
hasActiveSort={this.state.selectedSort !== 'date_added_desc'}
|
hasActiveSort={this.state.selectedSort !== 'date_added_desc'}
|
||||||
|
hasActiveSharing={!!this.state.selectedSharingValue}
|
||||||
hideChannelBanner={inEmbeddedApp()}
|
hideChannelBanner={inEmbeddedApp()}
|
||||||
/>
|
/>
|
||||||
) : null,
|
) : null,
|
||||||
@@ -435,6 +490,14 @@ export class ProfileSharedWithMePage extends Page {
|
|||||||
onTagSelect={this.onTagSelect}
|
onTagSelect={this.onTagSelect}
|
||||||
/>
|
/>
|
||||||
<ProfileMediaSorting hidden={this.state.hiddenSorting} onSortSelect={this.onSortSelect} />
|
<ProfileMediaSorting hidden={this.state.hiddenSorting} onSortSelect={this.onSortSelect} />
|
||||||
|
<ProfileMediaSharing
|
||||||
|
hidden={this.state.hiddenSharing}
|
||||||
|
sharedUsers={this.state.sharedUsers}
|
||||||
|
sharedGroups={this.state.sharedGroups}
|
||||||
|
onSharingSelect={this.onSharingSelect}
|
||||||
|
selectedSharingType={this.state.selectedSharingType}
|
||||||
|
selectedSharingValue={this.state.selectedSharingValue}
|
||||||
|
/>
|
||||||
<LazyLoadItemListAsync
|
<LazyLoadItemListAsync
|
||||||
key={this.state.requestUrl}
|
key={this.state.requestUrl}
|
||||||
requestUrl={this.state.requestUrl}
|
requestUrl={this.state.requestUrl}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -16,7 +16,7 @@
|
|||||||
mediaId: "{{ media_object.friendly_token }}",
|
mediaId: "{{ media_object.friendly_token }}",
|
||||||
redirectURL: "{{ media_object.get_absolute_url }}",
|
redirectURL: "{{ media_object.get_absolute_url }}",
|
||||||
redirectUserMediaURL: "{{ media_object.user.get_absolute_url }}",
|
redirectUserMediaURL: "{{ media_object.user.get_absolute_url }}",
|
||||||
chapters: {{ chapters|safe }},
|
chapters: {{ chapters }},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
{%endblock topimports %}
|
{%endblock topimports %}
|
||||||
|
|||||||
Reference in New Issue
Block a user