diff --git a/docs/docs.go b/docs/docs.go index 867a527..2cb3849 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -46,6 +46,53 @@ const docTemplate = `{ } } }, + "/access/list-user": { + "get": { + "tags": [ + "Access Role" + ], + "summary": "Get List User And Role", + "parameters": [ + { + "type": "string", + "description": "Search Keyword", + "name": "search", + "in": "query" + }, + { + "type": "string", + "default": "10", + "description": "Limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "default": "0", + "description": "Offset", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/access.UserRoleResponse" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/shared.BaseErrorResponse" + } + } + } + } + }, "/access/sync-keycloak-role": { "post": { "tags": [ @@ -879,6 +926,26 @@ const docTemplate = `{ } } }, + "access.UserRoleResponse": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "hak_akses": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "antrianoperasi.CreatePasienOperasiRequest": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 2af5663..c607a65 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -40,6 +40,53 @@ } } }, + "/access/list-user": { + "get": { + "tags": [ + "Access Role" + ], + "summary": "Get List User And Role", + "parameters": [ + { + "type": "string", + "description": "Search Keyword", + "name": "search", + "in": "query" + }, + { + "type": "string", + "default": "10", + "description": "Limit", + "name": "limit", + "in": "query" + }, + { + "type": "string", + "default": "0", + "description": "Offset", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/access.UserRoleResponse" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/shared.BaseErrorResponse" + } + } + } + } + }, "/access/sync-keycloak-role": { "post": { "tags": [ @@ -873,6 +920,26 @@ } } }, + "access.UserRoleResponse": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "hak_akses": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "antrianoperasi.CreatePasienOperasiRequest": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 3b62616..5851928 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -17,6 +17,19 @@ definitions: - keycloak_id - name type: object + access.UserRoleResponse: + properties: + email: + type: string + hak_akses: + items: + type: string + type: array + id: + type: string + name: + type: string + type: object antrianoperasi.CreatePasienOperasiRequest: properties: diagnosisItems: @@ -469,6 +482,37 @@ paths: summary: Get Pages By Keycloak Id tags: - Access Role + /access/list-user: + get: + parameters: + - description: Search Keyword + in: query + name: search + type: string + - default: "10" + description: Limit + in: query + name: limit + type: string + - default: "0" + description: Offset + in: query + name: offset + type: string + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/access.UserRoleResponse' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/shared.BaseErrorResponse' + summary: Get List User And Role + tags: + - Access Role /access/sync-keycloak-role: post: parameters: diff --git a/internal/domain/access/handler.go b/internal/domain/access/handler.go index 320f21f..810ccf0 100644 --- a/internal/domain/access/handler.go +++ b/internal/domain/access/handler.go @@ -104,3 +104,47 @@ func (h AccessHandler) GetPageByKeycloakId(c *gin.Context) { Data: MapMenuModelToResponse(pageResult), }) } + +// ListUserRole godoc +// @Summary Get List User And Role +// @Tags Access Role +// @Param search query string false "Search Keyword" +// @Param limit query string false "Limit" default(10) +// @Param offset query string false "Offset" default(0) +// @Success 200 {object} []UserRoleResponse +// @Failure 500 {object} shared.BaseErrorResponse +// @Router /access/list-user [get] +func (h AccessHandler) ListUserRole(c *gin.Context) { + var query QueryListUserRole + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + + res, err := h.repo.ListUserRole(c.Request.Context(), query) + if err != nil { + c.JSON(500, shared.BaseErrorResponse{ + Success: false, + Code: 500, + Message: err.Error(), + }) + return + } + + c.JSON(200, + shared.ToBaseResponsePaginate( + res.Data, res.Paging, true, 200, "success get list user role", + )) +} + +func (h AccessHandler) ListRolePageSettings(c *gin.Context) { + +} + +func (h AccessHandler) DetailRolePageSettings(c *gin.Context) { + +} + +func (h AccessHandler) UpdateRolePageSettings(c *gin.Context) { + +} diff --git a/internal/domain/access/model.go b/internal/domain/access/model.go index a299ae5..6e0b141 100644 --- a/internal/domain/access/model.go +++ b/internal/domain/access/model.go @@ -26,9 +26,10 @@ type RoleUserModel struct { } type RoleUserPermissionModel struct { - ID string `db:"id"` - IdUser string `db:"id_user"` - IdPermission string `db:"id_permission"` + ID string `db:"id"` + IdUser string `db:"id_user"` + IdPermission string `db:"id_permission"` + PermissionName *string `db:"permission_name"` } type RolePagePermissionModel struct { diff --git a/internal/domain/access/repository.go b/internal/domain/access/repository.go index 6df13c9..dc01dbc 100644 --- a/internal/domain/access/repository.go +++ b/internal/domain/access/repository.go @@ -24,6 +24,7 @@ type IAccessRepository interface { CreateUserPermission(c context.Context, req SyncKeycloakRoleRequest) error UpdateUserPermission(c context.Context, userId string, req SyncKeycloakRoleRequest) error GetAvailablePageByKeycloakId(c context.Context, keycloakId string) ([]RolePageModel, error) + ListUserRole(c context.Context, q QueryListUserRole) (ListUserRolePaginateResponse, error) } type accessRepo struct { @@ -182,6 +183,81 @@ func (r accessRepo) GetAvailablePageByKeycloakId(c context.Context, keycloakId s return result, nil } +func (r accessRepo) ListUserRole(c context.Context, q QueryListUserRole) (ListUserRolePaginateResponse, error) { + var result ListUserRolePaginateResponse + + query := queryUtils.DynamicQuery{ + From: TBL_USER, + Fields: []queryUtils.SelectField{ + {Expression: "id"}, + {Expression: "name"}, + {Expression: "email"}, + }, + Sort: []queryUtils.SortField{ + {Column: "created_at", Order: "DESC"}, + }, + } + + if q.Search != "" { + searchFilters := []queryUtils.DynamicFilter{ + {Column: "name", Operator: queryUtils.OpILike, Value: "%" + q.Search + "%"}, + {Column: "email", Operator: queryUtils.OpILike, Value: "%" + q.Search + "%"}, + } + + query.Filters = append(query.Filters, queryUtils.FilterGroup{Filters: searchFilters, LogicOp: "OR"}) + } + + dbconn, err := r.db.GetSQLXDB(DB_NAME) + if err != nil { + log.Printf("Unable to connect db : %s", err) + return result, err + } + + // query count + countData, err := r.queryBuilder.ExecuteCount(c, dbconn, query) + if err != nil { + log.Printf("Unable to execute query count : %s ", err) + return result, err + } + result.Paging.Limit = q.Limit + result.Paging.Offset = q.Offset + result.Paging.Total = int(countData) + result.Paging.CalculatePagingInfo() + + // query data + queryData := query + queryData.Limit = q.Limit + queryData.Offset = q.Offset + err = r.queryBuilder.ExecuteQuery( + c, dbconn, queryData, &result.Data) + if err != nil { + log.Printf("Unable to execute query data : %s", err) + return result, err + } + + userIds := make([]string, 0, len(result.Data)) + for _, item := range result.Data { + userIds = append(userIds, item.ID) + } + + // fetch role + userPermission, err := r.getPermissionNameByUserIds(c, dbconn, userIds) + if err != nil { + return result, err + } + groupPermissionByUser := make(map[string][]string) + for _, p := range userPermission { + groupPermissionByUser[p.IdUser] = append(groupPermissionByUser[p.IdUser], *p.PermissionName) + } + + // join result with role + for idx := range result.Data { + result.Data[idx].HakAkses = groupPermissionByUser[result.Data[idx].ID] + } + + return result, nil +} + // PRIVATE FUNCTIONS // Table user function @@ -424,6 +500,50 @@ func (r accessRepo) getUserPermissionByUserId(c context.Context, db *sqlx.DB, us return result, nil } +func (r accessRepo) getPermissionNameByUserIds(c context.Context, db *sqlx.DB, userIds []string) ([]RoleUserPermissionModel, error) { + var result []RoleUserPermissionModel + + query := queryUtils.DynamicQuery{ + From: TBL_USER_PERMISSION, + Aliases: "up", + Fields: []queryUtils.SelectField{ + {Expression: "up.id", Alias: "id"}, + {Expression: "up.id_user", Alias: "id_user"}, + {Expression: "up.id_permission", Alias: "id_permission"}, + {Expression: "p.name", Alias: "permission_name"}, + }, + Joins: []queryUtils.Join{ + { + Type: "LEFT", + Table: TBL_PERMISSION, + Alias: "p", + OnConditions: queryUtils.FilterGroup{ + Filters: []queryUtils.DynamicFilter{ + { + Column: "p.id", Operator: queryUtils.OpEqual, Value: "up.id_permission", + }, + }, + }, + }, + }, + Filters: []queryUtils.FilterGroup{ + { + Filters: []queryUtils.DynamicFilter{ + {Column: "id_user", Operator: queryUtils.OpIn, Value: userIds}, + }, LogicOp: "AND", + }, + }, + } + + err := r.queryBuilder.ExecuteQuery(c, db, query, &result) + if err != nil { + log.Printf("error executing fetch user permission : %v", err) + return nil, err + } + + return result, nil +} + // End Table user permission functions // Table role page permission functions diff --git a/internal/domain/access/request.go b/internal/domain/access/request.go index b1c3539..9c51b90 100644 --- a/internal/domain/access/request.go +++ b/internal/domain/access/request.go @@ -12,3 +12,9 @@ type UpsertAccessPermissionRequest struct { Status string `json:"status"` Pages []string `json:"pages"` } + +type QueryListUserRole struct { + Search string `form:"search"` + Limit int `form:"limit,default=10"` + Offset int `form:"offset,default=0"` +} diff --git a/internal/domain/access/response.go b/internal/domain/access/response.go index b259d7a..bc008d9 100644 --- a/internal/domain/access/response.go +++ b/internal/domain/access/response.go @@ -1,5 +1,7 @@ package access +import "antrian-operasi/internal/shared" + type AvailableMenuChildResponse struct { Title string `json:"title"` Icon string `json:"icon"` @@ -42,3 +44,15 @@ func MapMenuModelToResponse(pages []RolePageModel) []AvailableMenuResponse { return result } + +type UserRoleResponse struct { + ID string `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + HakAkses []string `json:"hak_akses"` +} + +type ListUserRolePaginateResponse struct { + Data []UserRoleResponse + Paging shared.PaginationInfo +} diff --git a/internal/domain/access/routes.go b/internal/domain/access/routes.go index 349cbab..937fe66 100644 --- a/internal/domain/access/routes.go +++ b/internal/domain/access/routes.go @@ -12,4 +12,5 @@ func RegisterRoutes(r *gin.RouterGroup, dbService database.Service) { r.POST("/sync-keycloak-role", accessHandler.SyncKeycloakRole) r.GET("/eligible-menu", accessHandler.GetPageByKeycloakId) + r.GET("/list-user", accessHandler.ListUserRole) }