Can now scan and follow library from front-end
This commit is contained in:
parent
fe7ca088c5
commit
f4f75dcb4f
|
@ -159,6 +159,7 @@ class APILibrarySerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class APILibraryCreateSerializer(serializers.ModelSerializer):
|
class APILibraryCreateSerializer(serializers.ModelSerializer):
|
||||||
actor = serializers.URLField()
|
actor = serializers.URLField()
|
||||||
|
federation_enabled = serializers.BooleanField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Library
|
model = models.Library
|
||||||
|
|
|
@ -31,6 +31,9 @@ class User(AbstractUser):
|
||||||
'dynamic_preferences.change_globalpreferencemodel': {
|
'dynamic_preferences.change_globalpreferencemodel': {
|
||||||
'external_codename': 'settings.change',
|
'external_codename': 'settings.change',
|
||||||
},
|
},
|
||||||
|
'federation.change_library': {
|
||||||
|
'external_codename': 'federation.manage',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
privacy_level = fields.get_privacy_field()
|
privacy_level = fields.get_privacy_field()
|
||||||
|
|
|
@ -45,6 +45,9 @@
|
||||||
<router-link
|
<router-link
|
||||||
v-if="$store.state.auth.authenticated"
|
v-if="$store.state.auth.authenticated"
|
||||||
class="item" :to="{path: '/activity'}"><i class="bell icon"></i> Activity</router-link>
|
class="item" :to="{path: '/activity'}"><i class="bell icon"></i> Activity</router-link>
|
||||||
|
<router-link
|
||||||
|
class="item" v-if="$store.state.auth.availablePermissions['federation.manage']"
|
||||||
|
:to="{path: '/manage/federation'}"><i class="sitemap icon"></i> Federation</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<player></player>
|
<player></player>
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<div class="ui card">
|
||||||
|
<div class="content">
|
||||||
|
<div class="header">
|
||||||
|
{{ libraryData.display_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<span class="right floated" v-if="libraryData.actor.manuallyApprovesFollowers">
|
||||||
|
<i class="lock icon"></i> Followers only
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<i class="music icon"></i>
|
||||||
|
{{ libraryData.library.totalItems }} tracks
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="extra content">
|
||||||
|
<template v-if="libraryData.local.awaiting_approval">
|
||||||
|
<i class="clock icon"></i>
|
||||||
|
Follow request pending approval
|
||||||
|
</template>
|
||||||
|
<template v-else-if="libraryData.local.following">Pending follow request
|
||||||
|
<i class="check icon"></i>
|
||||||
|
Already following this library
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-else-if="!library"
|
||||||
|
@click="follow"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="['ui', 'basic', {loading: isLoading}, 'green', 'button']">
|
||||||
|
<template v-if="libraryData.actor.manuallyApprovesFollowers">
|
||||||
|
Send a follow request
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
Follow
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<router-link
|
||||||
|
v-else
|
||||||
|
class="ui basic button"
|
||||||
|
:to="{name: 'federation.libraries.detail', params: {id: library.uuid }}">
|
||||||
|
Detail
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['libraryData'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isLoading: false,
|
||||||
|
data: null,
|
||||||
|
errors: [],
|
||||||
|
library: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
follow () {
|
||||||
|
let params = {
|
||||||
|
'actor': this.libraryData['actor']['id'],
|
||||||
|
'autoimport': false,
|
||||||
|
'download_files': false,
|
||||||
|
'federation_enabled': true
|
||||||
|
}
|
||||||
|
let self = this
|
||||||
|
self.isLoading = true
|
||||||
|
axios.post('/federation/libraries/', params).then((response) => {
|
||||||
|
self.$emit('follow', {data: self.libraryData, library: response.data})
|
||||||
|
self.library = response.data
|
||||||
|
self.isLoading = false
|
||||||
|
}, error => {
|
||||||
|
self.isLoading = false
|
||||||
|
self.errors = error.backendErrors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,110 @@
|
||||||
|
<template>
|
||||||
|
<form class="ui form" @submit.prevent="fetchInstanceInfo">
|
||||||
|
<h3 class="ui header">Federate with a new instance</h3>
|
||||||
|
<p>Use this form to scan an instance and setup federation.</p>
|
||||||
|
<div v-if="errors.length > 0 || scanErrors.length > 0" class="ui negative message">
|
||||||
|
<div class="header">Error while scanning library</div>
|
||||||
|
<ul class="list">
|
||||||
|
<li v-for="error in errors">{{ error }}</li>
|
||||||
|
<li v-for="error in scanErrors">{{ error }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="ui two fields">
|
||||||
|
<div class="ui field">
|
||||||
|
<label>Library name</label>
|
||||||
|
<input v-model="libraryUsername" type="text" placeholder="library@demo.funkwhale.audio" />
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<label> </label>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
:disabled="isLoading"
|
||||||
|
:class="['ui', 'icon', {loading: isLoading}, 'button']">
|
||||||
|
<i class="search icon"></i>
|
||||||
|
Launch scan
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
import TrackTable from '@/components/audio/track/Table'
|
||||||
|
import RadioButton from '@/components/radios/Button'
|
||||||
|
import Pagination from '@/components/Pagination'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TrackTable,
|
||||||
|
RadioButton,
|
||||||
|
Pagination
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isLoading: false,
|
||||||
|
libraryUsername: 'library@node2.funkwhale.test',
|
||||||
|
result: null,
|
||||||
|
errors: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
follow () {
|
||||||
|
let params = {
|
||||||
|
'actor': this.result['actor']['id'],
|
||||||
|
'autoimport': false,
|
||||||
|
'download_files': false,
|
||||||
|
'federation_enabled': true
|
||||||
|
}
|
||||||
|
let self = this
|
||||||
|
self.isFollowing = false
|
||||||
|
axios.post('/federation/libraries/', params).then((response) => {
|
||||||
|
self.$emit('follow', {data: self.result, library: response.data})
|
||||||
|
self.result = response.data
|
||||||
|
self.isFollowing = false
|
||||||
|
}, error => {
|
||||||
|
self.isFollowing = false
|
||||||
|
self.errors = error.backendErrors
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchInstanceInfo () {
|
||||||
|
let self = this
|
||||||
|
this.isLoading = true
|
||||||
|
self.errors = []
|
||||||
|
self.result = null
|
||||||
|
axios.get('/federation/libraries/scan/', {params: {account: this.libraryUsername}}).then((response) => {
|
||||||
|
self.result = response.data
|
||||||
|
self.result.display_name = self.libraryUsername
|
||||||
|
self.isLoading = false
|
||||||
|
}, error => {
|
||||||
|
self.isLoading = false
|
||||||
|
self.errors = error.backendErrors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
scanErrors () {
|
||||||
|
let errors = []
|
||||||
|
if (!this.result) {
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
let keys = ['webfinger', 'actor', 'library']
|
||||||
|
keys.forEach(k => {
|
||||||
|
if (this.result[k]) {
|
||||||
|
if (this.result[k].errors) {
|
||||||
|
this.result[k].errors.forEach(e => {
|
||||||
|
errors.push(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
result (newValue, oldValue) {
|
||||||
|
this.$emit('scanned', newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -25,6 +25,7 @@ import RequestsList from '@/components/requests/RequestsList'
|
||||||
import PlaylistDetail from '@/views/playlists/Detail'
|
import PlaylistDetail from '@/views/playlists/Detail'
|
||||||
import PlaylistList from '@/views/playlists/List'
|
import PlaylistList from '@/views/playlists/List'
|
||||||
import Favorites from '@/components/favorites/List'
|
import Favorites from '@/components/favorites/List'
|
||||||
|
import Federation from '@/views/federation/Home'
|
||||||
|
|
||||||
Vue.use(Router)
|
Vue.use(Router)
|
||||||
|
|
||||||
|
@ -83,6 +84,10 @@ export default new Router({
|
||||||
defaultPaginateBy: route.query.paginateBy
|
defaultPaginateBy: route.query.paginateBy
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/manage/federation',
|
||||||
|
component: Federation
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/library',
|
path: '/library',
|
||||||
component: Library,
|
component: Library,
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<template>
|
||||||
|
<div class="main pusher" v-title="'Federation'">
|
||||||
|
<div class="ui vertical stripe segment">
|
||||||
|
<h1 class="ui header">Manage federation</h1>
|
||||||
|
<library-form @scanned="updateLibraryData"></library-form>
|
||||||
|
<library-card v-if="libraryData" :library-data="libraryData"></library-card>
|
||||||
|
</div>
|
||||||
|
<div class="ui vertical stripe segment">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import axios from 'axios'
|
||||||
|
import TrackTable from '@/components/audio/track/Table'
|
||||||
|
import RadioButton from '@/components/radios/Button'
|
||||||
|
import Pagination from '@/components/Pagination'
|
||||||
|
import LibraryForm from '@/components/federation/LibraryForm'
|
||||||
|
import LibraryCard from '@/components/federation/LibraryCard'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TrackTable,
|
||||||
|
RadioButton,
|
||||||
|
Pagination,
|
||||||
|
LibraryForm,
|
||||||
|
LibraryCard
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
libraryData: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateLibraryData (data) {
|
||||||
|
this.libraryData = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in New Issue