kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Can now add domains via manage API / UI
rodzic
b69d9f221b
commit
ddffbeadfa
|
@ -1,6 +1,7 @@
|
||||||
import mimetypes
|
import mimetypes
|
||||||
from os.path import splitext
|
from os.path import splitext
|
||||||
|
|
||||||
|
from django.core import validators
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.files.images import get_image_dimensions
|
from django.core.files.images import get_image_dimensions
|
||||||
from django.template.defaultfilters import filesizeformat
|
from django.template.defaultfilters import filesizeformat
|
||||||
|
@ -150,3 +151,17 @@ class FileValidator(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
raise ValidationError(message)
|
raise ValidationError(message)
|
||||||
|
|
||||||
|
|
||||||
|
class DomainValidator(validators.URLValidator):
|
||||||
|
message = "Enter a valid domain name."
|
||||||
|
|
||||||
|
def __call__(self, value):
|
||||||
|
"""
|
||||||
|
This is a bit hackish but since we don't have any built-in domain validator,
|
||||||
|
we use the url one, and prepend http:// in front of it.
|
||||||
|
|
||||||
|
If it fails, we know the domain is not valid.
|
||||||
|
"""
|
||||||
|
super().__call__("http://{}".format(value))
|
||||||
|
return value
|
||||||
|
|
|
@ -13,6 +13,7 @@ from django.urls import reverse
|
||||||
|
|
||||||
from funkwhale_api.common import session
|
from funkwhale_api.common import session
|
||||||
from funkwhale_api.common import utils as common_utils
|
from funkwhale_api.common import utils as common_utils
|
||||||
|
from funkwhale_api.common import validators as common_validators
|
||||||
from funkwhale_api.music import utils as music_utils
|
from funkwhale_api.music import utils as music_utils
|
||||||
|
|
||||||
from . import utils as federation_utils
|
from . import utils as federation_utils
|
||||||
|
@ -83,7 +84,11 @@ class DomainQuerySet(models.QuerySet):
|
||||||
|
|
||||||
|
|
||||||
class Domain(models.Model):
|
class Domain(models.Model):
|
||||||
name = models.CharField(primary_key=True, max_length=255)
|
name = models.CharField(
|
||||||
|
primary_key=True,
|
||||||
|
max_length=255,
|
||||||
|
validators=[common_validators.DomainValidator()],
|
||||||
|
)
|
||||||
creation_date = models.DateTimeField(default=timezone.now)
|
creation_date = models.DateTimeField(default=timezone.now)
|
||||||
nodeinfo_fetch_date = models.DateTimeField(default=None, null=True, blank=True)
|
nodeinfo_fetch_date = models.DateTimeField(default=None, null=True, blank=True)
|
||||||
nodeinfo = JSONField(default=empty_dict, max_length=50000, blank=True)
|
nodeinfo = JSONField(default=empty_dict, max_length=50000, blank=True)
|
||||||
|
|
|
@ -98,7 +98,10 @@ class ManageInvitationViewSet(
|
||||||
|
|
||||||
|
|
||||||
class ManageDomainViewSet(
|
class ManageDomainViewSet(
|
||||||
mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
|
mixins.CreateModelMixin,
|
||||||
|
mixins.ListModelMixin,
|
||||||
|
mixins.RetrieveModelMixin,
|
||||||
|
viewsets.GenericViewSet,
|
||||||
):
|
):
|
||||||
lookup_value_regex = r"[a-zA-Z0-9\-\.]+"
|
lookup_value_regex = r"[a-zA-Z0-9\-\.]+"
|
||||||
queryset = (
|
queryset = (
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
from funkwhale_api.manage import serializers
|
from funkwhale_api.manage import serializers
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,6 +55,13 @@ def test_manage_domain_serializer(factories, now):
|
||||||
assert s.data == expected
|
assert s.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_manage_domain_serializer_validates_hostname(db):
|
||||||
|
s = serializers.ManageDomainSerializer(data={"name": "hello world"})
|
||||||
|
|
||||||
|
with pytest.raises(serializers.serializers.ValidationError):
|
||||||
|
s.is_valid(raise_exception=True)
|
||||||
|
|
||||||
|
|
||||||
def test_manage_actor_serializer(factories, now):
|
def test_manage_actor_serializer(factories, now):
|
||||||
actor = factories["federation.Actor"]()
|
actor = factories["federation.Actor"]()
|
||||||
setattr(actor, "uploads_count", 66)
|
setattr(actor, "uploads_count", 66)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from funkwhale_api.federation import models as federation_models
|
||||||
from funkwhale_api.federation import tasks as federation_tasks
|
from funkwhale_api.federation import tasks as federation_tasks
|
||||||
from funkwhale_api.manage import serializers, views
|
from funkwhale_api.manage import serializers, views
|
||||||
|
|
||||||
|
@ -90,6 +91,14 @@ def test_domain_detail(factories, superuser_api_client):
|
||||||
assert response.data["name"] == d.pk
|
assert response.data["name"] == d.pk
|
||||||
|
|
||||||
|
|
||||||
|
def test_domain_create(superuser_api_client):
|
||||||
|
url = reverse("api:v1:manage:federation:domains-list")
|
||||||
|
response = superuser_api_client.post(url, {"name": "test.federation"})
|
||||||
|
|
||||||
|
assert response.status_code == 201
|
||||||
|
assert federation_models.Domain.objects.filter(pk="test.federation").exists()
|
||||||
|
|
||||||
|
|
||||||
def test_domain_nodeinfo(factories, superuser_api_client, mocker):
|
def test_domain_nodeinfo(factories, superuser_api_client, mocker):
|
||||||
domain = factories["federation.Domain"]()
|
domain = factories["federation.Domain"]()
|
||||||
url = reverse(
|
url = reverse(
|
||||||
|
|
|
@ -1,26 +1,70 @@
|
||||||
<template>
|
<template>
|
||||||
<main v-title="labels.domains">
|
<main v-title="labels.domains">
|
||||||
<section class="ui vertical stripe segment">
|
<section class="ui vertical stripe segment">
|
||||||
<h2 class="ui header"><translate>Domains</translate></h2>
|
<h2 class="ui left floated header"><translate>Domains</translate></h2>
|
||||||
<div class="ui hidden divider"></div>
|
<form class="ui right floated form" @submit.prevent="createDomain">
|
||||||
|
<div v-if="errors && errors.length > 0" class="ui negative message">
|
||||||
|
<div class="header"><translate>Error while creating domain</translate></div>
|
||||||
|
<ul class="list">
|
||||||
|
<li v-for="error in errors">{{ error }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="inline fields">
|
||||||
|
<div class="field">
|
||||||
|
<label for="domain"><translate>Add a domain</translate></label>
|
||||||
|
<input type="text" id="domain" v-model="domainName">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<button :class="['ui', {'loading': isCreating}, 'green', 'button']" type="submit" :disabled="isCreating">
|
||||||
|
<label for="domain"><translate>Add</translate></label>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="ui clearing hidden divider"></div>
|
||||||
<domains-table></domains-table>
|
<domains-table></domains-table>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DomainsTable from "@/components/manage/moderation/DomainsTable"
|
import axios from 'axios'
|
||||||
|
|
||||||
|
import DomainsTable from "@/components/manage/moderation/DomainsTable"
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DomainsTable
|
DomainsTable
|
||||||
},
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
domainName: '',
|
||||||
|
isCreating: false,
|
||||||
|
errors: []
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
labels() {
|
labels() {
|
||||||
return {
|
return {
|
||||||
domains: this.$gettext("Domains")
|
domains: this.$gettext("Domains")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
createDomain () {
|
||||||
|
let self = this
|
||||||
|
this.isCreating = true
|
||||||
|
this.errors = []
|
||||||
|
axios.post('manage/federation/domains/', {name: this.domainName}).then((response) => {
|
||||||
|
this.isCreating = false
|
||||||
|
this.$router.push({
|
||||||
|
name: "manage.moderation.domains.detail",
|
||||||
|
params: {'id': response.data.name}
|
||||||
|
})
|
||||||
|
}, (error) => {
|
||||||
|
self.isCreating = false
|
||||||
|
self.errors = error.backendErrors
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Ładowanie…
Reference in New Issue