diff --git a/internal/domain/access/handler.go b/internal/domain/access/handler.go index d056901..28840b7 100644 --- a/internal/domain/access/handler.go +++ b/internal/domain/access/handler.go @@ -67,3 +67,26 @@ func (h AccessHandler) SyncKeycloakRole(c *gin.Context) { Data: req, }) } + +func (h AccessHandler) GetPageByKeycloakId(c *gin.Context) { + keycloakId := c.Query("keycloak_id") + + pageResult, err := h.repo.GetAvailablePageByKeycloakId(c, keycloakId) + if err != nil { + errMessage := []string{err.Error()} + c.JSON(500, shared.BaseErrorResponse{ + Success: false, + Code: 500, + Message: "error fetch page by keycloak id", + Errors: errMessage, + }) + return + } + + c.JSON(200, shared.BaseResponse[[]AvailableMenuResponse]{ + Success: true, + Code: 200, + Message: "success fetch eligible page", + Data: MapMenuModelToResponse(pageResult), + }) +} diff --git a/internal/domain/access/model.go b/internal/domain/access/model.go index 234e01b..a299ae5 100644 --- a/internal/domain/access/model.go +++ b/internal/domain/access/model.go @@ -1,5 +1,7 @@ package access +import "database/sql" + type RolePermissionModel struct { ID string `db:"id"` Name string `db:"name"` @@ -7,8 +9,13 @@ type RolePermissionModel struct { } type RolePageModel struct { - ID string `db:"id"` - PagePath string `db:"page_path"` + ID string `db:"id"` + Name string `db:"name"` + Icon sql.NullString `db:"icon"` + Url sql.NullString `db:"url"` + Level int `db:"level"` + Sort int `db:"sort"` + ParentId sql.NullString `db:"parent"` } type RoleUserModel struct { @@ -17,3 +24,15 @@ type RoleUserModel struct { Email string `db:"email"` KeycloakId string `db:"keycloak_id"` } + +type RoleUserPermissionModel struct { + ID string `db:"id"` + IdUser string `db:"id_user"` + IdPermission string `db:"id_permission"` +} + +type RolePagePermissionModel struct { + ID string `db:"id"` + IdPermission string `db:"id_permission"` + IdPage string `db:"id_page"` +} diff --git a/internal/domain/access/repository.go b/internal/domain/access/repository.go index f9456d9..6df13c9 100644 --- a/internal/domain/access/repository.go +++ b/internal/domain/access/repository.go @@ -16,11 +16,14 @@ const DB_NAME = "db_role_access" const TBL_USER = "role_users" const TBL_PERMISSION = "role_permission" const TBL_USER_PERMISSION = "role_user_permission" +const TBL_ROLE_PAGES = "role_pages" +const TBL_PAGE_PERMISSION = "role_page_permission" type IAccessRepository interface { FindUserByKeycloakId(c context.Context, id string) ([]RoleUserModel, error) CreateUserPermission(c context.Context, req SyncKeycloakRoleRequest) error UpdateUserPermission(c context.Context, userId string, req SyncKeycloakRoleRequest) error + GetAvailablePageByKeycloakId(c context.Context, keycloakId string) ([]RolePageModel, error) } type accessRepo struct { @@ -134,6 +137,51 @@ func (r accessRepo) UpdateUserPermission(c context.Context, userId string, req S return nil } +func (r accessRepo) GetAvailablePageByKeycloakId(c context.Context, keycloakId string) ([]RolePageModel, error) { + var result []RolePageModel + + dbconn, err := r.db.GetSQLXDB(DB_NAME) + if err != nil { + log.Printf("Unable to connect db : %s", err) + return result, err + } + + fetchUsers, err := r.FindUserByKeycloakId(c, keycloakId) + if err != nil { + return nil, err + } + if len(fetchUsers) == 0 { + log.Printf("user not found, keycloak id : %s", keycloakId) + return nil, err + } + user := &fetchUsers[0] + + var permissionIds []string + fetchUserPermission, err := r.getUserPermissionByUserId(c, dbconn, user.ID) + if err != nil { + return nil, err + } + for _, p := range fetchUserPermission { + permissionIds = append(permissionIds, p.IdPermission) + } + + var pageIds []string + fetchPagePermission, err := r.getPageIdsByPermissionIds(c, dbconn, permissionIds) + if err != nil { + return nil, err + } + for _, pg := range fetchPagePermission { + pageIds = append(pageIds, pg.IdPage) + } + + result, err = r.getPageByIds(c, dbconn, pageIds) + if err != nil { + return nil, err + } + + return result, nil +} + // PRIVATE FUNCTIONS // Table user function @@ -348,4 +396,100 @@ func (r accessRepo) getOrCreateUserPermission(c context.Context, db *sqlx.DB, tx return nil } +func (r accessRepo) getUserPermissionByUserId(c context.Context, db *sqlx.DB, userId string) ([]RoleUserPermissionModel, error) { + var result []RoleUserPermissionModel + + query := queryUtils.DynamicQuery{ + From: TBL_USER_PERMISSION, + Fields: []queryUtils.SelectField{ + {Expression: "id"}, + {Expression: "id_user"}, + {Expression: "id_permission"}, + }, + Filters: []queryUtils.FilterGroup{ + { + Filters: []queryUtils.DynamicFilter{ + {Column: "id_user", Operator: queryUtils.OpEqual, Value: userId}, + }, 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 + +func (r accessRepo) getPageIdsByPermissionIds(c context.Context, db *sqlx.DB, permissionIds []string) ([]RolePagePermissionModel, error) { + var result []RolePagePermissionModel + + query := queryUtils.DynamicQuery{ + From: TBL_PAGE_PERMISSION, + Fields: []queryUtils.SelectField{ + {Expression: "id"}, + {Expression: "id_permission"}, + {Expression: "id_page"}, + }, + Filters: []queryUtils.FilterGroup{ + { + Filters: []queryUtils.DynamicFilter{ + {Column: "id_permission", Operator: queryUtils.OpIn, Value: permissionIds}, + }, 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 role page permission functions + +// Table pages functions + +func (r accessRepo) getPageByIds(c context.Context, db *sqlx.DB, ids []string) ([]RolePageModel, error) { + var result []RolePageModel + + query := queryUtils.DynamicQuery{ + From: TBL_ROLE_PAGES, + Fields: []queryUtils.SelectField{ + {Expression: "id"}, + {Expression: "name"}, + {Expression: "icon"}, + {Expression: "url"}, + {Expression: "level"}, + {Expression: "sort"}, + {Expression: "parent"}, + }, + Filters: []queryUtils.FilterGroup{ + { + Filters: []queryUtils.DynamicFilter{ + {Column: "id", Operator: queryUtils.OpIn, Value: ids}, + }, LogicOp: "AND", + }, + }, + } + + err := r.queryBuilder.ExecuteQuery(c, db, query, &result) + if err != nil { + log.Printf("error executing fetch pages : %v", err) + return nil, err + } + + return result, nil +} + +// End page functions diff --git a/internal/domain/access/response.go b/internal/domain/access/response.go new file mode 100644 index 0000000..b259d7a --- /dev/null +++ b/internal/domain/access/response.go @@ -0,0 +1,44 @@ +package access + +type AvailableMenuChildResponse struct { + Title string `json:"title"` + Icon string `json:"icon"` + To string `json:"to"` + Children []*AvailableMenuChildResponse `json:"children"` +} + +type AvailableMenuResponse struct { + ID string `json:"id"` + Header string `json:"header"` + Children []*AvailableMenuChildResponse `json:"children"` +} + +func MapMenuModelToResponse(pages []RolePageModel) []AvailableMenuResponse { + pageMap := make(map[string]*AvailableMenuChildResponse) + + var result []AvailableMenuResponse + + for _, p := range pages { + pageMap[p.ID] = &AvailableMenuChildResponse{ + Title: p.Name, + Icon: p.Icon.String, + To: p.Url.String, + } + + if p.ParentId.String != "" { + pageMap[p.ParentId.String].Children = append(pageMap[p.ParentId.String].Children, pageMap[p.ID]) + } + } + + for _, p := range pages { + if p.ParentId.String == "" { + result = append(result, AvailableMenuResponse{ + ID: p.ID, + Header: p.Name, + Children: pageMap[p.ID].Children, + }) + } + } + + return result +} diff --git a/internal/domain/access/routes.go b/internal/domain/access/routes.go index db41028..349cbab 100644 --- a/internal/domain/access/routes.go +++ b/internal/domain/access/routes.go @@ -11,4 +11,5 @@ func RegisterRoutes(r *gin.RouterGroup, dbService database.Service) { accessHandler := NewAccessHandler(accessRepo) r.POST("/sync-keycloak-role", accessHandler.SyncKeycloakRole) + r.GET("/eligible-menu", accessHandler.GetPageByKeycloakId) }