admin oauth2 client management
This commit is contained in:
parent
73049447cd
commit
04e0c77a46
@ -143,8 +143,6 @@ const API = {
|
|||||||
data = dataFilter(data, fields, ['scope', 'verified'])
|
data = dataFilter(data, fields, ['scope', 'verified'])
|
||||||
if (!data) throw new Error('Missing fields')
|
if (!data) throw new Error('Missing fields')
|
||||||
|
|
||||||
data.verified = (data.verified != null ? 1 : 0)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Models.OAuth2Client.query().patchAndFetchById(id, data)
|
await Models.OAuth2Client.query().patchAndFetchById(id, data)
|
||||||
await Models.OAuth2AuthorizedClient.query().delete().where('client_id', id)
|
await Models.OAuth2AuthorizedClient.query().delete().where('client_id', id)
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
modal(:show='show', @close='close')
|
modal(:show='show', @close='close')
|
||||||
.modal-header
|
.modal-header
|
||||||
h3 Ban user
|
h3 Ban user
|
||||||
.modal-body
|
.modal-body.aligned-form
|
||||||
.message.error(v-if='error') {{ error }}
|
.message.error(v-if='error') {{ error }}
|
||||||
input(type='hidden', name='user_id', :value='id')
|
input(type='hidden', name='user_id', :value='id')
|
||||||
label(for='reason') Reason
|
.cell
|
||||||
input#reason(type='text', name='reason', v-model='reason')
|
label(for='reason') Reason
|
||||||
label(for='expires_at') Expires
|
input#reason(type='text', name='reason', v-model='reason')
|
||||||
input#expires_at(type='date', name='expires_at', v-model='expires_at')
|
.cell
|
||||||
.modal-footer.text-right
|
label(for='expires_at') Expires
|
||||||
|
input#expires_at(type='date', name='expires_at', v-model='expires_at')
|
||||||
|
.modal-footer.text-align
|
||||||
button(@click='submit') Ban
|
button(@click='submit') Ban
|
||||||
button(@click='close') Cancel
|
button(@click='close') Cancel
|
||||||
</template>
|
</template>
|
||||||
|
111
src/script/component/ClientModal.vue
Normal file
111
src/script/component/ClientModal.vue
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
modal(:show='show', @close='close')
|
||||||
|
.modal-header
|
||||||
|
h3(v-if="id > 0") Edit Client
|
||||||
|
h3(v-else) New Client
|
||||||
|
.modal-body.aligned-form
|
||||||
|
.message.error(v-if='error') {{ error }}
|
||||||
|
.cell
|
||||||
|
label(for="title") Title
|
||||||
|
input(type="text" id="title" name="title" v-model="title")
|
||||||
|
.cell
|
||||||
|
label(for="description") Description
|
||||||
|
input(type="text" id="description" name="description" v-model="description")
|
||||||
|
.cell
|
||||||
|
label(for="url") URL
|
||||||
|
input(type="text" id="url" name="url" v-model="url")
|
||||||
|
.cell
|
||||||
|
label(for="scope") Scope
|
||||||
|
input(type="text" id="scope" name="scope" v-model="scope")
|
||||||
|
.cell
|
||||||
|
label(for="redirect_url") Redirect
|
||||||
|
input(type="text" id="redirect_url" name="redirect_url" v-model="redirect_url")
|
||||||
|
.cell
|
||||||
|
label(for="verified") Verified
|
||||||
|
input(type="checkbox" id="verified" name="verified" v-model="verified")
|
||||||
|
.modal-footer.text-align
|
||||||
|
button(@click='submit') Done
|
||||||
|
button(@click='newSecret' v-if="id > 0") New Secret
|
||||||
|
button(@click='close') Cancel
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
import Modal from './Modal.vue'
|
||||||
|
const csrfToken = document.querySelector('meta[name="csrf-token"]').content
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['show', 'id'],
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
error: '',
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
scope: '',
|
||||||
|
url: '',
|
||||||
|
redirect_url: '',
|
||||||
|
verified: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Modal
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close: function () {
|
||||||
|
this.$emit('close')
|
||||||
|
this.error = ''
|
||||||
|
this.title = ''
|
||||||
|
this.description = ''
|
||||||
|
this.scope = ''
|
||||||
|
this.url = ''
|
||||||
|
this.redirect_url = ''
|
||||||
|
this.verified = false
|
||||||
|
},
|
||||||
|
submit: function () {
|
||||||
|
let url = this.id === -1 ? 'new' : 'update'
|
||||||
|
|
||||||
|
this.$http.post('/admin/api/client/' + url, {
|
||||||
|
id: this.id,
|
||||||
|
title: this.title,
|
||||||
|
description: this.description,
|
||||||
|
scope: this.scope,
|
||||||
|
url: this.url,
|
||||||
|
redirect_url: this.redirect_url,
|
||||||
|
verified: this.verified,
|
||||||
|
csrf: csrfToken
|
||||||
|
}).then(data => {
|
||||||
|
this.close()
|
||||||
|
this.$root.$emit('reload_clients')
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
if (err.body && err.body.error) this.error = err.body.error
|
||||||
|
})
|
||||||
|
},
|
||||||
|
newSecret: function () {
|
||||||
|
this.$http.post('/admin/api/client/new_secret/' + this.id).then(data => {
|
||||||
|
alert('New secret generated.')
|
||||||
|
this.$root.$emit('reload_clients')
|
||||||
|
}).catch(err => {
|
||||||
|
this.error = 'Failed to generate new secret.'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
id: function () {
|
||||||
|
if (this.id <= 0) return
|
||||||
|
this.$http.get('/admin/api/client/' + this.id).then(data => {
|
||||||
|
let dr = data.body
|
||||||
|
|
||||||
|
this.title = dr.title
|
||||||
|
this.description = dr.description
|
||||||
|
this.scope = dr.scope
|
||||||
|
this.url = dr.url
|
||||||
|
this.redirect_url = dr.redirect_url
|
||||||
|
this.verified = dr.verified
|
||||||
|
}).catch(err => {
|
||||||
|
alert('Failed to fetch client data')
|
||||||
|
this.close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
85
src/script/component/OAuthClients.vue
Normal file
85
src/script/component/OAuthClients.vue
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
#clientlist
|
||||||
|
button(@click="editing = -1") New Client
|
||||||
|
.pgn
|
||||||
|
span.pagenum Page {{ pagination.page }} of {{ pagination.pages }}
|
||||||
|
.button(v-if='pagination.page > 1', v-on:click='getClients(pagination.page - 1)') Previous
|
||||||
|
.button(v-for='n in pagination.pages', v-on:click='getClients(n)', v-bind:class='{active: n == pagination.page}') {{ n }}
|
||||||
|
.button(v-if='pagination.page < pagination.pages', v-on:click='getClients(pagination.page + 1)') Next
|
||||||
|
.list.client
|
||||||
|
.message.error(v-if="error") {{ error }}
|
||||||
|
.application.list-item(v-else v-for="client in clients")
|
||||||
|
.picture
|
||||||
|
img(v-if="client.icon" :src="'/usercontent/images/' + client.icon")
|
||||||
|
.noicon(v-else)
|
||||||
|
i.fa.fa-fw.fa-gears
|
||||||
|
.info
|
||||||
|
.stamps
|
||||||
|
.verified(v-if="client.verified")
|
||||||
|
i.fa.fa-fw.fa-check
|
||||||
|
.name {{ client.title }}
|
||||||
|
.description {{ client.description }}
|
||||||
|
a.url(:href='client.url', target='_blank', rel='nofollow') {{ client.url }}
|
||||||
|
.scope Scopes: {{ client.scope }}
|
||||||
|
.redirect_url Redirect: {{ client.redirect_url }}
|
||||||
|
.id Client ID: {{ client.id }}
|
||||||
|
.secret
|
||||||
|
| Client Secret:
|
||||||
|
#showbutton Hover
|
||||||
|
#hiddensecret {{ client.secret }}
|
||||||
|
.button.edit(@click="editing = client.id") Edit
|
||||||
|
.button.delete(@click="deleteClient(client.id)") Delete
|
||||||
|
client-modal(:show="editing != 0" @close='editing = 0', :id='editing')
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
import ClientModal from './ClientModal.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
clients: [],
|
||||||
|
pagination: {
|
||||||
|
offset: 0,
|
||||||
|
page: 1,
|
||||||
|
pages: 1,
|
||||||
|
perPage: 6,
|
||||||
|
total: 0
|
||||||
|
},
|
||||||
|
editing: 0,
|
||||||
|
error: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ClientModal
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getClients: function (page) {
|
||||||
|
this.pagination.total = 0
|
||||||
|
this.error = ''
|
||||||
|
|
||||||
|
this.$http.get('/admin/api/clients?page=' + page).then(data => {
|
||||||
|
if (data.body && data.body.error) {
|
||||||
|
this.error = data.body.error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pagination = data.body.page
|
||||||
|
this.clients = data.body.clients
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteClient: function (id) {
|
||||||
|
this.$http.post('/admin/api/client/delete/' + id).then(data => {
|
||||||
|
this.getClients(1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
this.getClients(1)
|
||||||
|
|
||||||
|
this.$root.$on('reload_clients', () => {
|
||||||
|
this.getClients(1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,8 +1,20 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.root
|
.root
|
||||||
h1 Manage OAuth2 Clients
|
h1 Manage OAuth2 Clients
|
||||||
|
o-auth-clients
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
export default {}
|
import OAuthClients from '../component/OAuthClients.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
newClient: function () {
|
||||||
|
alert('not yet')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
OAuthClients
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
import UserList from '../component/UserList.vue'
|
import UserList from '../component/UserList.vue'
|
||||||
import BanList from '../component/BanList.vue'
|
import BanList from '../component/BanList.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
UserList, BanList
|
UserList, BanList
|
||||||
|
@ -71,11 +71,22 @@ nav
|
|||||||
background-color: #fff
|
background-color: #fff
|
||||||
|
|
||||||
.application
|
.application
|
||||||
height: 200px
|
min-height: 200px
|
||||||
|
|
||||||
#hiddensecret
|
#hiddensecret
|
||||||
display: none
|
display: none
|
||||||
&.shown
|
color: #ff796f
|
||||||
display: inline-block
|
background-color: #f1f1f1
|
||||||
|
padding: 5px
|
||||||
|
min-width: 250px
|
||||||
|
|
||||||
|
#showbutton
|
||||||
|
font-style: italic
|
||||||
|
display: inline-block
|
||||||
|
cursor: pointer
|
||||||
|
&:hover > #hiddensecret
|
||||||
|
display: block
|
||||||
|
|
||||||
.link
|
.link
|
||||||
color: green
|
color: green
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
@ -97,7 +108,7 @@ nav
|
|||||||
vertical-align: middle
|
vertical-align: middle
|
||||||
|
|
||||||
.modal-container
|
.modal-container
|
||||||
width: 300px
|
width: 360px
|
||||||
margin: 0px auto
|
margin: 0px auto
|
||||||
padding: 20px 30px
|
padding: 20px 30px
|
||||||
background-color: #fff
|
background-color: #fff
|
||||||
@ -113,8 +124,15 @@ nav
|
|||||||
.modal-body
|
.modal-body
|
||||||
margin: 20px 0
|
margin: 20px 0
|
||||||
|
|
||||||
.modal-default-button
|
.modal-footer
|
||||||
float: right
|
min-height: 50px
|
||||||
|
|
||||||
|
button
|
||||||
|
margin: 5px
|
||||||
|
display: inline-block
|
||||||
|
|
||||||
|
&.text-align
|
||||||
|
text-align: center
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following styles are auto-applied to elements with
|
* The following styles are auto-applied to elements with
|
||||||
@ -125,6 +143,16 @@ nav
|
|||||||
* these styles.
|
* these styles.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.fade-enter-active, .fade-leave-active
|
||||||
|
transition-property: opacity
|
||||||
|
transition-duration: .25s
|
||||||
|
|
||||||
|
.fade-enter-active
|
||||||
|
transition-delay: .25s
|
||||||
|
|
||||||
|
.fade-enter, .fade-leave-active
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
.modal-enter
|
.modal-enter
|
||||||
opacity: 0
|
opacity: 0
|
||||||
|
|
||||||
@ -135,9 +163,6 @@ nav
|
|||||||
-webkit-transform: scale(1.1)
|
-webkit-transform: scale(1.1)
|
||||||
transform: scale(1.1)
|
transform: scale(1.1)
|
||||||
|
|
||||||
.modal-footer
|
|
||||||
min-height: 50px
|
|
||||||
|
|
||||||
form
|
form
|
||||||
.message
|
.message
|
||||||
display: none
|
display: none
|
||||||
|
@ -211,6 +211,7 @@ button, .button, input[type="submit"]
|
|||||||
|
|
||||||
.button
|
.button
|
||||||
display: inline-block
|
display: inline-block
|
||||||
|
margin-right: 5px
|
||||||
|
|
||||||
.boxcont
|
.boxcont
|
||||||
.box
|
.box
|
||||||
@ -568,6 +569,17 @@ select
|
|||||||
margin-left: 5px
|
margin-left: 5px
|
||||||
border-radius: 5px
|
border-radius: 5px
|
||||||
|
|
||||||
|
.aligned-form
|
||||||
|
.cell
|
||||||
|
margin-top: 10px
|
||||||
|
label
|
||||||
|
width: 120px
|
||||||
|
float: left
|
||||||
|
margin: 0
|
||||||
|
padding: 8px 0
|
||||||
|
input[type="checkbox"]
|
||||||
|
margin-top: 10px
|
||||||
|
|
||||||
@media all and (max-width: 800px)
|
@media all and (max-width: 800px)
|
||||||
.navigator
|
.navigator
|
||||||
padding: 0 10px
|
padding: 0 10px
|
||||||
|
@ -3,8 +3,6 @@ extends layout.pug
|
|||||||
block body
|
block body
|
||||||
.container
|
.container
|
||||||
.content
|
.content
|
||||||
router-view
|
transition(name="fade")
|
||||||
|
router-view
|
||||||
.templates
|
|
||||||
script(type="text/x-template" id="ban-modal-template").
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user