Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-02-19 12:27:59 +03:00
parent 76e7ca2e4a
commit 1ced1b1649
6 changed files with 76 additions and 40 deletions

View File

@@ -212,19 +212,19 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
// ============================================================ // ============================================================
bindV3(r, pgDB, bindV3(r, pgDB,
"/api/password/change", "POST", "/api/password/change", "POST",
"system", "update", "auth", "update",
wrapV3(http.HandlerFunc(routes.FirstPasswordChangeHandler(pgDB))), wrapV3(http.HandlerFunc(routes.FirstPasswordChangeHandler(pgDB))),
) )
bindV3(r, pgDB, bindV3(r, pgDB,
"/api/activity-logs", "GET", "/api/activity-logs", "GET",
"user", "view", "system", "read",
wrapV3(routes.AdminActivityLogsHandler(pgDB)), wrapV3(routes.AdminActivityLogsHandler(pgDB)),
) )
bindV3(r, pgDB, bindV3(r, pgDB,
"/api/test-mail", "POST", "/api/test-mail", "POST",
"user", "insert", "system", "update",
wrapV3(routes.TestMailHandler(ml)), wrapV3(routes.TestMailHandler(ml)),
) )
@@ -235,12 +235,12 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
bindV3(r, pgDB, bindV3(r, pgDB,
rolePerm, "GET", rolePerm, "GET",
"user", "update", "system", "update",
wrapV3(routes.GetRolePermissionMatrix(pgDB)), wrapV3(routes.GetRolePermissionMatrix(pgDB)),
) )
bindV3(r, pgDB, bindV3(r, pgDB,
rolePerm, "POST", rolePerm, "POST",
"user", "update", "system", "update",
wrapV3(routes.SaveRolePermissionMatrix(pgDB)), wrapV3(routes.SaveRolePermissionMatrix(pgDB)),
) )
@@ -248,12 +248,12 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
bindV3(r, pgDB, bindV3(r, pgDB,
userPerm, "GET", userPerm, "GET",
"user", "update", "system", "update",
wrapV3(routes.GetUserPermissionsHandler(pgDB)), wrapV3(routes.GetUserPermissionsHandler(pgDB)),
) )
bindV3(r, pgDB, bindV3(r, pgDB,
userPerm, "POST", userPerm, "POST",
"user", "update", "system", "update",
wrapV3(routes.SaveUserPermissionsHandler(pgDB)), wrapV3(routes.SaveUserPermissionsHandler(pgDB)),
) )
@@ -286,17 +286,17 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
bindV3(r, pgDB, bindV3(r, pgDB,
"/api/role-dept-permissions/list", "GET", "/api/role-dept-permissions/list", "GET",
"user", "update", "system", "update",
wrapV3(http.HandlerFunc(rdHandler.List)), wrapV3(http.HandlerFunc(rdHandler.List)),
) )
bindV3(r, pgDB, bindV3(r, pgDB,
rdPerm, "GET", rdPerm, "GET",
"user", "update", "system", "update",
wrapV3(http.HandlerFunc(rdHandler.Get)), wrapV3(http.HandlerFunc(rdHandler.Get)),
) )
bindV3(r, pgDB, bindV3(r, pgDB,
rdPerm, "POST", rdPerm, "POST",
"user", "update", "system", "update",
wrapV3(http.HandlerFunc(rdHandler.Save)), wrapV3(http.HandlerFunc(rdHandler.Save)),
) )

View File

@@ -226,25 +226,25 @@ const menuItems = [
{ {
label: 'Rol + Departman Yetkileri', label: 'Rol + Departman Yetkileri',
to: '/app/role-dept-permissions', to: '/app/role-dept-permissions',
permission: 'user:update' permission: 'system:update'
}, },
{ {
label: 'Kullanıcı Yetkileri', label: 'Kullanıcı Yetkileri',
to: '/app/user-permissions', to: '/app/user-permissions',
permission: 'user:update' permission: 'system:update'
}, },
{ {
label: 'Loglar', label: 'Loglar',
to: '/app/activity-logs', to: '/app/activity-logs',
permission: 'user:view' permission: 'system:read'
}, },
{ {
label: 'Test Mail', label: 'Test Mail',
to: '/app/test-mail', to: '/app/test-mail',
permission: 'user:insert' permission: 'system:update'
} }
] ]
@@ -258,7 +258,7 @@ const menuItems = [
{ {
label: 'Kullanıcılar', label: 'Kullanıcılar',
to: '/app/users', to: '/app/users',
permission: 'user:view' permission: 'system:read'
} }
] ]
} }

View File

@@ -46,6 +46,9 @@
<q-item clickable @click="selectAllModules"> <q-item clickable @click="selectAllModules">
<q-item-section>Tümünü Seç</q-item-section> <q-item-section>Tümünü Seç</q-item-section>
</q-item> </q-item>
<q-item clickable @click="clearAllModules">
<q-item-section>Tümünü Temizle</q-item-section>
</q-item>
<q-separator /> <q-separator />
<q-item <q-item
v-for="m in store.modules" v-for="m in store.modules"
@@ -78,6 +81,9 @@
<q-item clickable @click="selectAllActionsForActive"> <q-item clickable @click="selectAllActionsForActive">
<q-item-section>Tümünü Seç</q-item-section> <q-item-section>Tümünü Seç</q-item-section>
</q-item> </q-item>
<q-item clickable @click="clearAllActionsForActive">
<q-item-section>Tümünü Temizle</q-item-section>
</q-item>
<q-separator /> <q-separator />
<q-item <q-item
v-for="a in actionsForActiveModule" v-for="a in actionsForActiveModule"
@@ -180,6 +186,7 @@ const canUpdateUser = canUpdate('user')
const selectedModules = ref([]) const selectedModules = ref([])
const selectedActionsByModule = ref({}) const selectedActionsByModule = ref({})
const activeModuleCode = ref('') const activeModuleCode = ref('')
const allowEmptySelection = ref(false)
const actionLabelMap = { const actionLabelMap = {
update: 'Güncelleme', update: 'Güncelleme',
@@ -284,9 +291,15 @@ function syncSelections () {
} }
const selected = selectedModules.value.filter((m) => availableModules.includes(m)) const selected = selectedModules.value.filter((m) => availableModules.includes(m))
selectedModules.value = selected.length ? selected : [...availableModules] if (selected.length) {
selectedModules.value = selected
} else {
selectedModules.value = allowEmptySelection.value ? [] : [...availableModules]
}
if (!selectedModules.value.includes(activeModuleCode.value)) { if (!selectedModules.value.length) {
activeModuleCode.value = ''
} else if (!selectedModules.value.includes(activeModuleCode.value)) {
activeModuleCode.value = selectedModules.value[0] activeModuleCode.value = selectedModules.value[0]
} }
@@ -295,7 +308,7 @@ function syncSelections () {
const allActions = actionsByModule.value[m] || [] const allActions = actionsByModule.value[m] || []
const prev = selectedActionsByModule.value[m] || [] const prev = selectedActionsByModule.value[m] || []
const filtered = prev.filter((a) => allActions.includes(a)) const filtered = prev.filter((a) => allActions.includes(a))
next[m] = filtered.length ? filtered : [...allActions] next[m] = filtered.length ? filtered : (allowEmptySelection.value ? [] : [...allActions])
}) })
selectedActionsByModule.value = next selectedActionsByModule.value = next
} }
@@ -313,6 +326,7 @@ function isModuleSelected (moduleCode) {
} }
function toggleModule (moduleCode, checked) { function toggleModule (moduleCode, checked) {
allowEmptySelection.value = false
const set = new Set(selectedModules.value) const set = new Set(selectedModules.value)
if (checked) { if (checked) {
set.add(moduleCode) set.add(moduleCode)
@@ -321,9 +335,8 @@ function toggleModule (moduleCode, checked) {
} }
selectedModules.value = [...set] selectedModules.value = [...set]
if (!selectedModules.value.length) { if (!selectedModules.value.length) {
selectedModules.value = [moduleCode] activeModuleCode.value = ''
} } else if (!selectedModules.value.includes(activeModuleCode.value)) {
if (!selectedModules.value.includes(activeModuleCode.value)) {
activeModuleCode.value = selectedModules.value[0] activeModuleCode.value = selectedModules.value[0]
} }
syncSelections() syncSelections()
@@ -334,24 +347,31 @@ function onModuleRowClick (moduleCode) {
} }
function selectAllModules () { function selectAllModules () {
allowEmptySelection.value = false
selectedModules.value = (store.modules || []).map((m) => m.value) selectedModules.value = (store.modules || []).map((m) => m.value)
syncSelections() syncSelections()
} }
function clearAllModules () {
allowEmptySelection.value = true
selectedModules.value = []
selectedActionsByModule.value = {}
activeModuleCode.value = ''
syncSelections()
}
function isActionSelected (moduleCode, action) { function isActionSelected (moduleCode, action) {
return (selectedActionsByModule.value[moduleCode] || []).includes(action) return (selectedActionsByModule.value[moduleCode] || []).includes(action)
} }
function toggleAction (moduleCode, action, checked) { function toggleAction (moduleCode, action, checked) {
allowEmptySelection.value = false
const current = new Set(selectedActionsByModule.value[moduleCode] || []) const current = new Set(selectedActionsByModule.value[moduleCode] || [])
if (checked) { if (checked) {
current.add(action) current.add(action)
} else { } else {
current.delete(action) current.delete(action)
} }
if (current.size === 0) {
current.add(action)
}
selectedActionsByModule.value = { selectedActionsByModule.value = {
...selectedActionsByModule.value, ...selectedActionsByModule.value,
[moduleCode]: [...current] [moduleCode]: [...current]
@@ -359,6 +379,7 @@ function toggleAction (moduleCode, action, checked) {
} }
function selectAllActionsForActive () { function selectAllActionsForActive () {
allowEmptySelection.value = false
if (!activeModuleCode.value) return if (!activeModuleCode.value) return
selectedActionsByModule.value = { selectedActionsByModule.value = {
...selectedActionsByModule.value, ...selectedActionsByModule.value,
@@ -366,6 +387,15 @@ function selectAllActionsForActive () {
} }
} }
function clearAllActionsForActive () {
allowEmptySelection.value = true
if (!activeModuleCode.value) return
selectedActionsByModule.value = {
...selectedActionsByModule.value,
[activeModuleCode.value]: []
}
}
const permissionColumns = computed(() => { const permissionColumns = computed(() => {
const cols = [] const cols = []
selectedModules.value.forEach((m) => { selectedModules.value.forEach((m) => {

View File

@@ -14,6 +14,9 @@ export default route(function () {
routes routes
}) })
if (typeof window !== 'undefined' && process.env.DEV) {
window.__router = router
}
/* ============================================================ /* ============================================================
🔐 GLOBAL GUARD 🔐 GLOBAL GUARD
@@ -23,6 +26,17 @@ export default route(function () {
const auth = useAuthStore() const auth = useAuthStore()
const perm = usePermissionStore() const perm = usePermissionStore()
if (typeof window !== 'undefined') {
console.warn('🧭 ROUTE GUARD HIT:', {
path: to.fullPath,
meta: to.meta
})
}
if (typeof window !== 'undefined' && process.env.DEV) {
window.__auth = auth
window.__perm = perm
}
/* ================= PUBLIC ================= */ /* ================= PUBLIC ================= */

View File

@@ -69,7 +69,7 @@ const routes = [
path: '', path: '',
name: 'dashboard', name: 'dashboard',
component: () => import('pages/Dashboard.vue'), component: () => import('pages/Dashboard.vue'),
meta: { permission: 'system:read' } meta: {}
}, },
@@ -86,28 +86,28 @@ const routes = [
path: 'role-dept-permissions', path: 'role-dept-permissions',
name: 'role-dept-permissions', name: 'role-dept-permissions',
component: () => import('pages/RoleDepartmentPermissionGateway.vue'), component: () => import('pages/RoleDepartmentPermissionGateway.vue'),
meta: { permission: 'user:update' } meta: { permission: 'system:update' }
}, },
{ {
path: 'role-dept-permissions/list', path: 'role-dept-permissions/list',
name: 'role-dept-permissions-list', name: 'role-dept-permissions-list',
component: () => import('pages/RoleDepartmentPermissionList.vue'), component: () => import('pages/RoleDepartmentPermissionList.vue'),
meta: { permission: 'user:update' } meta: { permission: 'system:update' }
}, },
{ {
path: 'role-dept-permissions/editor', path: 'role-dept-permissions/editor',
name: 'role-dept-permissions-editor', name: 'role-dept-permissions-editor',
component: () => import('pages/RoleDepartmentPermissionPage.vue'), component: () => import('pages/RoleDepartmentPermissionPage.vue'),
meta: { permission: 'user:update' } meta: { permission: 'system:update' }
}, },
{ {
path: 'user-permissions', path: 'user-permissions',
name: 'user-permissions', name: 'user-permissions',
component: () => import('pages/UserPermissionPage.vue'), component: () => import('pages/UserPermissionPage.vue'),
meta: { permission: 'user:update' } meta: { permission: 'system:update' }
}, },
@@ -190,7 +190,7 @@ const routes = [
path: 'activity-logs', path: 'activity-logs',
name: 'activity-logs', name: 'activity-logs',
component: () => import('pages/ActivityLogs.vue'), component: () => import('pages/ActivityLogs.vue'),
meta: { permission: 'user:view' } meta: { permission: 'system:read' }
}, },
@@ -200,7 +200,7 @@ const routes = [
path: 'test-mail', path: 'test-mail',
name: 'test-mail', name: 'test-mail',
component: () => import('pages/TestMail.vue'), component: () => import('pages/TestMail.vue'),
meta: { permission: 'user:insert' } meta: { permission: 'system:update' }
}, },

View File

@@ -78,15 +78,7 @@ export const useAuthStore = defineStore('auth', {
========================================================= */ ========================================================= */
setSession ({ token, user }) { setSession ({ token, user }) {
this.token = token this.token = token
if (user) { this.user = user || null
// Keep prior role fields if backend returns partial user payload.
this.user = {
...(this.user || {}),
...user
}
} else {
this.user = null
}
this.forcePasswordChange = !!user?.force_password_change this.forcePasswordChange = !!user?.force_password_change
localStorage.setItem('token', token) localStorage.setItem('token', token)