Merge remote-tracking branch 'origin/master'
This commit is contained in:
20
svc/main.go
20
svc/main.go
@@ -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)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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 ================= */
|
||||||
|
|
||||||
|
|||||||
@@ -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' }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user