Files
bssapp/svc/routes/role_department_permissions.go
2026-02-11 17:46:22 +03:00

441 lines
9.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
// JWTden 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)
}
}