ilk
This commit is contained in:
440
svc/routes/role_department_permissions.go
Normal file
440
svc/routes/role_department_permissions.go
Normal file
@@ -0,0 +1,440 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"bssapp-backend/auth"
|
||||
"bssapp-backend/internal/auditlog"
|
||||
"bssapp-backend/permissions"
|
||||
"bssapp-backend/queries"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type IdTitleOption struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
type Row struct {
|
||||
Route string `json:"route"`
|
||||
CanAccess bool `json:"can_access"`
|
||||
}
|
||||
|
||||
type RoleDepartmentPermissionHandler struct {
|
||||
DB *sql.DB
|
||||
Repo *permissions.RoleDepartmentPermissionRepo
|
||||
}
|
||||
|
||||
func NewRoleDepartmentPermissionHandler(db *sql.DB) *RoleDepartmentPermissionHandler {
|
||||
|
||||
return &RoleDepartmentPermissionHandler{
|
||||
DB: db, // ✅ EKLENDİ
|
||||
Repo: permissions.NewRoleDepartmentPermissionRepo(db),
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================
|
||||
GET
|
||||
====================================================== */
|
||||
|
||||
func (h *RoleDepartmentPermissionHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
claims, ok := auth.GetClaimsFromContext(r.Context())
|
||||
if !ok || claims == nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
roleID, err := strconv.Atoi(vars["roleId"])
|
||||
if err != nil || roleID <= 0 {
|
||||
http.Error(w, "invalid roleId", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
deptCode := vars["deptCode"]
|
||||
if deptCode == "" {
|
||||
http.Error(w, "invalid deptCode", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
list, err := h.Repo.Get(roleID, deptCode)
|
||||
if err != nil {
|
||||
http.Error(w, "db error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
|
||||
/* ======================================================
|
||||
POST
|
||||
====================================================== */
|
||||
|
||||
func (h *RoleDepartmentPermissionHandler) Save(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
claims, ok := auth.GetClaimsFromContext(r.Context())
|
||||
if !ok || claims == nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
roleID, err := strconv.Atoi(vars["roleId"])
|
||||
if err != nil || roleID <= 0 {
|
||||
http.Error(w, "invalid roleId", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
deptCode := vars["deptCode"]
|
||||
if deptCode == "" {
|
||||
http.Error(w, "invalid deptCode", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var list []permissions.RoleDepartmentPermission
|
||||
if err := json.NewDecoder(r.Body).Decode(&list); err != nil {
|
||||
http.Error(w, "bad payload", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// ================= OLD =================
|
||||
oldRows, err := h.Repo.Get(roleID, deptCode)
|
||||
if err != nil {
|
||||
log.Println("OLD PERM LOAD ERROR:", err)
|
||||
}
|
||||
|
||||
oldMap := map[string]bool{}
|
||||
for _, p := range oldRows {
|
||||
key := p.Module + ":" + p.Action
|
||||
oldMap[key] = p.Allowed
|
||||
}
|
||||
|
||||
// ================= DIFF =================
|
||||
var changes []map[string]any
|
||||
for _, p := range list {
|
||||
key := p.Module + ":" + p.Action
|
||||
oldVal := oldMap[key]
|
||||
if oldVal != p.Allowed {
|
||||
changes = append(changes, map[string]any{
|
||||
"module": p.Module,
|
||||
"action": p.Action,
|
||||
"before": oldVal,
|
||||
"after": p.Allowed,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ================= SAVE =================
|
||||
if err := h.Repo.Save(roleID, deptCode, list); err != nil {
|
||||
http.Error(w, "save error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// ================= AUDIT =================
|
||||
if len(changes) > 0 {
|
||||
auditlog.Enqueue(r.Context(), auditlog.ActivityLog{
|
||||
ActionType: "role_department_permission_change",
|
||||
ActionCategory: "role_permission",
|
||||
ActionTarget: fmt.Sprintf(
|
||||
"/api/roles/%d/departments/%s/permissions",
|
||||
roleID,
|
||||
deptCode,
|
||||
),
|
||||
Description: "role+department permissions updated",
|
||||
Username: claims.Username,
|
||||
RoleCode: claims.RoleCode,
|
||||
DfUsrID: int64(claims.ID),
|
||||
ChangeBefore: map[string]any{
|
||||
"permissions": oldRows,
|
||||
},
|
||||
ChangeAfter: map[string]any{
|
||||
"changes": changes,
|
||||
},
|
||||
IsSuccess: true,
|
||||
})
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(map[string]bool{"success": true})
|
||||
}
|
||||
func GetModuleLookupRoute(db *sql.DB) http.HandlerFunc {
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
rows, err := db.Query(queries.GetModuleLookup)
|
||||
if err != nil {
|
||||
http.Error(w, "db error", 500)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
type Row struct {
|
||||
Value string `json:"value"`
|
||||
Label string `json:"label"`
|
||||
}
|
||||
|
||||
var list []Row
|
||||
|
||||
for rows.Next() {
|
||||
|
||||
var r Row
|
||||
|
||||
if err := rows.Scan(
|
||||
&r.Value,
|
||||
&r.Label,
|
||||
); err != nil {
|
||||
http.Error(w, "scan error", 500)
|
||||
return
|
||||
}
|
||||
|
||||
list = append(list, r)
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
}
|
||||
func GetRolesForPermissionSelectRoute(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
rows, err := db.Query(queries.GetRolesForPermissionSelect)
|
||||
if err != nil {
|
||||
http.Error(w, "roles select error", 500)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
list := make([]IdTitleOption, 0)
|
||||
for rows.Next() {
|
||||
var o IdTitleOption
|
||||
if err := rows.Scan(&o.ID, &o.Title); err == nil {
|
||||
list = append(list, o)
|
||||
}
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
}
|
||||
|
||||
func GetDepartmentsForPermissionSelectRoute(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
rows, err := db.Query(queries.GetDepartmentsForPermissionSelect)
|
||||
if err != nil {
|
||||
http.Error(w, "departments select error", 500)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
list := make([]IdTitleOption, 0)
|
||||
for rows.Next() {
|
||||
var o IdTitleOption
|
||||
if err := rows.Scan(&o.ID, &o.Title); err == nil {
|
||||
list = append(list, o)
|
||||
}
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
}
|
||||
func GetUsersForPermissionSelectRoute(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
rows, err := db.Query(queries.GetUserLookupForPermission)
|
||||
if err != nil {
|
||||
http.Error(w, "users lookup error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
list := make([]IdTitleOption, 0, 128)
|
||||
|
||||
for rows.Next() {
|
||||
|
||||
var o IdTitleOption
|
||||
|
||||
if err := rows.Scan(&o.ID, &o.Title); err == nil {
|
||||
list = append(list, o)
|
||||
}
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *PermissionHandler) GetUserOverrides(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
claims, ok := auth.GetClaimsFromContext(r.Context())
|
||||
if !ok || claims == nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
userID, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)
|
||||
if err != nil || userID <= 0 {
|
||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
list, err := h.Repo.GetUserOverridesByUserID(userID)
|
||||
if err != nil {
|
||||
log.Println("❌ USER OVERRIDE LOAD ERROR:", err)
|
||||
http.Error(w, "db error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
func GetUserRoutePermissionsHandler(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
claims, ok := auth.GetClaimsFromContext(r.Context())
|
||||
if !ok || claims == nil {
|
||||
http.Error(w, "unauthorized", 401)
|
||||
return
|
||||
}
|
||||
|
||||
repo := permissions.NewPermissionRepository(db)
|
||||
|
||||
// JWT’den departmanlar
|
||||
depts := claims.DepartmentCodes
|
||||
|
||||
rows, err := db.Query(`
|
||||
SELECT DISTINCT
|
||||
module_code,
|
||||
action,
|
||||
path
|
||||
FROM mk_sys_routes
|
||||
`)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
type Row struct {
|
||||
Route string `json:"route"`
|
||||
CanAccess bool `json:"can_access"`
|
||||
}
|
||||
|
||||
list := make([]Row, 0, 64)
|
||||
|
||||
for rows.Next() {
|
||||
|
||||
var module, action, path string
|
||||
|
||||
if err := rows.Scan(
|
||||
&module,
|
||||
&action,
|
||||
&path,
|
||||
); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
allowed, err := repo.ResolvePermissionChain(
|
||||
int64(claims.ID),
|
||||
int64(claims.RoleID),
|
||||
depts,
|
||||
module,
|
||||
action,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println("PERM RESOLVE ERROR:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
list = append(list, Row{
|
||||
Route: path,
|
||||
CanAccess: allowed,
|
||||
})
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
}
|
||||
|
||||
func GetMyEffectivePermissions(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
claims, ok := auth.GetClaimsFromContext(r.Context())
|
||||
if !ok || claims == nil {
|
||||
http.Error(w, "unauthorized", 401)
|
||||
return
|
||||
}
|
||||
|
||||
repo := permissions.NewPermissionRepository(db)
|
||||
|
||||
// ✅ JWT'DEN DEPARTMENTS
|
||||
depts := claims.DepartmentCodes
|
||||
|
||||
log.Printf("🧪 EFFECTIVE PERM | user=%d role=%d depts=%v",
|
||||
claims.ID,
|
||||
claims.RoleID,
|
||||
depts,
|
||||
)
|
||||
|
||||
// all system perms
|
||||
all, err := db.Query(`
|
||||
SELECT DISTINCT module_code, action
|
||||
FROM mk_sys_routes
|
||||
`)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
defer all.Close()
|
||||
|
||||
type Row struct {
|
||||
Module string `json:"module"`
|
||||
Action string `json:"action"`
|
||||
Allowed bool `json:"allowed"`
|
||||
}
|
||||
|
||||
list := make([]Row, 0, 128)
|
||||
|
||||
for all.Next() {
|
||||
|
||||
var m, a string
|
||||
if err := all.Scan(&m, &a); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
allowed, err := repo.ResolvePermissionChain(
|
||||
int64(claims.ID),
|
||||
int64(claims.RoleID),
|
||||
depts,
|
||||
m,
|
||||
a,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
list = append(list, Row{
|
||||
Module: m,
|
||||
Action: a,
|
||||
Allowed: allowed,
|
||||
})
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user