@@ -75,6 +75,7 @@ type UpdateBalanceRequest struct {
7575// - role: filter by user role
7676// - search: search in email, username
7777// - attr[{id}]: filter by custom attribute value, e.g. attr[1]=company
78+ // - group_name: fuzzy filter by allowed group name
7879func (h * UserHandler ) List (c * gin.Context ) {
7980 page , pageSize := response .ParsePagination (c )
8081
@@ -89,6 +90,7 @@ func (h *UserHandler) List(c *gin.Context) {
8990 Status : c .Query ("status" ),
9091 Role : c .Query ("role" ),
9192 Search : search ,
93+ GroupName : strings .TrimSpace (c .Query ("group_name" )),
9294 Attributes : parseAttributeFilters (c ),
9395 }
9496 if raw , ok := c .GetQuery ("include_subscriptions" ); ok {
@@ -366,3 +368,35 @@ func (h *UserHandler) GetBalanceHistory(c *gin.Context) {
366368 "total_recharged" : totalRecharged ,
367369 })
368370}
371+
372+ // ReplaceGroupRequest represents the request to replace a user's exclusive group
373+ type ReplaceGroupRequest struct {
374+ OldGroupID int64 `json:"old_group_id" binding:"required,gt=0"`
375+ NewGroupID int64 `json:"new_group_id" binding:"required,gt=0"`
376+ }
377+
378+ // ReplaceGroup handles replacing a user's exclusive group
379+ // POST /api/v1/admin/users/:id/replace-group
380+ func (h * UserHandler ) ReplaceGroup (c * gin.Context ) {
381+ userID , err := strconv .ParseInt (c .Param ("id" ), 10 , 64 )
382+ if err != nil {
383+ response .BadRequest (c , "Invalid user ID" )
384+ return
385+ }
386+
387+ var req ReplaceGroupRequest
388+ if err := c .ShouldBindJSON (& req ); err != nil {
389+ response .BadRequest (c , "Invalid request: " + err .Error ())
390+ return
391+ }
392+
393+ result , err := h .adminService .ReplaceUserGroup (c .Request .Context (), userID , req .OldGroupID , req .NewGroupID )
394+ if err != nil {
395+ response .ErrorFrom (c , err )
396+ return
397+ }
398+
399+ response .Success (c , gin.H {
400+ "migrated_keys" : result .MigratedKeys ,
401+ })
402+ }
0 commit comments