Merge branch 'develop' into feature/add-polls
This commit is contained in:
commit
20766b8522
34 changed files with 774 additions and 73 deletions
|
@ -24,12 +24,14 @@
|
|||
"node-sass": "^3.10.1",
|
||||
"object-path": "^0.11.3",
|
||||
"phoenix": "^1.3.0",
|
||||
"popper.js": "^1.14.7",
|
||||
"sanitize-html": "^1.13.0",
|
||||
"sass-loader": "^4.0.2",
|
||||
"vue": "^2.5.13",
|
||||
"vue-chat-scroll": "^1.2.1",
|
||||
"vue-compose": "^0.7.1",
|
||||
"vue-i18n": "^7.3.2",
|
||||
"vue-popperjs": "^2.0.3",
|
||||
"vue-router": "^3.0.1",
|
||||
"vue-template-compiler": "^2.3.4",
|
||||
"vue-timeago": "^3.1.2",
|
||||
|
|
|
@ -101,6 +101,14 @@ button {
|
|||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg)
|
||||
}
|
||||
|
||||
&.danger {
|
||||
// TODO: add better color variable
|
||||
color: $fallback--text;
|
||||
color: var(--alertErrorPanelText, $fallback--text);
|
||||
background-color: $fallback--alertError;
|
||||
background-color: var(--alertError, $fallback--alertError);
|
||||
}
|
||||
}
|
||||
|
||||
label.select {
|
||||
|
|
|
@ -9,12 +9,13 @@ const getStatusnetConfig = async ({ store }) => {
|
|||
const res = await window.fetch('/api/statusnet/config.json')
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
const { name, closed: registrationClosed, textlimit, uploadlimit, server, vapidPublicKey } = data.site
|
||||
const { name, closed: registrationClosed, textlimit, uploadlimit, server, vapidPublicKey, safeDMMentionsEnabled } = data.site
|
||||
|
||||
store.dispatch('setInstanceOption', { name: 'name', value: name })
|
||||
store.dispatch('setInstanceOption', { name: 'registrationOpen', value: (registrationClosed === '0') })
|
||||
store.dispatch('setInstanceOption', { name: 'textlimit', value: parseInt(textlimit) })
|
||||
store.dispatch('setInstanceOption', { name: 'server', value: server })
|
||||
store.dispatch('setInstanceOption', { name: 'safeDM', value: safeDMMentionsEnabled !== '0' })
|
||||
|
||||
// TODO: default values for this stuff, added if to not make it break on
|
||||
// my dev config out of the box.
|
||||
|
@ -210,6 +211,7 @@ const getNodeInfo = async ({ store }) => {
|
|||
|
||||
const frontendVersion = window.___pleromafe_commit_hash
|
||||
store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion })
|
||||
store.dispatch('setInstanceOption', { name: 'tagPolicyAvailable', value: metadata.federation.mrf_policies.includes('TagPolicy') })
|
||||
} else {
|
||||
throw (res)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
:key="status.id"
|
||||
:inlineExpanded="collapsable"
|
||||
:statusoid="status"
|
||||
:expandable='!expanded'
|
||||
:expandable='!isExpanded'
|
||||
:focused="focused(status.id)"
|
||||
:inConversation="isExpanded"
|
||||
:highlight="getHighlight()"
|
||||
|
|
|
@ -10,7 +10,11 @@ const DeleteButton = {
|
|||
},
|
||||
computed: {
|
||||
currentUser () { return this.$store.state.users.currentUser },
|
||||
canDelete () { return this.currentUser && this.currentUser.rights.delete_others_notice || this.status.user.id === this.currentUser.id }
|
||||
canDelete () {
|
||||
if (!this.currentUser) { return }
|
||||
const superuser = this.currentUser.rights.moderator || this.currentUser.rights.admin
|
||||
return superuser || this.status.user.id === this.currentUser.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
14
src/components/dialog_modal/dialog_modal.js
Normal file
14
src/components/dialog_modal/dialog_modal.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
const DialogModal = {
|
||||
props: {
|
||||
darkOverlay: {
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
onCancel: {
|
||||
default: () => {},
|
||||
type: Function
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DialogModal
|
92
src/components/dialog_modal/dialog_modal.vue
Normal file
92
src/components/dialog_modal/dialog_modal.vue
Normal file
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<span v-bind:class="{ 'dark-overlay': darkOverlay }" @click.self.stop='onCancel()'>
|
||||
<div class="dialog-modal panel panel-default" @click.stop=''>
|
||||
<div class="panel-heading dialog-modal-heading">
|
||||
<div class="title">
|
||||
<slot name="header"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-modal-content">
|
||||
<slot name="default"></slot>
|
||||
</div>
|
||||
<div class="dialog-modal-footer user-interactions panel-footer">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script src="./dialog_modal.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
// TODO: unify with other modals.
|
||||
.dark-overlay {
|
||||
&::before {
|
||||
bottom: 0;
|
||||
content: " ";
|
||||
display: block;
|
||||
cursor: default;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background: rgba(27,31,35,.5);
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-modal.panel {
|
||||
top: 0;
|
||||
left: 50%;
|
||||
max-height: 80vh;
|
||||
max-width: 90vw;
|
||||
margin: 15vh auto;
|
||||
position: fixed;
|
||||
transform: translateX(-50%);
|
||||
z-index: 999;
|
||||
cursor: default;
|
||||
display: block;
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg);
|
||||
|
||||
.dialog-modal-heading {
|
||||
padding: .5em .5em;
|
||||
margin-right: auto;
|
||||
margin-bottom: 0;
|
||||
white-space: nowrap;
|
||||
color: var(--panelText);
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--panel, $fallback--fg);
|
||||
|
||||
.title {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-modal-content {
|
||||
margin: 0;
|
||||
padding: 1rem 1rem;
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.dialog-modal-footer {
|
||||
margin: 0;
|
||||
padding: .5em .5em;
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
border-top: 1px solid $fallback--bg;
|
||||
border-top: 1px solid var(--bg, $fallback--bg);
|
||||
justify-content: flex-end;
|
||||
|
||||
button {
|
||||
width: auto;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -31,15 +31,19 @@ const LoginForm = {
|
|||
username: this.user.username,
|
||||
password: this.user.password
|
||||
}
|
||||
).then((result) => {
|
||||
).then(async (result) => {
|
||||
if (result.error) {
|
||||
this.authError = result.error
|
||||
this.user.password = ''
|
||||
return
|
||||
}
|
||||
this.$store.commit('setToken', result.access_token)
|
||||
this.$store.dispatch('loginUser', result.access_token)
|
||||
this.$router.push({name: 'friends'})
|
||||
try {
|
||||
await this.$store.dispatch('loginUser', result.access_token)
|
||||
this.$router.push({name: 'friends'})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
|
106
src/components/moderation_tools/moderation_tools.js
Normal file
106
src/components/moderation_tools/moderation_tools.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
import DialogModal from '../dialog_modal/dialog_modal.vue'
|
||||
import Popper from 'vue-popperjs/src/component/popper.js.vue'
|
||||
|
||||
const FORCE_NSFW = 'mrf_tag:media-force-nsfw'
|
||||
const STRIP_MEDIA = 'mrf_tag:media-strip'
|
||||
const FORCE_UNLISTED = 'mrf_tag:force-unlisted'
|
||||
const DISABLE_REMOTE_SUBSCRIPTION = 'mrf_tag:disable-remote-subscription'
|
||||
const DISABLE_ANY_SUBSCRIPTION = 'mrf_tag:disable-any-subscription'
|
||||
const SANDBOX = 'mrf_tag:sandbox'
|
||||
const QUARANTINE = 'mrf_tag:quarantine'
|
||||
|
||||
const ModerationTools = {
|
||||
props: [
|
||||
'user'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
showDropDown: false,
|
||||
tags: {
|
||||
FORCE_NSFW,
|
||||
STRIP_MEDIA,
|
||||
FORCE_UNLISTED,
|
||||
DISABLE_REMOTE_SUBSCRIPTION,
|
||||
DISABLE_ANY_SUBSCRIPTION,
|
||||
SANDBOX,
|
||||
QUARANTINE
|
||||
},
|
||||
showDeleteUserDialog: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
DialogModal,
|
||||
Popper
|
||||
},
|
||||
computed: {
|
||||
tagsSet () {
|
||||
return new Set(this.user.tags)
|
||||
},
|
||||
hasTagPolicy () {
|
||||
return this.$store.state.instance.tagPolicyAvailable
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleMenu () {
|
||||
this.showDropDown = !this.showDropDown
|
||||
},
|
||||
hasTag (tagName) {
|
||||
return this.tagsSet.has(tagName)
|
||||
},
|
||||
toggleTag (tag) {
|
||||
const store = this.$store
|
||||
if (this.tagsSet.has(tag)) {
|
||||
store.state.api.backendInteractor.untagUser(this.user, tag).then(response => {
|
||||
if (!response.ok) { return }
|
||||
store.commit('untagUser', {user: this.user, tag})
|
||||
})
|
||||
} else {
|
||||
store.state.api.backendInteractor.tagUser(this.user, tag).then(response => {
|
||||
if (!response.ok) { return }
|
||||
store.commit('tagUser', {user: this.user, tag})
|
||||
})
|
||||
}
|
||||
},
|
||||
toggleRight (right) {
|
||||
const store = this.$store
|
||||
if (this.user.rights[right]) {
|
||||
store.state.api.backendInteractor.deleteRight(this.user, right).then(response => {
|
||||
if (!response.ok) { return }
|
||||
store.commit('updateRight', {user: this.user, right: right, value: false})
|
||||
})
|
||||
} else {
|
||||
store.state.api.backendInteractor.addRight(this.user, right).then(response => {
|
||||
if (!response.ok) { return }
|
||||
store.commit('updateRight', {user: this.user, right: right, value: true})
|
||||
})
|
||||
}
|
||||
},
|
||||
toggleActivationStatus () {
|
||||
const store = this.$store
|
||||
const status = !!this.user.deactivated
|
||||
store.state.api.backendInteractor.setActivationStatus(this.user, status).then(response => {
|
||||
if (!response.ok) { return }
|
||||
store.commit('updateActivationStatus', {user: this.user, status: status})
|
||||
})
|
||||
},
|
||||
deleteUserDialog (show) {
|
||||
this.showDeleteUserDialog = show
|
||||
},
|
||||
deleteUser () {
|
||||
const store = this.$store
|
||||
const user = this.user
|
||||
const {id, name} = user
|
||||
store.state.api.backendInteractor.deleteUser(user)
|
||||
.then(e => {
|
||||
this.$store.dispatch('markStatusesAsDeleted', status => user.id === status.user.id)
|
||||
const isProfile = this.$route.name === 'external-user-profile' || this.$route.name === 'user-profile'
|
||||
const isTargetUser = this.$route.params.name === name || this.$route.params.id === id
|
||||
if (isProfile && isTargetUser) {
|
||||
window.history.back()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ModerationTools
|
158
src/components/moderation_tools/moderation_tools.vue
Normal file
158
src/components/moderation_tools/moderation_tools.vue
Normal file
|
@ -0,0 +1,158 @@
|
|||
<template>
|
||||
<div class='block' style='position: relative'>
|
||||
<Popper
|
||||
trigger="click"
|
||||
@hide='showDropDown = false'
|
||||
append-to-body
|
||||
:options="{
|
||||
placement: 'bottom-end',
|
||||
modifiers: {
|
||||
arrow: { enabled: true },
|
||||
offset: { offset: '0, 5px' },
|
||||
}
|
||||
}">
|
||||
<div class="popper-wrapper">
|
||||
<div class="dropdown-menu">
|
||||
<span v-if='user.is_local'>
|
||||
<button class="dropdown-item" @click='toggleRight("admin")'>
|
||||
{{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }}
|
||||
</button>
|
||||
<button class="dropdown-item" @click='toggleRight("moderator")'>
|
||||
{{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }}
|
||||
</button>
|
||||
<div role="separator" class="dropdown-divider"></div>
|
||||
</span>
|
||||
<button class="dropdown-item" @click='toggleActivationStatus()'>
|
||||
{{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }}
|
||||
</button>
|
||||
<button class="dropdown-item" @click='deleteUserDialog(true)'>
|
||||
{{ $t('user_card.admin_menu.delete_account') }}
|
||||
</button>
|
||||
<div role="separator" class="dropdown-divider" v-if='hasTagPolicy'></div>
|
||||
<span v-if='hasTagPolicy'>
|
||||
<button class="dropdown-item" @click='toggleTag(tags.FORCE_NSFW)'>
|
||||
{{ $t('user_card.admin_menu.force_nsfw') }}
|
||||
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }"></span>
|
||||
</button>
|
||||
<button class="dropdown-item" @click='toggleTag(tags.STRIP_MEDIA)'>
|
||||
{{ $t('user_card.admin_menu.strip_media') }}
|
||||
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }"></span>
|
||||
</button>
|
||||
<button class="dropdown-item" @click='toggleTag(tags.FORCE_UNLISTED)'>
|
||||
{{ $t('user_card.admin_menu.force_unlisted') }}
|
||||
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }"></span>
|
||||
</button>
|
||||
<button class="dropdown-item" @click='toggleTag(tags.SANDBOX)'>
|
||||
{{ $t('user_card.admin_menu.sandbox') }}
|
||||
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }"></span>
|
||||
</button>
|
||||
<button class="dropdown-item" v-if='user.is_local' @click='toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)'>
|
||||
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
|
||||
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_REMOTE_SUBSCRIPTION) }"></span>
|
||||
</button>
|
||||
<button class="dropdown-item" v-if='user.is_local' @click='toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)'>
|
||||
{{ $t('user_card.admin_menu.disable_any_subscription') }}
|
||||
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_ANY_SUBSCRIPTION) }"></span>
|
||||
</button>
|
||||
<button class="dropdown-item" v-if='user.is_local' @click='toggleTag(tags.QUARANTINE)'>
|
||||
{{ $t('user_card.admin_menu.quarantine') }}
|
||||
<span class="menu-checkbox" v-bind:class="{ 'menu-checkbox-checked': hasTag(tags.QUARANTINE) }"></span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button slot="reference" v-bind:class="{ pressed: showDropDown }" @click='toggleMenu'>
|
||||
{{ $t('user_card.admin_menu.moderation') }}
|
||||
</button>
|
||||
</Popper>
|
||||
<DialogModal v-if="showDeleteUserDialog" :onCancel='deleteUserDialog.bind(this, false)'>
|
||||
<span slot="header">{{ $t('user_card.admin_menu.delete_user') }}</span>
|
||||
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
|
||||
<span slot="footer">
|
||||
<button @click='deleteUserDialog(false)'>
|
||||
{{ $t('general.cancel') }}
|
||||
</button>
|
||||
<button class="danger" @click='deleteUser()'>
|
||||
{{ $t('user_card.admin_menu.delete_user') }}
|
||||
</button>
|
||||
</span>
|
||||
</DialogModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./moderation_tools.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
@import '../popper/popper.scss';
|
||||
|
||||
.dropdown-menu {
|
||||
display: block;
|
||||
padding: .5rem 0;
|
||||
font-size: 1rem;
|
||||
text-align: left;
|
||||
list-style: none;
|
||||
max-width: 100vw;
|
||||
z-index: 10;
|
||||
box-shadow: 1px 1px 4px rgba(0,0,0,.6);
|
||||
box-shadow: var(--panelShadow);
|
||||
border: none;
|
||||
border-radius: $fallback--btnRadius;
|
||||
border-radius: var(--btnRadius, $fallback--btnRadius);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg);
|
||||
|
||||
.dropdown-divider {
|
||||
height: 0;
|
||||
margin: .5rem 0;
|
||||
overflow: hidden;
|
||||
border-top: 1px solid $fallback--border;
|
||||
border-top: 1px solid var(--border, $fallback--border);
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
line-height: 21px;
|
||||
margin-right: 5px;
|
||||
overflow: auto;
|
||||
display: block;
|
||||
padding: .25rem 1.0rem .25rem 1.5rem;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
text-align: inherit;
|
||||
white-space: normal;
|
||||
border: none;
|
||||
border-radius: 0px;
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&:hover {
|
||||
// TODO: improve the look on breeze themes
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btn, $fallback--fg);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-checkbox {
|
||||
float: right;
|
||||
min-width: 22px;
|
||||
max-width: 22px;
|
||||
min-height: 22px;
|
||||
max-height: 22px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
border-radius: 0px;
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--input, $fallback--fg);
|
||||
box-shadow: 0px 0px 2px black inset;
|
||||
box-shadow: var(--inputShadow);
|
||||
|
||||
&.menu-checkbox-checked::after {
|
||||
content: '✔';
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -21,6 +21,9 @@ const Notification = {
|
|||
},
|
||||
userProfileLink (user) {
|
||||
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
|
||||
},
|
||||
getUser (notification) {
|
||||
return this.$store.state.users.usersObject[notification.action.user.id]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<UserAvatar :compact="true" :betterShadow="betterShadow" :src="notification.action.user.profile_image_url_original"/>
|
||||
</a>
|
||||
<div class='notification-right'>
|
||||
<UserCard :user="user" :rounded="true" :bordered="true" v-if="userExpanded"/>
|
||||
<UserCard :user="getUser(notification)" :rounded="true" :bordered="true" v-if="userExpanded"/>
|
||||
<span class="notification-details">
|
||||
<div class="name-and-action">
|
||||
<span class="username" v-if="!!notification.action.user.name_html" :title="'@'+notification.action.user.screen_name" v-html="notification.action.user.name_html"></span>
|
||||
|
|
|
@ -10,13 +10,6 @@ const Notifications = {
|
|||
props: [
|
||||
'noHeading'
|
||||
],
|
||||
created () {
|
||||
const store = this.$store
|
||||
const credentials = store.state.users.currentUser.credentials
|
||||
|
||||
const fetcherId = notificationsFetcher.startFetching({ store, credentials })
|
||||
this.$store.commit('setNotificationFetcher', { fetcherId })
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
bottomedOut: false
|
||||
|
|
70
src/components/popper/popper.scss
Normal file
70
src/components/popper/popper.scss
Normal file
|
@ -0,0 +1,70 @@
|
|||
@import '../../_variables.scss';
|
||||
|
||||
.popper-wrapper {
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
.popper-wrapper .popper__arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
position: absolute;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.popper-wrapper[x-placement^="top"] {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.popper-wrapper[x-placement^="top"] .popper__arrow {
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-color: $fallback--bg transparent transparent transparent;
|
||||
border-color: var(--bg, $fallback--bg) transparent transparent transparent;
|
||||
bottom: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.popper-wrapper[x-placement^="bottom"] {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.popper-wrapper[x-placement^="bottom"] .popper__arrow {
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-color: transparent transparent $fallback--bg transparent;
|
||||
border-color: transparent transparent var(--bg, $fallback--bg) transparent;
|
||||
top: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.popper-wrapper[x-placement^="right"] {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.popper-wrapper[x-placement^="right"] .popper__arrow {
|
||||
border-width: 5px 5px 5px 0;
|
||||
border-color: transparent $fallback--bg transparent transparent;
|
||||
border-color: transparent var(--bg, $fallback--bg) transparent transparent;
|
||||
left: -5px;
|
||||
top: calc(50% - 5px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.popper-wrapper[x-placement^="left"] {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.popper-wrapper[x-placement^="left"] .popper__arrow {
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-color: transparent transparent transparent $fallback--bg;
|
||||
border-color: transparent transparent transparent var(--bg, $fallback--bg);
|
||||
right: -5px;
|
||||
top: calc(50% - 5px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
|
@ -185,6 +185,9 @@ const PostStatusForm = {
|
|||
},
|
||||
postFormats () {
|
||||
return this.$store.state.instance.postFormats || []
|
||||
},
|
||||
safeDMEnabled () {
|
||||
return this.$store.state.instance.safeDM
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
<form @submit.prevent="postStatus(newStatus)">
|
||||
<div class="form-group" >
|
||||
<i18n
|
||||
v-if="!this.$store.state.users.currentUser.locked && this.newStatus.visibility == 'private'"
|
||||
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private'"
|
||||
path="post_status.account_not_locked_warning"
|
||||
tag="p"
|
||||
class="visibility-notice">
|
||||
<router-link :to="{ name: 'user-settings' }">{{ $t('post_status.account_not_locked_warning_link') }}</router-link>
|
||||
</i18n>
|
||||
<p v-if="this.newStatus.visibility == 'direct'" class="visibility-notice">{{ $t('post_status.direct_warning') }}</p>
|
||||
<p v-if="newStatus.visibility === 'direct'" class="visibility-notice">
|
||||
<span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span>
|
||||
<span v-else>{{ $t('post_status.direct_warning_to_all') }}</span>
|
||||
</p>
|
||||
<EmojiInput
|
||||
v-if="newStatus.spoilerText || alwaysShowSubject"
|
||||
type="text"
|
||||
|
|
|
@ -7,7 +7,7 @@ const PublicAndExternalTimeline = {
|
|||
timeline () { return this.$store.state.statuses.timelines.publicAndExternal }
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('startFetching', { timeline: 'publicAndExternal' })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' })
|
||||
},
|
||||
destroyed () {
|
||||
this.$store.dispatch('stopFetching', 'publicAndExternal')
|
||||
|
|
|
@ -7,7 +7,7 @@ const PublicTimeline = {
|
|||
timeline () { return this.$store.state.statuses.timelines.public }
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('startFetching', { timeline: 'public' })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'public' })
|
||||
},
|
||||
destroyed () {
|
||||
this.$store.dispatch('stopFetching', 'public')
|
||||
|
|
|
@ -3,7 +3,7 @@ import Timeline from '../timeline/timeline.vue'
|
|||
const TagTimeline = {
|
||||
created () {
|
||||
this.$store.commit('clearTimeline', { timeline: 'tag' })
|
||||
this.$store.dispatch('startFetching', { timeline: 'tag', tag: this.tag })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'tag', tag: this.tag })
|
||||
},
|
||||
components: {
|
||||
Timeline
|
||||
|
@ -15,7 +15,7 @@ const TagTimeline = {
|
|||
watch: {
|
||||
tag () {
|
||||
this.$store.commit('clearTimeline', { timeline: 'tag' })
|
||||
this.$store.dispatch('startFetching', { timeline: 'tag', tag: this.tag })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'tag', tag: this.tag })
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
|
|
|
@ -52,7 +52,7 @@ const Timeline = {
|
|||
|
||||
window.addEventListener('scroll', this.scrollLoad)
|
||||
|
||||
if (this.timelineName === 'friends' && !credentials) { return false }
|
||||
if (store.state.api.fetchers[this.timelineName]) { return false }
|
||||
|
||||
timelineFetcher.fetchAndUpdate({
|
||||
store,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import RemoteFollow from '../remote_follow/remote_follow.vue'
|
||||
import ModerationTools from '../moderation_tools/moderation_tools.vue'
|
||||
import { hex2rgb } from '../../services/color_convert/color_convert.js'
|
||||
import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
@ -93,15 +94,17 @@ export default {
|
|||
}
|
||||
},
|
||||
visibleRole () {
|
||||
const validRole = (this.user.role === 'admin' || this.user.role === 'moderator')
|
||||
const showRole = this.isOtherUser || this.user.show_role
|
||||
|
||||
return validRole && showRole && this.user.role
|
||||
const rights = this.user.rights
|
||||
if (!rights) { return }
|
||||
const validRole = rights.admin || rights.moderator
|
||||
const roleTitle = rights.admin ? 'admin' : 'moderator'
|
||||
return validRole && roleTitle
|
||||
}
|
||||
},
|
||||
components: {
|
||||
UserAvatar,
|
||||
RemoteFollow
|
||||
RemoteFollow,
|
||||
ModerationTools
|
||||
},
|
||||
methods: {
|
||||
followUser () {
|
||||
|
|
|
@ -99,6 +99,8 @@
|
|||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<ModerationTools :user='user' v-if='loggedIn.role === "admin"'>
|
||||
</ModerationTools>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,6 +3,7 @@ import get from 'lodash/get'
|
|||
import UserCard from '../user_card/user_card.vue'
|
||||
import FollowCard from '../follow_card/follow_card.vue'
|
||||
import Timeline from '../timeline/timeline.vue'
|
||||
import ModerationTools from '../moderation_tools/moderation_tools.vue'
|
||||
import withLoadMore from '../../hocs/with_load_more/with_load_more'
|
||||
import withList from '../../hocs/with_list/with_list'
|
||||
|
||||
|
@ -90,7 +91,7 @@ const UserProfile = {
|
|||
methods: {
|
||||
startFetchFavorites () {
|
||||
if (this.isUs) {
|
||||
this.$store.dispatch('startFetching', { timeline: 'favorites', userId: this.userId })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId: this.userId })
|
||||
}
|
||||
},
|
||||
fetchUserId () {
|
||||
|
@ -118,8 +119,8 @@ const UserProfile = {
|
|||
},
|
||||
startUp () {
|
||||
if (this.userId) {
|
||||
this.$store.dispatch('startFetching', { timeline: 'user', userId: this.userId })
|
||||
this.$store.dispatch('startFetching', { timeline: 'media', userId: this.userId })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'user', userId: this.userId })
|
||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'media', userId: this.userId })
|
||||
this.startFetchFavorites()
|
||||
}
|
||||
},
|
||||
|
@ -155,7 +156,8 @@ const UserProfile = {
|
|||
UserCard,
|
||||
Timeline,
|
||||
FollowerList,
|
||||
FriendList
|
||||
FriendList,
|
||||
ModerationTools
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
"generic_error": "An error occured",
|
||||
"optional": "optional",
|
||||
"show_more": "Show more",
|
||||
"show_less": "Show less"
|
||||
"show_less": "Show less",
|
||||
"cancel": "Cancel"
|
||||
},
|
||||
"image_cropper": {
|
||||
"crop_picture": "Crop picture",
|
||||
|
@ -85,7 +86,8 @@
|
|||
},
|
||||
"content_warning": "Subject (optional)",
|
||||
"default": "Just landed in L.A.",
|
||||
"direct_warning": "This post will only be visible to all the mentioned users.",
|
||||
"direct_warning_to_all": "This post will be visible to all the mentioned users.",
|
||||
"direct_warning_to_first_only": "This post will only be visible to the mentioned users at the beginning of the message.",
|
||||
"posting": "Posting",
|
||||
"scope": {
|
||||
"direct": "Direct - Post to mentioned users only",
|
||||
|
@ -407,7 +409,26 @@
|
|||
"block_progress": "Blocking...",
|
||||
"unmute": "Unmute",
|
||||
"unmute_progress": "Unmuting...",
|
||||
"mute_progress": "Muting..."
|
||||
"mute_progress": "Muting...",
|
||||
"admin_menu": {
|
||||
"moderation": "Moderation",
|
||||
"grant_admin": "Grant Admin",
|
||||
"revoke_admin": "Revoke Admin",
|
||||
"grant_moderator": "Grant Moderator",
|
||||
"revoke_moderator": "Revoke Moderator",
|
||||
"activate_account": "Activate account",
|
||||
"deactivate_account": "Deactivate account",
|
||||
"delete_account": "Delete account",
|
||||
"force_nsfw": "Mark all posts as NSFW",
|
||||
"strip_media": "Remove media from posts",
|
||||
"force_unlisted": "Force posts to be unlisted",
|
||||
"sandbox": "Force posts to be followers-only",
|
||||
"disable_remote_subscription": "Disallow following user from remote instances",
|
||||
"disable_any_subscription": "Disallow following user at all",
|
||||
"quarantine": "Disallow user posts from federating",
|
||||
"delete_user": "Delete user",
|
||||
"delete_user_confirmation": "Are you absolutely sure? This action cannot be undone."
|
||||
}
|
||||
},
|
||||
"user_profile": {
|
||||
"timeline_title": "User Timeline",
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
},
|
||||
"general": {
|
||||
"apply": "Применить",
|
||||
"submit": "Отправить"
|
||||
"submit": "Отправить",
|
||||
"cancel": "Отмена"
|
||||
},
|
||||
"login": {
|
||||
"login": "Войти",
|
||||
|
@ -311,7 +312,26 @@
|
|||
"muted": "Игнорирую",
|
||||
"per_day": "в день",
|
||||
"remote_follow": "Читать удалённо",
|
||||
"statuses": "Статусы"
|
||||
"statuses": "Статусы",
|
||||
"admin_menu": {
|
||||
"moderation": "Опции модератора",
|
||||
"grant_admin": "Сделать администратором",
|
||||
"revoke_admin": "Забрать права администратора",
|
||||
"grant_moderator": "Сделать модератором",
|
||||
"revoke_moderator": "Забрать права модератора",
|
||||
"activate_account": "Активировать аккаунт",
|
||||
"deactivate_account": "Деактивировать аккаунт",
|
||||
"delete_account": "Удалить аккаунт",
|
||||
"force_nsfw": "Отмечать посты пользователя как NSFW",
|
||||
"strip_media": "Убирать вложения из постов пользователя",
|
||||
"force_unlisted": "Не добавлять посты в публичные ленты",
|
||||
"sandbox": "Посты доступны только для подписчиков",
|
||||
"disable_remote_subscription": "Запретить подписываться с удаленных серверов",
|
||||
"disable_any_subscription": "Запретить подписываться на пользователя",
|
||||
"quarantine": "Не федерировать посты пользователя",
|
||||
"delete_user": "Удалить пользователя",
|
||||
"delete_user_confirmation": "Вы уверены? Это действие нельзя отменить."
|
||||
}
|
||||
},
|
||||
"user_profile": {
|
||||
"timeline_title": "Лента пользователя"
|
||||
|
|
|
@ -13,11 +13,11 @@ const api = {
|
|||
setBackendInteractor (state, backendInteractor) {
|
||||
state.backendInteractor = backendInteractor
|
||||
},
|
||||
addFetcher (state, {timeline, fetcher}) {
|
||||
state.fetchers[timeline] = fetcher
|
||||
addFetcher (state, { fetcherName, fetcher }) {
|
||||
state.fetchers[fetcherName] = fetcher
|
||||
},
|
||||
removeFetcher (state, {timeline}) {
|
||||
delete state.fetchers[timeline]
|
||||
removeFetcher (state, { fetcherName }) {
|
||||
delete state.fetchers[fetcherName]
|
||||
},
|
||||
setWsToken (state, token) {
|
||||
state.wsToken = token
|
||||
|
@ -33,17 +33,24 @@ const api = {
|
|||
}
|
||||
},
|
||||
actions: {
|
||||
startFetching (store, {timeline = 'friends', tag = false, userId = false}) {
|
||||
startFetchingTimeline (store, { timeline = 'friends', tag = false, userId = false }) {
|
||||
// Don't start fetching if we already are.
|
||||
if (store.state.fetchers[timeline]) return
|
||||
|
||||
const fetcher = store.state.backendInteractor.startFetching({ timeline, store, userId, tag })
|
||||
store.commit('addFetcher', { timeline, fetcher })
|
||||
const fetcher = store.state.backendInteractor.startFetchingTimeline({ timeline, store, userId, tag })
|
||||
store.commit('addFetcher', { fetcherName: timeline, fetcher })
|
||||
},
|
||||
stopFetching (store, timeline) {
|
||||
const fetcher = store.state.fetchers[timeline]
|
||||
startFetchingNotifications (store) {
|
||||
// Don't start fetching if we already are.
|
||||
if (store.state.fetchers['notifications']) return
|
||||
|
||||
const fetcher = store.state.backendInteractor.startFetchingNotifications({ store })
|
||||
store.commit('addFetcher', { fetcherName: 'notifications', fetcher })
|
||||
},
|
||||
stopFetching (store, fetcherName) {
|
||||
const fetcher = store.state.fetchers[fetcherName]
|
||||
window.clearInterval(fetcher)
|
||||
store.commit('removeFetcher', {timeline})
|
||||
store.commit('removeFetcher', { fetcherName })
|
||||
},
|
||||
setWsToken (store, token) {
|
||||
store.commit('setWsToken', token)
|
||||
|
|
|
@ -5,6 +5,7 @@ const defaultState = {
|
|||
// Stuff from static/config.json and apiConfig
|
||||
name: 'Pleroma FE',
|
||||
registrationOpen: true,
|
||||
safeDM: true,
|
||||
textlimit: 5000,
|
||||
server: 'http://localhost:4040/',
|
||||
theme: 'pleroma-dark',
|
||||
|
|
|
@ -48,7 +48,6 @@ const interfaceMod = {
|
|||
commit('setNotificationPermission', permission)
|
||||
},
|
||||
setMobileLayout ({ commit }, value) {
|
||||
console.log('setMobileLayout called')
|
||||
commit('setMobileLayout', value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,20 +20,21 @@ const emptyTl = (userId = 0) => ({
|
|||
flushMarker: 0
|
||||
})
|
||||
|
||||
const emptyNotifications = () => ({
|
||||
desktopNotificationSilence: true,
|
||||
maxId: 0,
|
||||
minId: Number.POSITIVE_INFINITY,
|
||||
data: [],
|
||||
idStore: {},
|
||||
loading: false,
|
||||
error: false
|
||||
})
|
||||
|
||||
export const defaultState = () => ({
|
||||
allStatuses: [],
|
||||
allStatusesObject: {},
|
||||
maxId: 0,
|
||||
notifications: {
|
||||
desktopNotificationSilence: true,
|
||||
maxId: 0,
|
||||
minId: Number.POSITIVE_INFINITY,
|
||||
data: [],
|
||||
idStore: {},
|
||||
loading: false,
|
||||
error: false,
|
||||
fetcherId: null
|
||||
},
|
||||
notifications: emptyNotifications(),
|
||||
favorites: new Set(),
|
||||
error: false,
|
||||
timelines: {
|
||||
|
@ -340,9 +341,6 @@ export const mutations = {
|
|||
oldTimeline.visibleStatusesObject = {}
|
||||
each(oldTimeline.visibleStatuses, (status) => { oldTimeline.visibleStatusesObject[status.id] = status })
|
||||
},
|
||||
setNotificationFetcher (state, { fetcherId }) {
|
||||
state.notifications.fetcherId = fetcherId
|
||||
},
|
||||
resetStatuses (state) {
|
||||
const emptyState = defaultState()
|
||||
Object.entries(emptyState).forEach(([key, value]) => {
|
||||
|
@ -352,6 +350,9 @@ export const mutations = {
|
|||
clearTimeline (state, { timeline }) {
|
||||
state.timelines[timeline] = emptyTl(state.timelines[timeline].userId)
|
||||
},
|
||||
clearNotifications (state) {
|
||||
state.notifications = emptyNotifications()
|
||||
},
|
||||
setFavorited (state, { status, value }) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
newStatus.favorited = value
|
||||
|
@ -378,6 +379,13 @@ export const mutations = {
|
|||
const newStatus = state.allStatusesObject[status.id]
|
||||
newStatus.deleted = true
|
||||
},
|
||||
setManyDeleted (state, condition) {
|
||||
Object.values(state.allStatusesObject).forEach(status => {
|
||||
if (condition(status)) {
|
||||
status.deleted = true
|
||||
}
|
||||
})
|
||||
},
|
||||
setLoading (state, { timeline, value }) {
|
||||
state.timelines[timeline].loading = value
|
||||
},
|
||||
|
@ -428,16 +436,13 @@ const statuses = {
|
|||
setNotificationsSilence ({ rootState, commit }, { value }) {
|
||||
commit('setNotificationsSilence', { value })
|
||||
},
|
||||
stopFetchingNotifications ({ rootState, commit }) {
|
||||
if (rootState.statuses.notifications.fetcherId) {
|
||||
window.clearInterval(rootState.statuses.notifications.fetcherId)
|
||||
}
|
||||
commit('setNotificationFetcher', { fetcherId: null })
|
||||
},
|
||||
deleteStatus ({ rootState, commit }, status) {
|
||||
commit('setDeleted', { status })
|
||||
apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials })
|
||||
},
|
||||
markStatusesAsDeleted ({ commit }, condition) {
|
||||
commit('setManyDeleted', condition)
|
||||
},
|
||||
favorite ({ rootState, commit }, status) {
|
||||
// Optimistic favoriting...
|
||||
commit('setFavorited', { status, value: true })
|
||||
|
|
|
@ -37,6 +37,28 @@ export const mutations = {
|
|||
const user = state.usersObject[id]
|
||||
set(user, 'muted', muted)
|
||||
},
|
||||
tagUser (state, { user: { id }, tag }) {
|
||||
const user = state.usersObject[id]
|
||||
const tags = user.tags || []
|
||||
const newTags = tags.concat([tag])
|
||||
set(user, 'tags', newTags)
|
||||
},
|
||||
untagUser (state, { user: { id }, tag }) {
|
||||
const user = state.usersObject[id]
|
||||
const tags = user.tags || []
|
||||
const newTags = tags.filter(t => t !== tag)
|
||||
set(user, 'tags', newTags)
|
||||
},
|
||||
updateRight (state, { user: { id }, right, value }) {
|
||||
const user = state.usersObject[id]
|
||||
let newRights = user.rights
|
||||
newRights[right] = value
|
||||
set(user, 'rights', newRights)
|
||||
},
|
||||
updateActivationStatus (state, { user: { id }, status }) {
|
||||
const user = state.usersObject[id]
|
||||
set(user, 'deactivated', !status)
|
||||
},
|
||||
setCurrentUser (state, user) {
|
||||
state.lastLoginName = user.screen_name
|
||||
state.currentUser = merge(state.currentUser || {}, user)
|
||||
|
@ -331,7 +353,8 @@ const users = {
|
|||
store.commit('setToken', false)
|
||||
store.dispatch('stopFetching', 'friends')
|
||||
store.commit('setBackendInteractor', backendInteractorService())
|
||||
store.dispatch('stopFetchingNotifications')
|
||||
store.dispatch('stopFetching', 'notifications')
|
||||
store.commit('clearNotifications')
|
||||
store.commit('resetStatuses')
|
||||
},
|
||||
loginUser (store, accessToken) {
|
||||
|
@ -363,7 +386,10 @@ const users = {
|
|||
}
|
||||
|
||||
// Start getting fresh posts.
|
||||
store.dispatch('startFetching', { timeline: 'friends' })
|
||||
store.dispatch('startFetchingTimeline', { timeline: 'friends' })
|
||||
|
||||
// Start fetching notifications
|
||||
store.dispatch('startFetchingNotifications')
|
||||
|
||||
// Get user mutes
|
||||
store.dispatch('fetchMutes')
|
||||
|
|
|
@ -16,6 +16,10 @@ const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
|||
const FOLLOW_REQUESTS_URL = '/api/pleroma/friend_requests'
|
||||
const APPROVE_USER_URL = '/api/pleroma/friendships/approve'
|
||||
const DENY_USER_URL = '/api/pleroma/friendships/deny'
|
||||
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
|
||||
const PERMISSION_GROUP_URL = '/api/pleroma/admin/permission_group'
|
||||
const ACTIVATION_STATUS_URL = '/api/pleroma/admin/activation_status'
|
||||
const ADMIN_USER_URL = '/api/pleroma/admin/user'
|
||||
const SUGGESTIONS_URL = '/api/v1/suggestions'
|
||||
|
||||
const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
|
||||
|
@ -354,6 +358,86 @@ const fetchStatus = ({id, credentials}) => {
|
|||
.then((data) => parseStatus(data))
|
||||
}
|
||||
|
||||
const tagUser = ({tag, credentials, ...options}) => {
|
||||
const screenName = options.screen_name
|
||||
const form = {
|
||||
nicknames: [screenName],
|
||||
tags: [tag]
|
||||
}
|
||||
|
||||
const headers = authHeaders(credentials)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
return fetch(TAG_USER_URL, {
|
||||
method: 'PUT',
|
||||
headers: headers,
|
||||
body: JSON.stringify(form)
|
||||
})
|
||||
}
|
||||
|
||||
const untagUser = ({tag, credentials, ...options}) => {
|
||||
const screenName = options.screen_name
|
||||
const body = {
|
||||
nicknames: [screenName],
|
||||
tags: [tag]
|
||||
}
|
||||
|
||||
const headers = authHeaders(credentials)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
return fetch(TAG_USER_URL, {
|
||||
method: 'DELETE',
|
||||
headers: headers,
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
}
|
||||
|
||||
const addRight = ({right, credentials, ...user}) => {
|
||||
const screenName = user.screen_name
|
||||
|
||||
return fetch(`${PERMISSION_GROUP_URL}/${screenName}/${right}`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(credentials),
|
||||
body: {}
|
||||
})
|
||||
}
|
||||
|
||||
const deleteRight = ({right, credentials, ...user}) => {
|
||||
const screenName = user.screen_name
|
||||
|
||||
return fetch(`${PERMISSION_GROUP_URL}/${screenName}/${right}`, {
|
||||
method: 'DELETE',
|
||||
headers: authHeaders(credentials),
|
||||
body: {}
|
||||
})
|
||||
}
|
||||
|
||||
const setActivationStatus = ({status, credentials, ...user}) => {
|
||||
const screenName = user.screen_name
|
||||
const body = {
|
||||
status: status
|
||||
}
|
||||
|
||||
const headers = authHeaders(credentials)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
return fetch(`${ACTIVATION_STATUS_URL}/${screenName}.json`, {
|
||||
method: 'PUT',
|
||||
headers: headers,
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
}
|
||||
|
||||
const deleteUser = ({credentials, ...user}) => {
|
||||
const screenName = user.screen_name
|
||||
const headers = authHeaders(credentials)
|
||||
|
||||
return fetch(`${ADMIN_USER_URL}.json?nickname=${screenName}`, {
|
||||
method: 'DELETE',
|
||||
headers: headers
|
||||
})
|
||||
}
|
||||
|
||||
const fetchTimeline = ({timeline, credentials, since = false, until = false, userId = false, tag = false, withMuted = false}) => {
|
||||
const timelineUrls = {
|
||||
public: MASTODON_PUBLIC_TIMELINE,
|
||||
|
@ -697,6 +781,12 @@ const apiService = {
|
|||
fetchBlocks,
|
||||
fetchOAuthTokens,
|
||||
revokeOAuthToken,
|
||||
tagUser,
|
||||
untagUser,
|
||||
deleteUser,
|
||||
addRight,
|
||||
deleteRight,
|
||||
setActivationStatus,
|
||||
register,
|
||||
getCaptcha,
|
||||
updateAvatar,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import apiService from '../api/api.service.js'
|
||||
import timelineFetcherService from '../timeline_fetcher/timeline_fetcher.service.js'
|
||||
import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js'
|
||||
|
||||
const backendInteractorService = (credentials) => {
|
||||
const fetchStatus = ({id}) => {
|
||||
|
@ -58,6 +59,38 @@ const backendInteractorService = (credentials) => {
|
|||
return apiService.denyUser({credentials, id})
|
||||
}
|
||||
|
||||
const startFetchingTimeline = ({ timeline, store, userId = false, tag }) => {
|
||||
return timelineFetcherService.startFetching({ timeline, store, credentials, userId, tag })
|
||||
}
|
||||
|
||||
const startFetchingNotifications = ({ store }) => {
|
||||
return notificationsFetcher.startFetching({ store, credentials })
|
||||
}
|
||||
|
||||
const tagUser = ({screen_name}, tag) => {
|
||||
return apiService.tagUser({screen_name, tag, credentials})
|
||||
}
|
||||
|
||||
const untagUser = ({screen_name}, tag) => {
|
||||
return apiService.untagUser({screen_name, tag, credentials})
|
||||
}
|
||||
|
||||
const addRight = ({screen_name}, right) => {
|
||||
return apiService.addRight({screen_name, right, credentials})
|
||||
}
|
||||
|
||||
const deleteRight = ({screen_name}, right) => {
|
||||
return apiService.deleteRight({screen_name, right, credentials})
|
||||
}
|
||||
|
||||
const setActivationStatus = ({screen_name}, status) => {
|
||||
return apiService.setActivationStatus({screen_name, status, credentials})
|
||||
}
|
||||
|
||||
const deleteUser = ({screen_name}) => {
|
||||
return apiService.deleteUser({screen_name, credentials})
|
||||
}
|
||||
|
||||
const vote = (pollID, optionName) => {
|
||||
return apiService.vote({credentials, pollID, optionName})
|
||||
}
|
||||
|
@ -66,10 +99,6 @@ const backendInteractorService = (credentials) => {
|
|||
return apiService.fetchPoll({credentials, pollID})
|
||||
}
|
||||
|
||||
const startFetching = ({timeline, store, userId = false, tag}) => {
|
||||
return timelineFetcherService.startFetching({timeline, store, credentials, userId, tag})
|
||||
}
|
||||
|
||||
const fetchMutes = () => apiService.fetchMutes({credentials})
|
||||
const muteUser = (id) => apiService.muteUser({credentials, id})
|
||||
const unmuteUser = (id) => apiService.unmuteUser({credentials, id})
|
||||
|
@ -105,13 +134,20 @@ const backendInteractorService = (credentials) => {
|
|||
fetchUserRelationship,
|
||||
fetchAllFollowing,
|
||||
verifyCredentials: apiService.verifyCredentials,
|
||||
startFetching,
|
||||
startFetchingTimeline,
|
||||
startFetchingNotifications,
|
||||
fetchMutes,
|
||||
muteUser,
|
||||
unmuteUser,
|
||||
fetchBlocks,
|
||||
fetchOAuthTokens,
|
||||
revokeOAuthToken,
|
||||
tagUser,
|
||||
untagUser,
|
||||
addRight,
|
||||
deleteRight,
|
||||
deleteUser,
|
||||
setActivationStatus,
|
||||
register,
|
||||
getCaptcha,
|
||||
updateAvatar,
|
||||
|
|
|
@ -67,6 +67,11 @@ export const parseUser = (data) => {
|
|||
output.statusnet_blocking = relationship.blocking
|
||||
output.muted = relationship.muting
|
||||
}
|
||||
|
||||
output.rights = {
|
||||
moderator: data.pleroma.is_moderator,
|
||||
admin: data.pleroma.is_admin
|
||||
}
|
||||
}
|
||||
|
||||
// Missing, trying to recover
|
||||
|
@ -103,7 +108,12 @@ export const parseUser = (data) => {
|
|||
|
||||
// QVITTER ONLY FOR NOW
|
||||
// Really only applies to logged in user, really.. I THINK
|
||||
output.rights = data.rights
|
||||
if (data.rights) {
|
||||
output.rights = {
|
||||
moderator: data.rights.delete_others_notice,
|
||||
admin: data.rights.admin
|
||||
}
|
||||
}
|
||||
output.no_rich_text = data.no_rich_text
|
||||
output.default_scope = data.default_scope
|
||||
output.hide_follows = data.hide_follows
|
||||
|
@ -125,6 +135,13 @@ export const parseUser = (data) => {
|
|||
output.follow_request_count = data.pleroma.follow_request_count
|
||||
}
|
||||
|
||||
if (data.pleroma) {
|
||||
output.tags = data.pleroma.tags
|
||||
output.deactivated = data.pleroma.deactivated
|
||||
}
|
||||
|
||||
output.tags = output.tags || []
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -4831,6 +4831,10 @@ pluralize@^1.2.1:
|
|||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
|
||||
|
||||
popper.js@^1.14.7:
|
||||
version "1.14.7"
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e"
|
||||
|
||||
posix-character-classes@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||
|
@ -6457,6 +6461,12 @@ vue-loader@^11.1.0:
|
|||
vue-style-loader "^2.0.0"
|
||||
vue-template-es2015-compiler "^1.2.2"
|
||||
|
||||
vue-popperjs@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-popperjs/-/vue-popperjs-2.0.3.tgz#7c446d0ba7c63170ccb33a02669d0df4efc3d8cd"
|
||||
dependencies:
|
||||
popper.js "^1.14.7"
|
||||
|
||||
vue-router@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.2.tgz#dedc67afe6c4e2bc25682c8b1c2a8c0d7c7e56be"
|
||||
|
|
Loading…
Reference in a new issue