first commit

This commit is contained in:
meninjar
2026-04-14 01:21:54 +00:00
commit 35c101725f
443 changed files with 1245931 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
package role
// RolPagesRequest represents the request payload for RolPages
type RolPagesRequest struct {
Name string `json:"name"`
Icon string `json:"icon"`
URL string `json:"url"`
Level int16 `json:"level" validate:"required"`
Sort int16 `json:"sort"`
Parent *int64 `json:"parent"`
Active bool `json:"active"`
}
type RolPagesResponse struct {
Id int64 `json:"id"`
Name string `json:"name"`
Icon string `json:"icon"`
URL string `json:"url"`
Level int16 `json:"level"`
Sort int16 `json:"sort"`
Parent *int64 `json:"parent"`
Active bool `json:"active"`
}
// RoleAccessResponse represents the response structure for role access with hierarchical menu
type RoleAccessResponse struct {
Roles []string `json:"roles"`
Access []MenuItem `json:"access"`
}
// MenuItem represents a menu item in the access hierarchy
type MenuItem struct {
ID string `json:"id"`
Name string `json:"name"`
Icon string `json:"icon"`
URL string `json:"url"`
Level string `json:"level"`
Children []MenuChild `json:"children"`
}
// MenuChild represents a child menu item
type MenuChild struct {
Name string `json:"name"`
Icon string `json:"icon"`
URL string `json:"url"`
Level string `json:"level"`
}
+18
View File
@@ -0,0 +1,18 @@
package role
// RolPages entity represents the rol_pages table in the database
type RolPages struct {
Id int64 `json:"id" db:"id" gorm:"primaryKey;autoIncrement"`
Name string `json:"name" db:"name"`
Icon string `json:"icon" db:"icon"`
URL string `json:"url" db:"url"`
Level int16 `json:"level" db:"level"`
Sort int16 `json:"sort" db:"sort"`
Parent *int64 `json:"parent" db:"parent"`
Active bool `json:"active" db:"active"`
}
// TableName specifies the table name for RolPages
func (RolPages) TableName() string {
return "role_access.rol_pages"
}
+95
View File
@@ -0,0 +1,95 @@
package role
import (
"fmt"
"time"
rolepPermission "service/internal/master/role/permission"
)
func mapRequestToEntity(req RolPagesRequest) *RolPages {
return &RolPages{
Name: req.Name,
Icon: req.Icon,
URL: req.URL,
Level: req.Level,
Sort: req.Sort,
Parent: req.Parent,
Active: req.Active,
}
}
func mapEntityToResponse(e *RolPages) *RolPagesResponse {
return &RolPagesResponse{
Id: e.Id,
Name: e.Name,
Icon: e.Icon,
URL: e.URL,
Level: e.Level,
Sort: e.Sort,
Parent: e.Parent,
Active: e.Active,
}
}
// MapPermissionToRoleAccessResponse converts RolPermission to RoleAccessResponse structure
func MapPermissionToRoleAccessResponse(roles []string, permissions []*rolepPermission.RolPermission, pages []*RolPages) *RoleAccessResponse {
response := &RoleAccessResponse{
Roles: roles,
Access: []MenuItem{},
}
// Map permissions to create menu items based on pages
// Filter pages yang memiliki permission read = true
accessiblePages := []*RolPages{}
for i, permission := range permissions {
if permission.Read && i < len(pages) {
accessiblePages = append(accessiblePages, pages[i])
}
}
// Group pages by parent ID
parentMap := make(map[int64][]*RolPages)
var rootPages []*RolPages
for _, page := range accessiblePages {
if page.Parent == nil {
rootPages = append(rootPages, page)
} else {
parentMap[*page.Parent] = append(parentMap[*page.Parent], page)
}
}
// Build menu hierarchy
for _, rootPage := range rootPages {
menuItem := MenuItem{
ID: generateUUID(),
Name: rootPage.Name,
Icon: rootPage.Icon,
URL: rootPage.URL,
Level: fmt.Sprintf("%d", rootPage.Level),
}
// Add children if any
if children, exists := parentMap[rootPage.Id]; exists {
for _, child := range children {
menuChild := MenuChild{
Name: child.Name,
Icon: child.Icon,
URL: child.URL,
Level: fmt.Sprintf("%d", child.Level),
}
menuItem.Children = append(menuItem.Children, menuChild)
}
}
response.Access = append(response.Access, menuItem)
}
return response
}
// Helper function to generate UUID (you may want to use a proper UUID library)
func generateUUID() string {
return fmt.Sprintf("%d", time.Now().UnixNano())
}
+172
View File
@@ -0,0 +1,172 @@
package role
import (
"context"
"fmt"
"service/pkg/logger"
"service/pkg/utils/query"
rolepPermission "service/internal/master/role/permission"
"github.com/jmoiron/sqlx"
"gorm.io/gorm"
)
// RoleAccessRepository defines the contract for role access data operations
type RoleAccessRepository interface {
// GetRoleAccess retrieves role access information for a specific user
GetRoleAccess(ctx context.Context, userID string) (*RoleAccessData, error)
// GetRolePermissions retrieves permissions for a specific role
GetRolePermissions(ctx context.Context, roleID int64) ([]*rolepPermission.RolPermission, error)
// GetRolePages retrieves pages accessible by role
GetRolePages(ctx context.Context, roleIDs []int64) ([]*RolPages, error)
// GetUserRoles retrieves roles for a specific user
GetUserRoles(ctx context.Context, userID string) ([]string, error)
}
// RoleAccessData represents the complete role access information
type RoleAccessData struct {
Roles []string
Permissions []*rolepPermission.RolPermission
Pages []*RolPages
}
type roleAccessRepository struct {
db *gorm.DB
qb query.QueryBuilder
dbType query.DBType
}
// NewRoleAccessRepository creates a new instance of RoleAccessRepository
func NewRoleAccessRepository(db *gorm.DB) RoleAccessRepository {
dbType := query.DBTypePostgreSQL
qb := query.NewSQLQueryBuilder(dbType).
SetSecurityOptions(true, 1000).
SetQueryLogging(true).
SetQueryTimeout(30)
return &roleAccessRepository{
db: db,
qb: qb,
dbType: dbType,
}
}
// getSQLXDB extracts *sqlx.DB from *gorm.DB
func (r *roleAccessRepository) getSQLXDB() (*sqlx.DB, error) {
sqlDB, err := r.db.DB()
if err != nil {
return nil, fmt.Errorf("failed to get underlying *sql.DB: %w", err)
}
return sqlx.NewDb(sqlDB, "pgx"), nil
}
// GetRoleAccess retrieves complete role access information for a user
func (r *roleAccessRepository) GetRoleAccess(ctx context.Context, userID string) (*RoleAccessData, error) {
// Get user roles
roles, err := r.GetUserRoles(ctx, userID)
if err != nil {
return nil, fmt.Errorf("failed to get user roles: %w", err)
}
if len(roles) == 0 {
return &RoleAccessData{
Roles: []string{},
Permissions: []*rolepPermission.RolPermission{},
Pages: []*RolPages{},
}, nil
}
// For now, we'll use mock role IDs - in real implementation, this should come from database
// Mock role IDs based on role names
var roleIDs []int64
for range roles {
roleIDs = append(roleIDs, 1) // Mock role ID
}
// Get permissions and pages for the roles
permissions, err := r.GetRolePermissions(ctx, 1) // Mock role ID
if err != nil {
return nil, fmt.Errorf("failed to get role permissions: %w", err)
}
pages, err := r.GetRolePages(ctx, roleIDs)
if err != nil {
return nil, fmt.Errorf("failed to get role pages: %w", err)
}
return &RoleAccessData{
Roles: roles,
Permissions: permissions,
Pages: pages,
}, nil
}
// GetRolePermissions retrieves permissions for a specific role
func (r *roleAccessRepository) GetRolePermissions(ctx context.Context, roleID int64) ([]*rolepPermission.RolPermission, error) {
sqlxDB, err := r.getSQLXDB()
if err != nil {
return nil, err
}
// For now, return all permissions - in real implementation, this should filter by role
q := query.DynamicQuery{
From: "rol_permission",
Filters: []query.FilterGroup{{
Filters: []query.DynamicFilter{
query.CreateFilter("DeletedAt", query.OpNull, nil),
},
}},
Limit: 100,
}
var results []*rolepPermission.RolPermission
if err := r.qb.ExecuteQuery(ctx, sqlxDB, q, &results); err != nil {
return nil, fmt.Errorf("failed to execute role permissions query: %w", err)
}
return results, nil
}
// GetRolePages retrieves pages accessible by role
func (r *roleAccessRepository) GetRolePages(ctx context.Context, roleIDs []int64) ([]*RolPages, error) {
sqlxDB, err := r.getSQLXDB()
if err != nil {
return nil, err
}
// Get all active pages - in real implementation, this should join with role-page permissions
q := query.DynamicQuery{
From: "role_access.rol_pages",
Filters: []query.FilterGroup{{
Filters: []query.DynamicFilter{
query.CreateEqualFilter("Active", true),
},
}},
Sort: []query.SortField{
query.CreateAscSort("Level"),
query.CreateAscSort("Sort"),
},
Limit: 100,
}
var results []*RolPages
if err := r.qb.ExecuteQuery(ctx, sqlxDB, q, &results); err != nil {
return nil, fmt.Errorf("failed to execute role pages query: %w", err)
}
return results, nil
}
// GetUserRoles retrieves roles for a specific user
func (r *roleAccessRepository) GetUserRoles(ctx context.Context, userID string) ([]string, error) {
// Mock implementation - in real implementation, this should query user-role mapping table
// For now, return mock roles based on user ID
logger.Default().Info("Getting user roles", logger.String("userID", userID))
// Mock roles - in real implementation, get from database
mockRoles := []string{"admin1", "admin2"}
return mockRoles, nil
}
+54
View File
@@ -0,0 +1,54 @@
package role
import (
"context"
"service/pkg/errors"
)
// RoleAccessService defines the contract for role access operations
type RoleAccessService interface {
GetRoleAccess(ctx context.Context, userID string) (*RoleAccessResponse, error)
}
// roleAccessService implements RoleAccessService
type roleAccessService struct {
repo RoleAccessRepository
}
// NewRoleAccessService creates a new instance of RoleAccessService
func NewRoleAccessService(repo RoleAccessRepository) RoleAccessService {
return &roleAccessService{
repo: repo,
}
}
// GetRoleAccess retrieves role access information for a user
func (s *roleAccessService) GetRoleAccess(ctx context.Context, userID string) (*RoleAccessResponse, error) {
if userID == "" {
return nil, errors.NewValidationError().Message("User ID is required").Metadata("userID", userID).Build()
}
// Get role access data from repository
roleAccessData, err := s.repo.GetRoleAccess(ctx, userID)
if err != nil {
return nil, errors.InternalError().Message("Failed to retrieve role access data").Cause(err).Build()
}
// Map the data to response format
response := MapPermissionToRoleAccessResponse(
roleAccessData.Roles,
roleAccessData.Permissions,
roleAccessData.Pages,
)
return response, nil
}
// GetUserRoles retrieves roles for a specific user
func (s *roleAccessService) GetUserRoles(ctx context.Context, userID string) ([]string, error) {
if userID == "" {
return nil, errors.NewValidationError().Message("User ID is required").Metadata("userID", userID).Build()
}
return s.repo.GetUserRoles(ctx, userID)
}