mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-01-23 10:45:27 +00:00
parent
65e0be80e0
commit
ba6012b28c
3 changed files with 110 additions and 32 deletions
|
|
@ -8,7 +8,7 @@ from drf_yasg.utils import swagger_auto_schema
|
|||
from drf_yasg import openapi
|
||||
from django.shortcuts import get_object_or_404, get_list_or_404
|
||||
from django.db import transaction
|
||||
import os, json, requests
|
||||
import os, json, requests, logging
|
||||
from apps.accounts.permissions import (
|
||||
Authenticated,
|
||||
IsAdmin,
|
||||
|
|
@ -48,6 +48,9 @@ import mimetypes
|
|||
from rest_framework.pagination import PageNumberPagination
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OrInFilter(django_filters.Filter):
|
||||
"""
|
||||
Custom filter that handles the OR condition instead of AND.
|
||||
|
|
@ -275,30 +278,76 @@ class ChannelViewSet(viewsets.ModelViewSet):
|
|||
|
||||
@action(detail=False, methods=["patch"], url_path="edit/bulk")
|
||||
def edit_bulk(self, request):
|
||||
data_list = request.data
|
||||
if not isinstance(data_list, list):
|
||||
"""
|
||||
Bulk edit channels.
|
||||
Expects a list of channels with their updates.
|
||||
"""
|
||||
data = request.data
|
||||
if not isinstance(data, list):
|
||||
return Response(
|
||||
{"error": "Expected a list of channel objects objects"},
|
||||
{"error": "Expected a list of channel updates"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
updated_channels = []
|
||||
try:
|
||||
with transaction.atomic():
|
||||
for item in data_list:
|
||||
channel = Channel.objects.id(id=item.pop("id"))
|
||||
for key, value in item.items():
|
||||
setattr(channel, key, value)
|
||||
errors = []
|
||||
|
||||
channel.save(update_fields=item.keys())
|
||||
updated_channels.append(channel)
|
||||
except Exception as e:
|
||||
logger.error("Error during bulk channel edit", e)
|
||||
return Response({"error": e}, status=500)
|
||||
for channel_data in data:
|
||||
channel_id = channel_data.get("id")
|
||||
if not channel_id:
|
||||
errors.append({"error": "Channel ID is required"})
|
||||
continue
|
||||
|
||||
response_data = ChannelSerializer(updated_channels, many=True).data
|
||||
try:
|
||||
channel = Channel.objects.get(id=channel_id)
|
||||
|
||||
return Response(response_data, status=status.HTTP_200_OK)
|
||||
# Handle channel_group_id properly - convert string to integer if needed
|
||||
if 'channel_group_id' in channel_data:
|
||||
group_id = channel_data['channel_group_id']
|
||||
if group_id is not None:
|
||||
try:
|
||||
channel_data['channel_group_id'] = int(group_id)
|
||||
except (ValueError, TypeError):
|
||||
channel_data['channel_group_id'] = None
|
||||
|
||||
# Use the serializer to validate and update
|
||||
serializer = ChannelSerializer(
|
||||
channel, data=channel_data, partial=True
|
||||
)
|
||||
|
||||
if serializer.is_valid():
|
||||
updated_channel = serializer.save()
|
||||
updated_channels.append(updated_channel)
|
||||
else:
|
||||
errors.append({
|
||||
"channel_id": channel_id,
|
||||
"errors": serializer.errors
|
||||
})
|
||||
|
||||
except Channel.DoesNotExist:
|
||||
errors.append({
|
||||
"channel_id": channel_id,
|
||||
"error": "Channel not found"
|
||||
})
|
||||
except Exception as e:
|
||||
errors.append({
|
||||
"channel_id": channel_id,
|
||||
"error": str(e)
|
||||
})
|
||||
|
||||
if errors:
|
||||
return Response(
|
||||
{"errors": errors, "updated_count": len(updated_channels)},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
# Serialize the updated channels for response
|
||||
serialized_channels = ChannelSerializer(updated_channels, many=True).data
|
||||
|
||||
return Response({
|
||||
"message": f"Successfully updated {len(updated_channels)} channels",
|
||||
"channels": serialized_channels
|
||||
})
|
||||
|
||||
@action(detail=False, methods=["get"], url_path="ids")
|
||||
def get_ids(self, request, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -390,9 +390,9 @@ export default class API {
|
|||
|
||||
static async updateChannels(ids, values) {
|
||||
const body = [];
|
||||
for (const id in ids) {
|
||||
for (const id of ids) {
|
||||
body.push({
|
||||
id,
|
||||
id: id,
|
||||
...values,
|
||||
});
|
||||
}
|
||||
|
|
@ -406,7 +406,10 @@ export default class API {
|
|||
}
|
||||
);
|
||||
|
||||
useChannelsStore.getState().updateChannels(response);
|
||||
// Pass the channels array from the response, not the entire response
|
||||
if (response.channels) {
|
||||
useChannelsStore.getState().updateChannels(response.channels);
|
||||
}
|
||||
return response;
|
||||
} catch (e) {
|
||||
errorNotification('Failed to update channels', e);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ const ChannelBatchForm = ({ channelIds, isOpen, onClose }) => {
|
|||
|
||||
const [channelGroupModelOpen, setChannelGroupModalOpen] = useState(false);
|
||||
const [selectedChannelGroup, setSelectedChannelGroup] = useState('');
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const [groupPopoverOpened, setGroupPopoverOpened] = useState(false);
|
||||
const [groupFilter, setGroupFilter] = useState('');
|
||||
|
|
@ -51,27 +52,38 @@ const ChannelBatchForm = ({ channelIds, isOpen, onClose }) => {
|
|||
});
|
||||
|
||||
const onSubmit = async () => {
|
||||
setIsSubmitting(true);
|
||||
|
||||
const values = {
|
||||
...form.getValues(),
|
||||
channel_group_id: selectedChannelGroup,
|
||||
};
|
||||
|
||||
// Handle channel group ID - convert to integer if it exists
|
||||
if (selectedChannelGroup) {
|
||||
values.channel_group_id = parseInt(selectedChannelGroup);
|
||||
} else {
|
||||
delete values.channel_group_id;
|
||||
}
|
||||
|
||||
if (!values.stream_profile_id || values.stream_profile_id === '0') {
|
||||
values.stream_profile_id = null;
|
||||
}
|
||||
|
||||
if (!values.channel_group_id) {
|
||||
delete values.channel_group_id;
|
||||
}
|
||||
|
||||
if (values.user_level == '-1') {
|
||||
delete values.user_level;
|
||||
}
|
||||
|
||||
await API.batchUpdateChannels({
|
||||
ids: channelIds,
|
||||
values,
|
||||
});
|
||||
// Remove the channel_group field from form values as we use channel_group_id
|
||||
delete values.channel_group;
|
||||
|
||||
try {
|
||||
await API.updateChannels(channelIds, values);
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error('Failed to update channels:', error);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
|
|
@ -151,6 +163,21 @@ const ChannelBatchForm = ({ channelIds, isOpen, onClose }) => {
|
|||
onClick={() => setGroupPopoverOpened(true)}
|
||||
size="xs"
|
||||
style={{ flex: 1 }}
|
||||
rightSection={
|
||||
form.getValues().channel_group && (
|
||||
<ActionIcon
|
||||
size="xs"
|
||||
variant="subtle"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedChannelGroup('');
|
||||
form.setValues({ channel_group: '' });
|
||||
}}
|
||||
>
|
||||
<X size={12} />
|
||||
</ActionIcon>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<ActionIcon
|
||||
|
|
@ -264,7 +291,7 @@ const ChannelBatchForm = ({ channelIds, isOpen, onClose }) => {
|
|||
label: '(no change)',
|
||||
},
|
||||
].concat(
|
||||
Object.entries(USER_LEVELS).map(([label, value]) => {
|
||||
Object.entries(USER_LEVELS).map(([, value]) => {
|
||||
return {
|
||||
label: USER_LEVEL_LABELS[value],
|
||||
value: `${value}`,
|
||||
|
|
@ -274,9 +301,8 @@ const ChannelBatchForm = ({ channelIds, isOpen, onClose }) => {
|
|||
/>
|
||||
</Stack>
|
||||
</Group>
|
||||
|
||||
<Flex mih={50} gap="xs" justify="flex-end" align="flex-end">
|
||||
<Button type="submit" variant="default" disabled={form.submitting}>
|
||||
<Button type="submit" variant="default" disabled={isSubmitting}>
|
||||
Submit
|
||||
</Button>
|
||||
</Flex>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue