@ -443,6 +443,107 @@ class AdminHadisViewSet(ModelViewSet):
return queryset . order_by ( " -id " )
@action ( detail = False , methods = [ " post " ] , url_path = " bulk-assign-topics " )
def bulk_assign_topics ( self , request ) :
from django.db import transaction
from rest_framework import status as drf_status
from .signals import invalidate_hadis_cache
hadis_ids = request . data . get ( " hadis_ids " ) or [ ]
category_ids = request . data . get ( " category_ids " ) or [ ]
mode = request . data . get ( " mode " , " add " )
if not isinstance ( hadis_ids , list ) or not hadis_ids :
return Response (
{ " detail " : " hadis_ids must be a non-empty list. " } ,
status = drf_status . HTTP_400_BAD_REQUEST ,
)
if not isinstance ( category_ids , list ) or not category_ids :
return Response (
{ " detail " : " category_ids must be a non-empty list. " } ,
status = drf_status . HTTP_400_BAD_REQUEST ,
)
try :
hadis_ids = [ int ( hid ) for hid in hadis_ids ]
category_ids = list ( dict . fromkeys ( int ( cid ) for cid in category_ids ) )
except ( ValueError , TypeError ) :
return Response (
{ " detail " : " Invalid ID format. " } ,
status = drf_status . HTTP_400_BAD_REQUEST ,
)
categories = list ( HadisCategory . objects . filter ( id__in = category_ids ) )
if len ( categories ) != len ( category_ids ) :
return Response (
{ " detail " : " One or more selected topics do not exist. " } ,
status = drf_status . HTTP_400_BAD_REQUEST ,
)
for cat in categories :
if cat . children . exists ( ) :
return Response (
{ " detail " : " Cannot assign items to a parent category that has subcategories. Please select leaf topics only. " } ,
status = drf_status . HTTP_400_BAD_REQUEST ,
)
hadises_qs = Hadis . objects . filter ( id__in = hadis_ids )
existing_hadis_ids = list ( hadises_qs . values_list ( " id " , flat = True ) )
if not existing_hadis_ids :
return Response (
{ " detail " : " No matching items found. " } ,
status = drf_status . HTTP_404_NOT_FOUND ,
)
through_model = Hadis . categories . through
first_category_id = category_ids [ 0 ]
with transaction . atomic ( ) :
if mode == " replace " :
through_model . objects . filter ( hadis_id__in = existing_hadis_ids ) . delete ( )
relations = [
through_model ( hadis_id = hid , hadiscategory_id = cid )
for hid in existing_hadis_ids
for cid in category_ids
]
through_model . objects . bulk_create ( relations , ignore_conflicts = True )
Hadis . objects . filter ( id__in = existing_hadis_ids ) . update ( category_id = first_category_id )
else :
relations = [
through_model ( hadis_id = hid , hadiscategory_id = cid )
for hid in existing_hadis_ids
for cid in category_ids
]
through_model . objects . bulk_create ( relations , ignore_conflicts = True )
Hadis . objects . filter ( id__in = existing_hadis_ids , category__isnull = True ) . update (
category_id = first_category_id
)
invalidate_hadis_cache ( )
cat_map = { c . id : c for c in categories }
ordered_cats = [ cat_map [ cid ] for cid in category_ids if cid in cat_map ]
categories_detail = [
{
" id " : c . id ,
" title " : c . title ,
" slug " : c . slug ,
" source_type " : c . source_type ,
" is_topic " : True ,
}
for c in ordered_cats
]
return Response (
{
" updated_count " : len ( existing_hadis_ids ) ,
" mode " : mode ,
" categories_detail " : categories_detail ,
} ,
status = drf_status . HTTP_200_OK ,
)
class AdminHadisCorrectionViewSet ( ModelViewSet ) :
serializer_class = AdminHadisCorrectionSerializer