mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
@@ -4,7 +4,12 @@ const resource = 'accounts'
|
||||
|
||||
export default {
|
||||
getAll({ domain, role }) {
|
||||
return repository.get(`/${resource}/`, { params: { domain, role } })
|
||||
return repository.get(`/${resource}/`, {
|
||||
params: { domain, role },
|
||||
paramsSerializer: {
|
||||
indexes: null,
|
||||
},
|
||||
})
|
||||
},
|
||||
get(accountId) {
|
||||
return repository.get(`${resource}/${accountId}/`)
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
<script setup>
|
||||
import accountApi from '@/api/accounts'
|
||||
import domainApi from '@/api/domains'
|
||||
import constants from '@/constants.json'
|
||||
import { useBusStore } from '@/stores'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { ref, onMounted } from 'vue'
|
||||
@@ -128,13 +129,15 @@ function fetchAdministrators(domain) {
|
||||
}
|
||||
|
||||
function fetchAccounts() {
|
||||
accountApi.getAll({ role: 'DomainAdmins' }).then((resp) => {
|
||||
accounts.value = resp.data.filter(
|
||||
(account) =>
|
||||
administrators.value.find((admin) => admin.id === account.pk) ===
|
||||
undefined
|
||||
)
|
||||
})
|
||||
accountApi
|
||||
.getAll({ role: [constants.RESELLER, constants.DOMAIN_ADMIN] })
|
||||
.then((resp) => {
|
||||
accounts.value = resp.data.filter(
|
||||
(account) =>
|
||||
administrators.value.find((admin) => admin.id === account.pk) ===
|
||||
undefined
|
||||
)
|
||||
})
|
||||
}
|
||||
function addAdministrator() {
|
||||
domainApi
|
||||
|
||||
@@ -138,7 +138,8 @@
|
||||
v-if="
|
||||
limitsConfig.params &&
|
||||
limitsConfig.params.enable_domain_limits &&
|
||||
(authUser.role === 'SuperAdmins' || authUser.role === 'Resellers')
|
||||
(authUser.role === constants.SUPER_ADMIN ||
|
||||
authUser.role === constants.RESELLER)
|
||||
"
|
||||
value="resourcesForm"
|
||||
eager
|
||||
@@ -184,6 +185,7 @@ import { useGettext } from 'vue3-gettext'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import { useRouter } from 'vue-router'
|
||||
import domainsApi from '@/api/domains'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const router = useRouter()
|
||||
const { $gettext } = useGettext()
|
||||
@@ -219,8 +221,8 @@ const formMap = computed(() => {
|
||||
if (
|
||||
limitsConfig.value.params &&
|
||||
limitsConfig.value.params.enable_domain_limits &&
|
||||
(authUser.value.role === 'SuperAdmins' ||
|
||||
authUser.value.role === 'Resellers')
|
||||
(authUser.value.role === constants.SUPER_ADMIN ||
|
||||
authUser.value.role === constants.RESELLER)
|
||||
) {
|
||||
map.resourcesForm = resourcesForm
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ import AccountRoleForm from './form_steps/AccountRoleForm.vue'
|
||||
import AccountGeneralForm from './form_steps/AccountGeneralForm.vue'
|
||||
import AccountMailboxForm from './form_steps/AccountMailboxForm.vue'
|
||||
import AccountAliasForm from './form_steps/AccountAliasForm.vue'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { ref, computed } from 'vue'
|
||||
@@ -81,10 +82,7 @@ const domainsStore = useDomainsStore()
|
||||
const emit = defineEmits(['close', 'created'])
|
||||
|
||||
const needsMailbox = computed(
|
||||
() =>
|
||||
account.value.role !== 'SuperAdmins' &&
|
||||
account.value.username &&
|
||||
account.value.username.indexOf('@') !== -1
|
||||
() => account.value.username && account.value.username.indexOf('@') !== -1
|
||||
)
|
||||
|
||||
const summarySections = computed(() => {
|
||||
@@ -187,7 +185,7 @@ const steps = computed(() => {
|
||||
const account = ref({
|
||||
aliases: [],
|
||||
is_active: true,
|
||||
role: 'SimpleUsers',
|
||||
role: constants.USER,
|
||||
mailbox: {
|
||||
use_domain_quota: true,
|
||||
},
|
||||
@@ -234,19 +232,33 @@ function setFormErrors(step, errors) {
|
||||
function preparePayload(payload) {
|
||||
const cleaned_payload = { ...payload }
|
||||
if (
|
||||
cleaned_payload.role === 'SuperAdmins' &&
|
||||
[constants.RESELLER, constants.SUPER_ADMIN].includes(
|
||||
cleaned_payload.role
|
||||
) &&
|
||||
cleaned_payload.username &&
|
||||
cleaned_payload.username.indexOf('@') === -1
|
||||
) {
|
||||
delete cleaned_payload.mailbox
|
||||
}
|
||||
if (cleaned_payload.mailbox && cleaned_payload.mailbox.message_limit === '') {
|
||||
cleaned_payload.mailbox.message_limit = null
|
||||
if (cleaned_payload.mailbox) {
|
||||
if (cleaned_payload.mailbox.message_limit === '') {
|
||||
cleaned_payload.mailbox.message_limit = null
|
||||
}
|
||||
if (
|
||||
cleaned_payload.mailbox.quota === undefined ||
|
||||
cleaned_payload.mailbox.quota === null
|
||||
) {
|
||||
cleaned_payload.mailbox.quota = 0
|
||||
}
|
||||
}
|
||||
return cleaned_payload
|
||||
}
|
||||
|
||||
function validateAccount() {
|
||||
function validateAccount(step) {
|
||||
if (step === 1) {
|
||||
// No validation after role selection
|
||||
return true
|
||||
}
|
||||
const payload = preparePayload({ ...account.value })
|
||||
return accountsApi.validate(payload)
|
||||
}
|
||||
|
||||
@@ -209,6 +209,7 @@ import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { usePermissions } from '@/composables/permissions'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const authStore = useAuthStore()
|
||||
@@ -229,8 +230,8 @@ const needsResources = computed(() => {
|
||||
const isNeeded =
|
||||
limitsConfig.value.params &&
|
||||
limitsConfig.value.params.enable_admin_limits &&
|
||||
editedAccount.value.role !== 'SimpleUsers' &&
|
||||
editedAccount.value.role !== 'SuperAdmins'
|
||||
editedAccount.value.role !== constants.USER &&
|
||||
editedAccount.value.role !== constants.SUPER_ADMIN
|
||||
if (isNeeded === undefined) {
|
||||
return false
|
||||
}
|
||||
@@ -285,7 +286,7 @@ async function save() {
|
||||
const data = { ...editedAccount.value }
|
||||
if (usernameIsEmail.value) {
|
||||
data.mailbox.full_address = data.username
|
||||
} else {
|
||||
} else if (data.mailbox) {
|
||||
delete data.mailbox.full_address
|
||||
}
|
||||
if (data.new_password) {
|
||||
@@ -303,7 +304,7 @@ async function save() {
|
||||
if (editedAccount.value.pk === authStore.authUser.pk) {
|
||||
data.role = authStore.authUser.role
|
||||
} else {
|
||||
data.role = 'SimpleUsers'
|
||||
data.role = constants.USER
|
||||
}
|
||||
}
|
||||
await accountsApi.patch(editedAccount.value.pk, data)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<v-col v-else cols="6">
|
||||
<v-progress-linear
|
||||
:color="account.mailbox.quota_usage < 80 ? 'primary' : 'warning'"
|
||||
:value="account.mailbox.quota_usage"
|
||||
:model-value="account.mailbox.quota_usage"
|
||||
height="25"
|
||||
class="white--text"
|
||||
>
|
||||
|
||||
@@ -57,6 +57,7 @@ import { ref, computed } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import rules from '@/plugins/rules'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const authStore = useAuthStore()
|
||||
@@ -72,21 +73,18 @@ const formErrors = ref({})
|
||||
const account = computed(() => props.modelValue)
|
||||
|
||||
const usernamePlaceholder = computed(() => {
|
||||
if (account.value.role === 'SimpleUsers') {
|
||||
if (account.value.role === constants.USER) {
|
||||
return $gettext('Enter an email address')
|
||||
}
|
||||
return $gettext('Enter a simple username or an email address')
|
||||
})
|
||||
|
||||
const usernameInputType = computed(() => {
|
||||
return account.value.role === 'SimpleUsers' ? 'email' : 'text'
|
||||
return account.value.role === constants.USER ? 'email' : 'text'
|
||||
})
|
||||
|
||||
function updateUsername() {
|
||||
if (
|
||||
account.value.role != 'SuperAdmins' &&
|
||||
account.value.username.indexOf('@') !== -1
|
||||
) {
|
||||
if (account.value.username.indexOf('@') !== -1) {
|
||||
account.value.mailbox.full_address = account.value.username
|
||||
account.value.mailbox.message_limit = null
|
||||
}
|
||||
|
||||
@@ -44,11 +44,12 @@
|
||||
</v-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { useDomainsStore } from '@/stores'
|
||||
import rules from '@/plugins/rules'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
@@ -68,7 +69,7 @@ watch(
|
||||
(value) => {
|
||||
if (value) {
|
||||
form.value = { ...value }
|
||||
if (form.value.role === 'SimpleUsers') {
|
||||
if (form.value.role === constants.USER) {
|
||||
if (!form.value.mailbox) {
|
||||
form.value.mailbox = {}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,12 @@
|
||||
</v-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
<script setup>
|
||||
import ChoiceField from '@/components/tools/ChoiceField'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const { $gettext } = useGettext()
|
||||
@@ -59,16 +60,16 @@ const roleHelp = computed(() => {
|
||||
})
|
||||
|
||||
const accountRoles = computed(() => {
|
||||
if (authUser.value.role === 'SuperAdmins') {
|
||||
if (authUser.value.role === constants.SUPER_ADMIN) {
|
||||
return [
|
||||
...simpleUserRole,
|
||||
...domainAdminsRole,
|
||||
...resellerRole,
|
||||
...simpleUserRole,
|
||||
...superAdminsRole,
|
||||
]
|
||||
} else if (authUser.value.role === 'DomainAdmins') {
|
||||
} else if (authUser.value.role === constants.DOMAIN_ADMIN) {
|
||||
return [...simpleUserRole]
|
||||
} else if (authUser.value.role === 'Resellers') {
|
||||
} else if (authUser.value.role === constants.RESELLER) {
|
||||
return [...domainAdminsRole, ...simpleUserRole]
|
||||
} else {
|
||||
return []
|
||||
@@ -78,7 +79,7 @@ const accountRoles = computed(() => {
|
||||
const simpleUserRole = [
|
||||
{
|
||||
label: $gettext('Simple user'),
|
||||
value: 'SimpleUsers',
|
||||
value: constants.USER,
|
||||
help: $gettext(
|
||||
'A user with no privileges but with a mailbox. He will be allowed to use all end-user features: webmail, calendar, contacts, filters.'
|
||||
),
|
||||
@@ -88,7 +89,7 @@ const simpleUserRole = [
|
||||
const domainAdminsRole = [
|
||||
{
|
||||
label: $gettext('Domain administrator'),
|
||||
value: 'DomainAdmins',
|
||||
value: constants.DOMAIN_ADMIN,
|
||||
help: $gettext(
|
||||
'A user with privileges on one or more domain. He will be allowed to administer mailboxes and he can also have a mailbox.'
|
||||
),
|
||||
@@ -97,14 +98,16 @@ const domainAdminsRole = [
|
||||
const resellerRole = [
|
||||
{
|
||||
label: $gettext('Reseller'),
|
||||
value: 'Resellers',
|
||||
help: $gettext('help'),
|
||||
value: constants.RESELLER,
|
||||
help: $gettext(
|
||||
'An intermediate user who has the same privileges than a Domain administrator, plus the possibility to create domains and to assign resources.'
|
||||
),
|
||||
},
|
||||
]
|
||||
const superAdminsRole = [
|
||||
{
|
||||
label: $gettext('Super administrator'),
|
||||
value: 'SuperAdmins',
|
||||
value: constants.SUPER_ADMIN,
|
||||
help: $gettext(
|
||||
"A user with all privileges, can do anything. By default, such a user does not have a mailbox so he can't access end-user features."
|
||||
),
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useGlobalStore, useAuthStore, useLayoutStore } from '@/stores'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const props = defineProps({
|
||||
color: {
|
||||
@@ -141,7 +142,7 @@ function displayMenuItem(item) {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (authUser.value.role === 'SuperAdmins') {
|
||||
if (authUser.value.role === constants.SUPER_ADMIN) {
|
||||
globalStore.fetchNotifications()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<div
|
||||
v-for="(lineChoices, index1) in formatedChoices"
|
||||
:key="index1"
|
||||
class="d-flex"
|
||||
class="d-flex flex-grow-0"
|
||||
>
|
||||
<div
|
||||
v-for="(choice, index2) in lineChoices"
|
||||
|
||||
@@ -150,7 +150,7 @@ async function goToNextStep(current, next) {
|
||||
}
|
||||
if (props.validateObject) {
|
||||
try {
|
||||
await props.validateObject()
|
||||
await props.validateObject(current)
|
||||
} catch (error) {
|
||||
emit('validationError', current, error.response.data)
|
||||
return
|
||||
|
||||
@@ -25,17 +25,16 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, onUpdated, nextTick } from 'vue'
|
||||
import { useDomainsStore } from '@/stores'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const domainsStore = useDomainsStore()
|
||||
const props = defineProps({
|
||||
modelValue: { type: String, default: '' },
|
||||
allowAdd: { type: Boolean, default: false },
|
||||
role: { type: String, default: 'SimpleUsers' },
|
||||
role: { type: String, default: constants.USER },
|
||||
errorMsg: { type: Array, default: () => [] },
|
||||
})
|
||||
const emit = defineEmits(['domain-selected', 'update:model-value'])
|
||||
@@ -47,15 +46,11 @@ const input = computed({
|
||||
set(value) {
|
||||
errors.value = []
|
||||
if (value.indexOf('@') !== -1) {
|
||||
if (props.role !== 'SuperAdmins') {
|
||||
domainSearch.value = value.split('@')[1]
|
||||
if (props.allowAdd) {
|
||||
showMenu.value = filteredDomains.value.length > 0
|
||||
} else {
|
||||
showMenu.value = true
|
||||
}
|
||||
domainSearch.value = value.split('@')[1]
|
||||
if (props.allowAdd) {
|
||||
showMenu.value = filteredDomains.value.length > 0
|
||||
} else {
|
||||
errors.value = [$gettext('SuperAdmins cannot own a mailbox')]
|
||||
showMenu.value = true
|
||||
}
|
||||
} else {
|
||||
showMenu.value = false
|
||||
@@ -87,10 +82,6 @@ const inputRef = ref()
|
||||
const localErrors = ref([])
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (props.role === 'SuperAdmins') {
|
||||
// No mailbox for SuperAdmins
|
||||
return
|
||||
}
|
||||
const keyCode = e.keyCode
|
||||
if (keyCode === 40 || keyCode === 34) {
|
||||
// on arrow down or page down
|
||||
|
||||
@@ -5,21 +5,40 @@
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<div v-for="resource in resources" :key="resource.name" class="mt-4">
|
||||
{{ resource.label }} ({{ Math.ceil(resource.usage) }}%)
|
||||
<v-progress-linear
|
||||
:value="resource.usage"
|
||||
:color="getProgressColor(resource.usage)"
|
||||
/>
|
||||
<template v-if="resource.max_value === -1">
|
||||
{{ resource.label }} ({{ $gettext('Unlimited') }})
|
||||
</template>
|
||||
<template v-else-if="resource.max_value === 0">
|
||||
{{ resource.label }} ({{ noLimitLabel(resource) }})
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ resource.label }} ({{ Math.ceil(resource.usage) }}%)
|
||||
<v-progress-linear
|
||||
:model-value="resource.usage"
|
||||
:color="getProgressColor(resource.usage)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
<script setup>
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
defineProps({
|
||||
resources: { type: Array, default: null },
|
||||
})
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const noLimitLabel = (resource) => {
|
||||
if (resource.name === 'quota') {
|
||||
return $gettext('No quota')
|
||||
}
|
||||
return $gettext('Creation denied')
|
||||
}
|
||||
|
||||
function getProgressColor(value) {
|
||||
if (value < 50) {
|
||||
return 'primary'
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import { computed } from 'vue'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
export function usePermissions() {
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const canSetRole = computed(() => {
|
||||
return ['Resellers', 'SuperAdmins'].includes(authStore.authUser.role)
|
||||
return [constants.RESELLER, constants.SUPER_ADMIN].includes(
|
||||
authStore.authUser.role
|
||||
)
|
||||
})
|
||||
|
||||
const canAddDomain = computed(() => {
|
||||
return ['Resellers', 'SuperAdmins'].includes(authStore.authUser.role)
|
||||
return [constants.RESELLER, constants.SUPER_ADMIN].includes(
|
||||
authStore.authUser.role
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"ALARM_OPENED": 1,
|
||||
"ALARM_CLOSED": 2
|
||||
"ALARM_OPENED": 1,
|
||||
"ALARM_CLOSED": 2,
|
||||
"SUPER_ADMIN": "SuperAdmins",
|
||||
"RESELLER": "Resellers",
|
||||
"DOMAIN_ADMIN": "DomainAdmins",
|
||||
"USER": "SimpleUsers"
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useAuthStore, useParametersStore } from '@/stores'
|
||||
import parametersApi from '@/api/parameters'
|
||||
import capabilitiesApi from '@/api/capabilities'
|
||||
import ConnectedLayout from '@/layouts/connected/ConnectedLayout.vue'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const authStore = useAuthStore()
|
||||
@@ -38,13 +39,13 @@ const adminMenuItems = [
|
||||
text: $gettext('Domains'),
|
||||
to: { name: 'DomainList' },
|
||||
icon: 'mdi-domain',
|
||||
roles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
roles: [constants.DOMAIN_ADMIN, constants.RESELLER, constants.SUPER_ADMIN],
|
||||
},
|
||||
{
|
||||
text: $gettext('Identities'),
|
||||
to: { name: 'Identities' },
|
||||
icon: 'mdi-account',
|
||||
roles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
roles: [constants.DOMAIN_ADMIN, constants.RESELLER, constants.SUPER_ADMIN],
|
||||
},
|
||||
{
|
||||
text: $gettext('Alarms'),
|
||||
@@ -54,40 +55,44 @@ const adminMenuItems = [
|
||||
{
|
||||
icon: 'mdi-history',
|
||||
text: $gettext('Monitoring'),
|
||||
roles: ['SuperAdmins', 'Resellers', 'DomainAdmins'],
|
||||
roles: [constants.SUPER_ADMIN, constants.RESELLER, constants.DOMAIN_ADMIN],
|
||||
children: [
|
||||
{
|
||||
text: $gettext('Statistics'),
|
||||
to: { name: 'Statistics' },
|
||||
roles: ['SuperAdmins'],
|
||||
roles: [constants.SUPER_ADMIN],
|
||||
},
|
||||
{
|
||||
text: $gettext('Audit trail'),
|
||||
to: { name: 'AuditTrail' },
|
||||
roles: ['SuperAdmins'],
|
||||
roles: [constants.SUPER_ADMIN],
|
||||
},
|
||||
{
|
||||
text: $gettext('Messages'),
|
||||
to: { name: 'MessageLog' },
|
||||
roles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
roles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: 'mdi-email-sync-outline',
|
||||
text: $gettext('IMAP Migration'),
|
||||
roles: ['SuperAdmins', 'Resellers'],
|
||||
roles: [constants.SUPER_ADMIN, constants.RESELLER],
|
||||
condition: () => imapMigrationEnabled.value,
|
||||
children: [
|
||||
{
|
||||
text: $gettext('Email providers'),
|
||||
to: { name: 'ProvidersList' },
|
||||
roles: ['SuperAdmins', 'Resellers'],
|
||||
roles: [constants.SUPER_ADMIN, constants.RESELLER],
|
||||
},
|
||||
{
|
||||
text: $gettext('Migrations'),
|
||||
to: { name: 'MigrationsList' },
|
||||
roles: ['Resellers', 'SuperAdmins'],
|
||||
roles: [constants.RESELLER, constants.SUPER_ADMIN],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -95,26 +100,26 @@ const adminMenuItems = [
|
||||
icon: 'mdi-cog',
|
||||
text: $gettext('Settings'),
|
||||
children: settings,
|
||||
roles: ['SuperAdmins'],
|
||||
roles: [constants.SUPER_ADMIN],
|
||||
},
|
||||
{
|
||||
icon: 'mdi-email-check-outline',
|
||||
text: 'Rspamd',
|
||||
action: openRspamdDashboard,
|
||||
roles: ['SuperAdmins'],
|
||||
roles: [constants.SUPER_ADMIN],
|
||||
condition: () => isRspamdVisible.value,
|
||||
},
|
||||
{
|
||||
icon: 'mdi-information',
|
||||
text: $gettext('Information'),
|
||||
roles: ['SuperAdmins'],
|
||||
roles: [constants.SUPER_ADMIN],
|
||||
to: { name: 'Information' },
|
||||
withBell: true,
|
||||
},
|
||||
]
|
||||
|
||||
onMounted(() => {
|
||||
if (authUser.value.role === 'SuperAdmins') {
|
||||
if (authUser.value.role === constants.SUPER_ADMIN) {
|
||||
parametersApi.getGlobalApplications().then((response) => {
|
||||
response.data.forEach((item) => {
|
||||
settings.push({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useAuthStore } from '@/stores'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
export default {
|
||||
install: (app) => {
|
||||
@@ -8,7 +9,7 @@ export default {
|
||||
const permission = binding.value
|
||||
if (authStore.authUser) {
|
||||
if (
|
||||
authUser.authUser.role !== 'SuperAdmins' &&
|
||||
authUser.authUser.role !== constants.SUPER_ADMIN &&
|
||||
authStore.authUser.permissions.indexOf(permission) === -1
|
||||
) {
|
||||
el.style.display = 'none'
|
||||
@@ -21,7 +22,7 @@ export default {
|
||||
return false
|
||||
}
|
||||
if (
|
||||
authStore.authUser.role === 'SuperAdmins' ||
|
||||
authStore.authUser.role === constants.SUPER_ADMIN ||
|
||||
authStore.authUser.permissions.indexOf(permission) !== -1
|
||||
) {
|
||||
return true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Composables
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -26,7 +26,11 @@ const routes = [
|
||||
path: '/admin',
|
||||
component: () => import('@/layouts/admin/AdminLayout.vue'),
|
||||
meta: {
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@@ -42,7 +46,11 @@ const routes = [
|
||||
component: () => import('@/layouts/empty/EmptyLayout.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@@ -51,7 +59,11 @@ const routes = [
|
||||
component: () => import('@/views/admin/domains/DomainsView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -59,7 +71,11 @@ const routes = [
|
||||
name: 'DomainDetail',
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
component: () => import('@/views/admin/domains/DomainView.vue'),
|
||||
},
|
||||
@@ -68,7 +84,11 @@ const routes = [
|
||||
name: 'DomainEdit',
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
component: () => import('@/views/admin/domains/DomainEditView.vue'),
|
||||
},
|
||||
@@ -79,7 +99,11 @@ const routes = [
|
||||
component: () => import('@/layouts/empty/EmptyLayout.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@@ -89,7 +113,7 @@ const routes = [
|
||||
import('@/views/admin/imap_migration/MigrationsView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [constants.RESELLER, constants.SUPER_ADMIN],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -97,7 +121,7 @@ const routes = [
|
||||
component: () => import('@/layouts/empty/EmptyLayout.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [constants.RESELLER, constants.SUPER_ADMIN],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@@ -107,7 +131,7 @@ const routes = [
|
||||
import('@/views/admin/imap_migration/ProvidersView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [constants.RESELLER, constants.SUPER_ADMIN],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -117,7 +141,7 @@ const routes = [
|
||||
import('@/views/admin/imap_migration/ProviderEditView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [constants.RESELLER, constants.SUPER_ADMIN],
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -129,7 +153,11 @@ const routes = [
|
||||
component: () => import('@/layouts/empty/EmptyLayout.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@@ -139,7 +167,11 @@ const routes = [
|
||||
import('@/views/admin/identities/IdentitiesView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -148,7 +180,11 @@ const routes = [
|
||||
component: () => import('@/views/admin/identities/AccountView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -158,7 +194,11 @@ const routes = [
|
||||
import('@/views/admin/identities/AccountEditView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -167,7 +207,11 @@ const routes = [
|
||||
component: () => import('@/views/admin/identities/AliasView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -177,7 +221,11 @@ const routes = [
|
||||
import('@/views/admin/identities/AliasEditView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'Resellers', 'SuperAdmins'],
|
||||
allowedRoles: [
|
||||
constants.DOMAIN_ADMIN,
|
||||
constants.RESELLER,
|
||||
constants.SUPER_ADMIN,
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -188,7 +236,7 @@ const routes = [
|
||||
component: () => import('@/views/admin/ParametersView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['SuperAdmins'],
|
||||
allowedRoles: [constants.SUPER_ADMIN],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -205,7 +253,7 @@ const routes = [
|
||||
component: () => import('@/views/admin/monitoring/StatisticsView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['SuperAdmins'],
|
||||
allowedRoles: [constants.SUPER_ADMIN],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -214,7 +262,7 @@ const routes = [
|
||||
component: () => import('@/views/admin/monitoring/AuditTrailView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['SuperAdmins'],
|
||||
allowedRoles: [constants.SUPER_ADMIN],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -223,7 +271,7 @@ const routes = [
|
||||
component: () => import('@/views/admin/monitoring/MessagesView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['DomainAdmins', 'SuperAdmins'],
|
||||
allowedRoles: [constants.DOMAIN_ADMIN, constants.SUPER_ADMIN],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -232,7 +280,7 @@ const routes = [
|
||||
component: () => import('@/views/admin/InformationView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
allowedRoles: ['SuperAdmins'],
|
||||
allowedRoles: [constants.SUPER_ADMIN],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
<v-tab v-if="authStore.userHasMailbox" value="autoreply">
|
||||
{{ $gettext('Auto-reply message') }}
|
||||
</v-tab>
|
||||
<v-tab v-if="authStore.authUser.role === 'SuperAdmins'" value="api">
|
||||
<v-tab
|
||||
v-if="authStore.authUser.role === constants.SUPER_ADMIN"
|
||||
value="api"
|
||||
>
|
||||
{{ $gettext('API access') }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
@@ -36,7 +39,7 @@
|
||||
<AutoReplyForm />
|
||||
</v-tabs-window-item>
|
||||
<v-tabs-window-item
|
||||
v-if="authStore.authUser.role === 'SuperAdmins'"
|
||||
v-if="authStore.authUser.role === constants.SUPER_ADMIN"
|
||||
value="api"
|
||||
>
|
||||
<APISetupForm />
|
||||
@@ -55,6 +58,7 @@ import AutoReplyForm from '@/components/account/AutoReplyForm.vue'
|
||||
import APISetupForm from '@/components/account/APISetupForm.vue'
|
||||
import FidoAuthForm from '@/components/account/FidoAuthForm.vue'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const tab = ref()
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<v-col cols="6">
|
||||
<AccountSummary :account="account" />
|
||||
<DomainAdminDomains
|
||||
v-if="account.role === 'DomainAdmins'"
|
||||
v-if="account.role === constants.DOMAIN_ADMIN"
|
||||
class="mt-2"
|
||||
:account="account"
|
||||
/>
|
||||
@@ -24,8 +24,8 @@
|
||||
v-if="
|
||||
limitsConfig.params &&
|
||||
limitsConfig.params.enable_admin_limits &&
|
||||
account.role !== 'SimpleUsers' &&
|
||||
account.role !== 'SuperAdmins'
|
||||
account.role !== constants.USER &&
|
||||
account.role !== constants.SUPER_ADMIN
|
||||
"
|
||||
:resources="account.resources"
|
||||
/>
|
||||
@@ -40,7 +40,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { usePermissions } from '@/composables/permissions'
|
||||
import accountsApi from '@/api/accounts'
|
||||
@@ -50,6 +50,7 @@ import AccountSenderAddresses from '@/components/admin/identities/AccountSenderA
|
||||
import AccountSummary from '@/components/admin/identities/AccountSummary.vue'
|
||||
import DomainAdminDomains from '@/components/admin/identities/DomainAdminDomains.vue'
|
||||
import ResourcesView from '@/components/tools/ResourcesView.vue'
|
||||
import constants from '@/constants.json'
|
||||
|
||||
const route = useRoute()
|
||||
const { canSetRole } = usePermissions()
|
||||
|
||||
@@ -19,7 +19,7 @@ from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
|
||||
from modoboa.admin.api.v1 import viewsets as v1_viewsets
|
||||
from modoboa.core import models as core_models
|
||||
from modoboa.core import constants as core_constants, models as core_models
|
||||
from modoboa.lib import pagination
|
||||
from modoboa.lib import renderers as lib_renderers
|
||||
from modoboa.lib import viewsets as lib_viewsets
|
||||
@@ -153,14 +153,16 @@ class AccountFilterSet(dj_filters.FilterSet):
|
||||
queryset=lambda request: models.Domain.objects.get_for_admin(request.user),
|
||||
field_name="mailbox__domain",
|
||||
)
|
||||
role = dj_filters.CharFilter(method="filter_role")
|
||||
role = dj_filters.MultipleChoiceFilter(
|
||||
choices=core_constants.ROLES, method="filter_role"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = core_models.User
|
||||
fields = ["domain", "role"]
|
||||
|
||||
def filter_role(self, queryset, name, value):
|
||||
return queryset.filter(groups__name=value)
|
||||
return queryset.filter(groups__name__in=value)
|
||||
|
||||
|
||||
class AccountViewSet(v1_viewsets.AccountViewSet):
|
||||
|
||||
@@ -152,3 +152,10 @@ class IsSuperUser(permissions.BasePermission):
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return request.user.is_superuser
|
||||
|
||||
|
||||
class CanCreateDomain(permissions.BasePermission):
|
||||
"""Permissions class to allow users with add_domain right."""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return request.user.has_perm("admin.add_domain")
|
||||
|
||||
@@ -4,7 +4,7 @@ from drf_spectacular.utils import extend_schema, OpenApiParameter
|
||||
from rest_framework import permissions, response, viewsets
|
||||
from rest_framework.decorators import action
|
||||
|
||||
from modoboa.lib.permissions import IsSuperUser
|
||||
from modoboa.lib.permissions import CanCreateDomain, IsSuperUser
|
||||
from modoboa.lib.throttle import GetThrottleViewsetMixin
|
||||
|
||||
from . import serializers
|
||||
@@ -90,7 +90,11 @@ class GlobalParametersViewSet(BaseParametersViewSet):
|
||||
"""Parameter viewset, global level."""
|
||||
|
||||
level = "global"
|
||||
permission_classes = [permissions.IsAuthenticated, IsSuperUser]
|
||||
|
||||
def get_permissions(self):
|
||||
if self.action == "retrieve":
|
||||
return [permissions.IsAuthenticated(), CanCreateDomain()]
|
||||
return [permissions.IsAuthenticated(), IsSuperUser()]
|
||||
|
||||
def _get_parameter_values(self, request, app: str) -> dict:
|
||||
return request.localconfig.parameters.get_values_dict(app)
|
||||
|
||||
Reference in New Issue
Block a user