@@ -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..db039c3dc 100644
--- a/modoboa/admin/api/v2/serializers.py
+++ b/modoboa/admin/api/v2/serializers.py
@@ -35,6 +35,14 @@ 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."""
@@ -46,6 +54,14 @@ class DomainSerializer(v1_serializers.DomainSerializer):
"domain_admin", "transport"
)
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ if not param_tools.get_global_parameter("enable_domain_limits", app="limits"):
+ return
+ self.fields["resources"] = DomainResourceSerializer(
+ many=True, source="domainobjectlimit_set", required=False
+ )
+
def validate(self, data):
result = super().validate(data)
dtype = data.get("type", "domain")
@@ -122,6 +138,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 +155,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 +275,7 @@ class IdentitySerializer(serializers.Serializer):
tags = TagSerializer(many=True)
-class ResourceSerializer(serializers.ModelSerializer):
+class AccountResourceSerializer(serializers.ModelSerializer):
"""Serializer for user resource."""
class Meta:
@@ -268,15 +290,22 @@ class AccountSerializer(v1_serializers.AccountSerializer):
child=lib_fields.DRFEmailFieldUTF8(),
source="mailbox.alias_addresses"
)
- resources = serializers.SerializerMethodField()
class Meta(v1_serializers.AccountSerializer.Meta):
fields = (
v1_serializers.AccountSerializer.Meta.fields
- + ("aliases", "resources", )
+ + ("aliases", )
)
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ if not param_tools.get_global_parameter("enable_admin_limits", app="limits"):
+ return
+ self.fields["resources"] = serializers.SerializerMethodField()
+
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 +313,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):
@@ -329,14 +358,19 @@ class WritableAccountSerializer(v1_serializers.WritableAccountSerializer):
required=False
)
mailbox = MailboxSerializer(required=False)
- resources = WritableResourceSerializer(many=True, required=False)
class Meta(v1_serializers.WritableAccountSerializer.Meta):
fields = tuple(
field
for field in v1_serializers.WritableAccountSerializer.Meta.fields
if field != "random_password"
- ) + ("aliases", "resources")
+ ) + ("aliases",)
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ if not param_tools.get_global_parameter("enable_admin_limits", app="limits"):
+ return
+ self.fields["resources"] = WritableResourceSerializer(many=True, required=False)
def validate_aliases(self, value):
"""Check if required domains are locals and user can access them."""
diff --git a/modoboa/admin/api/v2/tests.py b/modoboa/admin/api/v2/tests.py
index 14b46a2b2..344f5f723 100644
--- a/modoboa/admin/api/v2/tests.py
+++ b/modoboa/admin/api/v2/tests.py
@@ -68,6 +68,22 @@ class DomainViewSetTestCase(ModoAPITestCase):
resp = self.client.put(url, data, format="json")
self.assertEqual(resp.status_code, 200)
+ def test_update_resources(self):
+ self.set_global_parameter("enable_domain_limits", True, app="limits")
+ domain = models.Domain.objects.get(name="test2.com")
+ data = {
+ "name": "test2.com",
+ "resources": [
+ {"name": "domain_aliases", "max_value": 20}
+ ]
+ }
+ url = reverse("v2:domain-detail", args=[domain.pk])
+ resp = self.client.put(url, data, format="json")
+ self.assertEqual(resp.status_code, 200)
+ self.assertEqual(
+ domain.domainobjectlimit_set.get(name="domain_aliases").max_value, 20
+ )
+
def test_delete(self):
self.client.credentials(
HTTP_AUTHORIZATION="Token " + self.da_token.key)