1616use App \Http \Resources \AdminStarterKitHistoryResource ;
1717use App \Http \Resources \AdminStarterKitResource ;
1818use App \Http \Resources \AdminUserAuditLogResource ;
19+ use App \Http \Resources \AdminVideoResource ;
1920use App \Http \Resources \CommentReplyResource ;
2021use App \Http \Resources \CommentResource ;
2122use App \Http \Resources \ProfileResource ;
5960use App \Services \VersionCheckService ;
6061use App \Services \VideoService ;
6162use Illuminate \Http \Request ;
63+ use Illuminate \Support \Collection ;
6264use Illuminate \Support \Facades \Cache ;
6365use Illuminate \Support \Facades \DB ;
6466use Illuminate \Support \Facades \Hash ;
@@ -81,53 +83,111 @@ public function videos(Request $request)
8183 {
8284 $ search = $ request ->query ('q ' );
8385 $ sort = $ request ->query ('sort ' );
86+ $ local = $ request ->query ('local ' );
8487
8588 $ query = Video::when ($ search , function ($ query , $ search ) {
86- $ query ->join ('profiles ' , 'videos.profile_id ' , '= ' , 'profiles.id ' )
87- ->where ('profiles.username ' , 'like ' , '% ' .$ search .'% ' )
88- ->select ('videos.* ' );
89+ $ isUsername = str_starts_with ($ search , 'username: ' );
90+ if ($ isUsername ) {
91+ $ username = substr ($ search , 9 );
92+ $ query ->join ('profiles ' , 'videos.profile_id ' , '= ' , 'profiles.id ' )
93+ ->where ('profiles.username ' , $ username )
94+ ->select ('videos.* ' );
95+ } else {
96+ $ query ->where ('caption ' , 'like ' , '% ' .$ search .'% ' );
97+ }
8998 });
9099
100+ if ($ local == true ) {
101+ $ query ->where ('is_local ' , true );
102+ }
103+
91104 $ query = $ this ->applySorting ($ query , $ sort );
92105 $ videos = $ query ->orderByDesc ('id ' )->cursorPaginate (10 )->withQueryString ();
93106
94- return VideoResource ::collection ($ videos );
107+ return AdminVideoResource ::collection ($ videos );
95108 }
96109
97110 public function videoShow (Request $ request , $ id )
98111 {
99112 $ video = Video::findOrFail ($ id );
100113
101- $ res = (new VideoResource ($ video ))->toArray ($ request );
102- $ res ['status ' ] = $ video ->statusLabel ();
103- $ res ['media ' ]['size ' ] = $ video ->size_kb ;
104- $ res ['hid ' ] = $ video ->hashid ();
114+ $ res = (new AdminVideoResource ($ video ))->toArray ($ request );
105115 $ res ['reported_count ' ] = Report::whereReportedVideoId ($ id )->count ();
106116
107117 return $ this ->data ($ res );
108118 }
109119
110120 public function videoCommentsShow (Request $ request , $ id )
111121 {
122+ $ validated = $ request ->validate ([
123+ 'limit ' => 'sometimes|integer|min:1|max:50 ' ,
124+ 'sort ' => 'sometimes|nullable|in:newest,oldest,most_liked,most_comments ' ,
125+ ]);
126+
112127 $ video = Video::findOrFail ($ id );
128+ $ limit = $ validated ['limit ' ];
129+ $ sort = $ validated ['sort ' ] ?? 'newest ' ;
130+ $ sortBy = match ($ sort ) {
131+ 'newest ' => ['column ' => 'id ' , 'dir ' => 'desc ' ],
132+ 'oldest ' => ['column ' => 'id ' , 'dir ' => 'asc ' ],
133+ 'most_liked ' => ['column ' => 'likes ' , 'dir ' => 'desc ' ],
134+ 'most_comments ' => ['column ' => 'replies ' , 'dir ' => 'desc ' ],
135+ default => ['column ' => 'id ' , 'dir ' => 'desc ' ],
136+ };
113137
114- $ comments = Comment::whereVideoId ($ video ->id )
115- ->orderByDesc ('id ' )
116- ->cursorPaginate (5 );
138+ $ comments = Comment::withTrashed ()
139+ ->with ('mediaAttachments ' )
140+ ->whereVideoId ($ video ->id )
141+ ->orderBy ($ sortBy ['column ' ], $ sortBy ['dir ' ])
142+ ->cursorPaginate ($ limit );
117143
118144 return CommentResource::collection ($ comments );
119145 }
120146
121147 public function videoModerate (Request $ request , $ id )
122148 {
123149 $ request ->validate ([
124- 'action ' => 'required|in:unpublished,publish,delete ' ,
150+ 'action ' => 'required|in:unpublished,publish,delete,ai,ad,nsfw ' ,
125151 ]);
126152
127153 $ action = $ request ->input ('action ' );
128154
155+ $ video = Video::findOrFail ($ id );
156+
157+ if ($ action === 'ai ' ) {
158+ $ oldState = $ video ->contains_ai ;
159+ $ video ->contains_ai = ! $ video ->contains_ai ;
160+ $ video ->saveQuietly ();
161+ VideoService::getMediaData ($ video ->id , true );
162+ $ changes = ['old ' => ['contains_ai ' => $ oldState ], 'new ' => ['contains_ai ' => ! $ oldState ]];
163+ app (AdminAuditLogService::class)->logVideoModerate ($ request ->user (), $ video , $ changes );
164+
165+ return $ this ->data ((new AdminVideoResource ($ video )));
166+ }
167+
168+ if ($ action === 'ad ' ) {
169+ $ oldState = $ video ->contains_ad ;
170+ $ video ->contains_ad = ! $ video ->contains_ad ;
171+ $ video ->saveQuietly ();
172+ VideoService::getMediaData ($ video ->id , true );
173+ $ changes = ['old ' => ['contains_ad ' => $ oldState ], 'new ' => ['contains_ad ' => ! $ oldState ]];
174+ app (AdminAuditLogService::class)->logVideoModerate ($ request ->user (), $ video , $ changes );
175+
176+ return $ this ->data ((new AdminVideoResource ($ video )));
177+ }
178+
179+ if ($ action === 'nsfw ' ) {
180+ $ oldState = $ video ->is_sensitive ;
181+ $ video ->is_sensitive = ! $ video ->is_sensitive ;
182+ $ video ->saveQuietly ();
183+ VideoService::getMediaData ($ video ->id , true );
184+ $ changes = ['old ' => ['is_sensitive ' => $ oldState ], 'new ' => ['is_sensitive ' => ! $ oldState ]];
185+ app (AdminAuditLogService::class)->logVideoModerate ($ request ->user (), $ video , $ changes );
186+
187+ return $ this ->data ((new AdminVideoResource ($ video )));
188+ }
189+
129190 if ($ action === 'delete ' ) {
130- $ video = Video::findOrFail ($ id );
131191 $ pid = $ video ->profile_id ;
132192 VideoService::deleteMediaData ($ video ->id );
133193
@@ -154,7 +214,6 @@ public function videoModerate(Request $request, $id)
154214 return $ this ->success ();
155215 }
156216
157- $ video = Video::findOrFail ($ id );
158217 $ video ->status = $ action == 'unpublished ' ? 6 : 2 ;
159218
160219 if ($ action == 'unpublished ' ) {
@@ -165,7 +224,7 @@ public function videoModerate(Request $request, $id)
165224 $ video ->saveQuietly ();
166225 VideoService::getMediaData ($ video ->id , true );
167226
168- $ res = (new VideoResource ($ video ))->toArray ($ request );
227+ $ res = (new AdminVideoResource ($ video ))->toArray ($ request );
169228 $ res ['status ' ] = $ video ->statusLabel ();
170229 $ res ['media ' ]['size ' ] = $ video ->size_kb ;
171230 $ res ['hid ' ] = $ video ->hashid ();
@@ -275,15 +334,40 @@ public function videoReplyDelete(Request $request, $id)
275334 'comment_likes ' => $ comment ->likes ,
276335 ]
277336 );
337+ $ children = 1 ;
338+
339+ $ parent = Comment::withTrashed ()->find ($ comment ->comment_id );
340+ if ($ parent ) {
341+ $ children = CommentReply::where ('comment_id ' , $ comment ->comment_id )->whereNotIn ('id ' , [$ comment ->id ])->count ();
342+ $ parent ->replies = $ children ;
343+ $ parent ->saveQuietly ();
344+ $ parent ->refresh ();
345+ }
278346
279- $ parent = $ comment ->parent ;
280347 $ comment ->forceDelete ();
281- $ parent ->recalculateReplies ();
282- $ video ->decrement ('comments ' );
348+
349+ if ($ parent && $ parent ->deleted_at && $ parent ->replies === 0 ) {
350+ $ parent ->forceDelete ();
351+ }
352+
353+ $ video ->recalculateCommentsCount ();
283354
284355 return $ this ->success ();
285356 }
286357
358+ public function videoAuditLog (Request $ request , $ id )
359+ {
360+ $ video = Video::findOrFail ($ id );
361+
362+ $ auditLogs = AdminAuditLog::whereActivityType ('App\Models\Video ' )
363+ ->whereActivityId ($ video ->id )
364+ ->orderByDesc ('id ' )
365+ ->cursorPaginate (15 )
366+ ->withQueryString ();
367+
368+ return AdminAuditLogResource::collection ($ auditLogs );
369+ }
370+
287371 public function profiles (Request $ request )
288372 {
289373 $ search = $ request ->query ('q ' );
@@ -706,6 +790,54 @@ protected function revokeAllSessions($user): void
706790 }
707791 }
708792
793+ public function profileDeleteAllComments (Request $ request , $ id )
794+ {
795+ $ pid = $ request ->user ()->profile_id ;
796+
797+ $ profile = Profile::findOrFail ($ id );
798+
799+ if ($ profile ->user_id ) {
800+ abort_if ($ profile ->user ->is_admin , 403 , 'You cannot perform this action ' );
801+ }
802+
803+ app (AdminAuditLogService::class)->logProfileDeleteAllComments ($ request ->user (), $ profile );
804+
805+ DB ::transaction (function () use ($ profile ) {
806+ CommentReply::withTrashed ()->where ('profile_id ' , $ profile ->id )
807+ ->chunkById (200 , function (Collection $ comments ) {
808+ foreach ($ comments as $ comment ) {
809+ $ video = $ comment ->video ;
810+ $ parentId = $ comment ->comment_id ;
811+ $ comment ->forceDelete ();
812+ $ parent = Comment::withTrashed ()->find ($ parentId );
813+ if ($ parent ) {
814+ $ parent ->recalculateReplies ();
815+ }
816+ $ video ->recalculateCommentsCount ();
817+ }
818+ }, column: 'id ' );
819+ });
820+
821+ DB ::transaction (function () use ($ profile ) {
822+ Comment::withTrashed ()->where ('profile_id ' , $ profile ->id )
823+ ->chunkById (200 , function (Collection $ comments ) {
824+ foreach ($ comments as $ comment ) {
825+ $ video = $ comment ->video ;
826+ $ replies = $ comment ->replies ;
827+ if ($ replies === 0 ) {
828+ $ comment ->forceDelete ();
829+ } else {
830+ $ comment ->update (['caption ' => null , 'status ' => 'deleted_by_admin ' ]);
831+ $ comment ->delete ();
832+ }
833+ $ video ->recalculateCommentsCount ();
834+ }
835+ }, column: 'id ' );
836+ });
837+
838+ return $ this ->success ();
839+ }
840+
709841 public function reportCount (Request $ request )
710842 {
711843 $ res = app (AdminDashboardService::class)->getReportsCount ();
@@ -974,6 +1106,19 @@ public function comments(Request $request)
9741106 return CommentResource::collection ($ comments );
9751107 }
9761108
1109+ public function getCommentReplies (Request $ request , $ id )
1110+ {
1111+ $ validated = $ request ->validate ([
1112+ 'limit ' => 'sometimes|integer|min:1|max:50 ' ,
1113+ ]);
1114+
1115+ $ limit = $ validated ['limit ' ];
1116+
1117+ $ comments = CommentReply::with ('mediaAttachments ' )->whereCommentId ($ id )->cursorPaginate ($ limit )->withQueryString ();
1118+
1119+ return CommentReplyResource::collection ($ comments );
1120+ }
1121+
9771122 public function getComment (Request $ request , $ id )
9781123 {
9791124 $ query = Comment::with ('mediaAttachments ' )->findOrFail ($ id );
0 commit comments