From af044bd325c922843e8a867d487a69e2fc7cdf18 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 7 Apr 2022 12:00:44 +0200 Subject: [PATCH] Manage domain and account resources. --- .../src/components/domains/DomainForm.vue | 45 +++++++++++++++++-- .../src/components/identities/AccountForm.vue | 19 +++++--- .../Resources.vue} | 4 +- .../src/components/tools/ResourcesForm.vue | 37 +++++++++++++++ frontend/src/views/domains/Domain.vue | 9 ++++ frontend/src/views/identities/Account.vue | 19 +++++--- modoboa/admin/api/v2/serializers.py | 23 ++++++++-- 7 files changed, 134 insertions(+), 22 deletions(-) rename frontend/src/components/{identities/AccountResources.vue => tools/Resources.vue} (91%) create mode 100644 frontend/src/components/tools/ResourcesForm.vue diff --git a/frontend/src/components/domains/DomainForm.vue b/frontend/src/components/domains/DomainForm.vue index 35eb84811..ad52fb1e1 100644 --- a/frontend/src/components/domains/DomainForm.vue +++ b/frontend/src/components/domains/DomainForm.vue @@ -133,6 +133,18 @@ + + + + + Resources + + + + + + +
@@ -151,18 +163,28 @@ import DomainDNSForm from './DomainDNSForm' import DomainGeneralForm from './DomainGeneralForm' import DomainLimitationsForm from './DomainLimitationsForm' import DomainTransportForm from './DomainTransportForm' +import { mapGetters } from 'vuex' +import parameters from '@/api/parameters' +import ResourcesForm from '@/components/tools/ResourcesForm' export default { components: { 'domain-dns-form': DomainDNSForm, DomainGeneralForm, DomainLimitationsForm, - DomainTransportForm + DomainTransportForm, + ResourcesForm }, props: ['domain'], + computed: { + ...mapGetters({ + authUser: 'auth/authUser' + }) + }, data () { return { editedDomain: {}, + limitsConfig: {}, panel: 0 } }, @@ -174,14 +196,29 @@ export default { return } } - if (this.editedDomain.type === 'relaydomain') { - this.$refs.transportForm.checkSettingTypes(this.editedDomain) + if (this.$refs.resourcesForm !== undefined) { + const valid = await this.$refs.resourcesForm.validateForm() + if (!valid) { + return + } } - this.$store.dispatch('domains/updateDomain', this.editedDomain).then(resp => { + const data = { ...this.editedDomain } + if (data.transport === null) { + delete data.transport + } + if (data.type === 'relaydomain') { + this.$refs.transportForm.checkSettingTypes(data) + } + this.$store.dispatch('domains/updateDomain', data).then(resp => { bus.$emit('notification', { msg: this.$gettext('Domain updated') }) }) } }, + created () { + parameters.getApplication('limits').then(resp => { + this.limitsConfig = resp.data + }) + }, watch: { domain: { handler: function (val) { diff --git a/frontend/src/components/identities/AccountForm.vue b/frontend/src/components/identities/AccountForm.vue index 96954c1dc..a08cd36ad 100644 --- a/frontend/src/components/identities/AccountForm.vue +++ b/frontend/src/components/identities/AccountForm.vue @@ -98,16 +98,16 @@ - + - Limits + Resources - + @@ -128,15 +128,16 @@ import { bus } from '@/main' import accounts from '@/api/accounts' import AccountGeneralForm from './AccountGeneralForm' import AccountMailboxForm from './AccountMailboxForm' -import AccountResourcesForm from './AccountResourcesForm' import AccountRoleForm from './AccountRoleForm' +import ResourcesForm from '@/components/tools/ResourcesForm' +import parameters from '@/api/parameters' export default { components: { AccountGeneralForm, AccountMailboxForm, - AccountResourcesForm, - AccountRoleForm + AccountRoleForm, + ResourcesForm }, props: ['account'], computed: { @@ -147,6 +148,7 @@ export default { data () { return { editedAccount: {}, + limitsConfig: {}, panel: 0 } }, @@ -197,6 +199,11 @@ export default { } } }, + created () { + parameters.getApplication('limits').then(resp => { + this.limitsConfig = resp.data + }) + }, mounted () { this.$store.dispatch('identities/fetchDomains') }, diff --git a/frontend/src/components/identities/AccountResources.vue b/frontend/src/components/tools/Resources.vue similarity index 91% rename from frontend/src/components/identities/AccountResources.vue rename to frontend/src/components/tools/Resources.vue index e069e7eee..6bdae983c 100644 --- a/frontend/src/components/identities/AccountResources.vue +++ b/frontend/src/components/tools/Resources.vue @@ -5,7 +5,7 @@
@@ -22,7 +22,7 @@ diff --git a/frontend/src/views/domains/Domain.vue b/frontend/src/views/domains/Domain.vue index 64328e8eb..840ced72f 100644 --- a/frontend/src/views/domains/Domain.vue +++ b/frontend/src/views/domains/Domain.vue @@ -17,6 +17,8 @@ +
+ @@ -45,6 +47,8 @@ import AdministratorList from '@/components/domains/AdministratorList' import DNSDetail from '@/components/domains/DNSDetail' import DomainForm from '@/components/domains/DomainForm' import DomainSummary from '@/components/domains/DomainSummary' +import parameters from '@/api/parameters' +import Resources from '@/components/tools/Resources' import TimeSerieChart from '@/components/tools/TimeSerieChart' export default { @@ -53,11 +57,13 @@ export default { 'dns-detail': DNSDetail, DomainForm, DomainSummary, + Resources, TimeSerieChart }, data () { return { domain: { pk: this.$route.params.id }, + limitsConfig: {}, showEditForm: false, showAdminList: false } @@ -65,6 +71,9 @@ export default { methods: { }, mounted () { + parameters.getApplication('limits').then(resp => { + this.limitsConfig = resp.data + }) domains.getDomain(this.$route.params.id).then(resp => { this.domain = resp.data }) diff --git a/frontend/src/views/identities/Account.vue b/frontend/src/views/identities/Account.vue index db2a2af5c..504d12156 100644 --- a/frontend/src/views/identities/Account.vue +++ b/frontend/src/views/identities/Account.vue @@ -11,9 +11,9 @@ - @@ -29,26 +29,31 @@ diff --git a/modoboa/admin/api/v2/serializers.py b/modoboa/admin/api/v2/serializers.py index 51206f353..82bac0c26 100644 --- a/modoboa/admin/api/v2/serializers.py +++ b/modoboa/admin/api/v2/serializers.py @@ -35,15 +35,24 @@ class CreateDomainAdminSerializer(serializers.Serializer): with_aliases = serializers.BooleanField(default=False) +class DomainResourceSerializer(serializers.ModelSerializer): + """Serializer for domain resource.""" + + class Meta: + fields = ("name", "label", "max_value", "current_value", "usage") + model = limits_models.DomainObjectLimit + + class DomainSerializer(v1_serializers.DomainSerializer): """Domain serializer for v2 API.""" domain_admin = CreateDomainAdminSerializer(required=False, write_only=True) + resources = DomainResourceSerializer(many=True, source="domainobjectlimit_set") transport = transport_serializers.TransportSerializer(required=False) class Meta(v1_serializers.DomainSerializer.Meta): fields = v1_serializers.DomainSerializer.Meta.fields + ( - "domain_admin", "transport" + "domain_admin", "resources", "transport" ) def validate(self, data): @@ -122,6 +131,7 @@ class DomainSerializer(v1_serializers.DomainSerializer): def update(self, instance, validated_data): """Update domain and create/update transport.""" transport_def = validated_data.pop("transport", None) + resources = validated_data.pop("domainobjectlimit_set", None) super().update(instance, validated_data) if transport_def and instance.type == "relaydomain": transport = getattr(instance, "transport", None) @@ -138,6 +148,11 @@ class DomainSerializer(v1_serializers.DomainSerializer): if created: instance.transport = transport instance.save() + if resources: + for resource in resources: + instance.domainobjectlimit_set.filter( + name=resource["name"] + ).update(max_value=resource["max_value"]) return instance @@ -253,7 +268,7 @@ class IdentitySerializer(serializers.Serializer): tags = TagSerializer(many=True) -class ResourceSerializer(serializers.ModelSerializer): +class AccountResourceSerializer(serializers.ModelSerializer): """Serializer for user resource.""" class Meta: @@ -277,6 +292,8 @@ class AccountSerializer(v1_serializers.AccountSerializer): ) def get_resources(self, account): + if account.role == 'SimpleUsers': + return [] resources = [] for limit in account.userobjectlimit_set.all(): tpl = limits_constants.DEFAULT_USER_LIMITS[limit.name] @@ -284,7 +301,7 @@ class AccountSerializer(v1_serializers.AccountSerializer): if account.role != tpl["required_role"]: continue resources.append(limit) - return ResourceSerializer(resources, many=True).data + return AccountResourceSerializer(resources, many=True).data class MailboxSerializer(serializers.ModelSerializer):