Merge branch 'feature/locked-accounts' into 'develop'

Feature/locked accounts

See merge request pleroma/pleroma-fe!274
This commit is contained in:
lambda 2018-06-12 16:57:18 +00:00
commit 6ea5cfe71e
14 changed files with 135 additions and 13 deletions

View File

@ -23,12 +23,12 @@ module.exports = {
assetsPublicPath: '/', assetsPublicPath: '/',
proxyTable: { proxyTable: {
'/api': { '/api': {
target: 'htts://localhost:4000/', target: 'http://localhost:4000/',
changeOrigin: true, changeOrigin: true,
cookieDomainRewrite: 'localhost' cookieDomainRewrite: 'localhost'
}, },
'/socket': { '/socket': {
target: 'htts://localhost:4000/', target: 'http://localhost:4000/',
changeOrigin: true, changeOrigin: true,
cookieDomainRewrite: 'localhost', cookieDomainRewrite: 'localhost',
ws: true ws: true

View File

@ -0,0 +1,23 @@
import UserCard from '../user_card/user_card.vue'
const FollowRequests = {
components: {
UserCard
},
created () {
this.updateRequests()
},
computed: {
requests () {
return this.$store.state.api.followRequests
}
},
methods: {
updateRequests () {
this.$store.state.api.backendInteractor.fetchFollowRequests()
.then((requests) => { this.$store.commit('setFollowRequests', requests) })
}
}
}
export default FollowRequests

View File

@ -0,0 +1,12 @@
<template>
<div class="settings panel panel-default">
<div class="panel-heading">
{{$t('nav.friend_requests')}}
</div>
<div class="panel-body">
<user-card v-for="request in requests" :key="request.id" :user="request" :showFollows="false" :showApproval="true"></user-card>
</div>
</div>
</template>
<script src="./follow_requests.js"></script>

View File

@ -12,6 +12,11 @@
{{ $t("nav.mentions") }} {{ $t("nav.mentions") }}
</router-link> </router-link>
</li> </li>
<li v-if='currentUser && currentUser.locked'>
<router-link to='/friend-requests'>
{{ $t("nav.friend_requests") }}
</router-link>
</li>
<li> <li>
<router-link to='/main/public'> <router-link to='/main/public'>
{{ $t("nav.public_tl") }} {{ $t("nav.public_tl") }}

View File

@ -3,7 +3,8 @@ import UserCardContent from '../user_card_content/user_card_content.vue'
const UserCard = { const UserCard = {
props: [ props: [
'user', 'user',
'showFollows' 'showFollows',
'showApproval'
], ],
data () { data () {
return { return {
@ -16,6 +17,14 @@ const UserCard = {
methods: { methods: {
toggleUserExpanded () { toggleUserExpanded () {
this.userExpanded = !this.userExpanded this.userExpanded = !this.userExpanded
},
approveUser () {
this.$store.state.api.backendInteractor.approveUser(this.user.id)
this.$store.dispatch('removeFollowRequest', this.user)
},
denyUser () {
this.$store.state.api.backendInteractor.denyUser(this.user.id)
this.$store.dispatch('removeFollowRequest', this.user)
} }
} }
} }

View File

@ -15,6 +15,10 @@
</div> </div>
<a :href="user.statusnet_profile_url" target="blank"><div class="user-screen-name">@{{ user.screen_name }}</div></a> <a :href="user.statusnet_profile_url" target="blank"><div class="user-screen-name">@{{ user.screen_name }}</div></a>
</div> </div>
<div class="approval" v-if="showApproval">
<button class="btn btn-default" @click="approveUser">{{ $t('user_card.approve') }}</button>
<button class="btn btn-default" @click="denyUser">{{ $t('user_card.deny') }}</button>
</div>
</div> </div>
</template> </template>
@ -75,4 +79,11 @@
margin-bottom: 0; margin-bottom: 0;
} }
} }
.approval {
button {
width: 100%;
margin-bottom: 0.5em;
}
}
</style> </style>

View File

@ -15,7 +15,7 @@
<div class="name-and-screen-name"> <div class="name-and-screen-name">
<div :title="user.name" class='user-name'>{{user.name}}</div> <div :title="user.name" class='user-name'>{{user.name}}</div>
<router-link class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }"> <router-link class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }">
<span>@{{user.screen_name}}</span> <span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span>
<span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span> <span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span>
</router-link> </router-link>
</div> </div>

View File

@ -5,6 +5,7 @@ const UserSettings = {
return { return {
newname: this.$store.state.users.currentUser.name, newname: this.$store.state.users.currentUser.name,
newbio: this.$store.state.users.currentUser.description, newbio: this.$store.state.users.currentUser.description,
newlocked: this.$store.state.users.currentUser.locked,
followList: null, followList: null,
followImportError: false, followImportError: false,
followsImported: false, followsImported: false,
@ -34,7 +35,8 @@ const UserSettings = {
updateProfile () { updateProfile () {
const name = this.newname const name = this.newname
const description = this.newbio const description = this.newbio
this.$store.state.api.backendInteractor.updateProfile({params: {name, description}}).then((user) => { const locked = this.newlocked
this.$store.state.api.backendInteractor.updateProfile({params: {name, description, locked}}).then((user) => {
if (!user.error) { if (!user.error) {
this.$store.commit('addNewUsers', [user]) this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user) this.$store.commit('setCurrentUser', user)

View File

@ -10,6 +10,10 @@
<input class='name-changer' id='username' v-model="newname"></input> <input class='name-changer' id='username' v-model="newname"></input>
<p>{{$t('settings.bio')}}</p> <p>{{$t('settings.bio')}}</p>
<textarea class="bio" v-model="newbio"></textarea> <textarea class="bio" v-model="newbio"></textarea>
<div class="setting-item">
<input type="checkbox" v-model="newlocked" id="account-locked">
<label for="account-locked">{{$t('settings.lock_account_description')}}</label>
</div>
<button :disabled='newname.length <= 0' class="btn btn-default" @click="updateProfile">{{$t('general.submit')}}</button> <button :disabled='newname.length <= 0' class="btn btn-default" @click="updateProfile">{{$t('general.submit')}}</button>
</div> </div>
<div class="setting-item"> <div class="setting-item">

View File

@ -220,7 +220,8 @@ const en = {
timeline: 'Timeline', timeline: 'Timeline',
mentions: 'Mentions', mentions: 'Mentions',
public_tl: 'Public Timeline', public_tl: 'Public Timeline',
twkn: 'The Whole Known Network' twkn: 'The Whole Known Network',
friend_requests: 'Follow Requests'
}, },
user_card: { user_card: {
follows_you: 'Follows you!', follows_you: 'Follows you!',
@ -234,7 +235,9 @@ const en = {
followers: 'Followers', followers: 'Followers',
followees: 'Following', followees: 'Following',
per_day: 'per day', per_day: 'per day',
remote_follow: 'Remote follow' remote_follow: 'Remote follow',
approve: 'Approve',
deny: 'Deny'
}, },
timeline: { timeline: {
show_new: 'Show new', show_new: 'Show new',
@ -304,7 +307,8 @@ const en = {
new_password: 'New password', new_password: 'New password',
confirm_new_password: 'Confirm new password', confirm_new_password: 'Confirm new password',
changed_password: 'Password changed successfully!', changed_password: 'Password changed successfully!',
change_password_error: 'There was an issue changing your password.' change_password_error: 'There was an issue changing your password.',
lock_account_description: 'Restrict your account to approved followers only'
}, },
notifications: { notifications: {
notifications: 'Notifications', notifications: 'Notifications',

View File

@ -12,6 +12,7 @@ import UserProfile from './components/user_profile/user_profile.vue'
import Settings from './components/settings/settings.vue' import Settings from './components/settings/settings.vue'
import Registration from './components/registration/registration.vue' import Registration from './components/registration/registration.vue'
import UserSettings from './components/user_settings/user_settings.vue' import UserSettings from './components/user_settings/user_settings.vue'
import FollowRequests from './components/follow_requests/follow_requests.vue'
import statusesModule from './modules/statuses.js' import statusesModule from './modules/statuses.js'
import usersModule from './modules/users.js' import usersModule from './modules/users.js'
@ -118,6 +119,7 @@ window.fetch('/static/config.json')
{ name: 'mentions', path: '/:username/mentions', component: Mentions }, { name: 'mentions', path: '/:username/mentions', component: Mentions },
{ name: 'settings', path: '/settings', component: Settings }, { name: 'settings', path: '/settings', component: Settings },
{ name: 'registration', path: '/registration', component: Registration }, { name: 'registration', path: '/registration', component: Registration },
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
{ name: 'user-settings', path: '/user-settings', component: UserSettings } { name: 'user-settings', path: '/user-settings', component: UserSettings }
] ]

View File

@ -7,7 +7,8 @@ const api = {
backendInteractor: backendInteractorService(), backendInteractor: backendInteractorService(),
fetchers: {}, fetchers: {},
socket: null, socket: null,
chatDisabled: false chatDisabled: false,
followRequests: []
}, },
mutations: { mutations: {
setBackendInteractor (state, backendInteractor) { setBackendInteractor (state, backendInteractor) {
@ -24,6 +25,9 @@ const api = {
}, },
setChatDisabled (state, value) { setChatDisabled (state, value) {
state.chatDisabled = value state.chatDisabled = value
},
setFollowRequests (state, value) {
state.followRequests = value
} }
}, },
actions: { actions: {
@ -57,6 +61,10 @@ const api = {
}, },
disableChat (store) { disableChat (store) {
store.commit('setChatDisabled', true) store.commit('setChatDisabled', true)
},
removeFollowRequest (store, request) {
let requests = store.state.followRequests.filter((it) => it !== request)
store.commit('setFollowRequests', requests)
} }
} }
} }

View File

@ -32,6 +32,9 @@ const USER_URL = '/api/users/show.json'
const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import' const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account' const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password' 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'
import { each, map } from 'lodash' import { each, map } from 'lodash'
import 'whatwg-fetch' import 'whatwg-fetch'
@ -127,11 +130,13 @@ const updateBanner = ({credentials, params}) => {
const updateProfile = ({credentials, params}) => { const updateProfile = ({credentials, params}) => {
let url = PROFILE_UPDATE_URL let url = PROFILE_UPDATE_URL
console.log(params)
const form = new FormData() const form = new FormData()
each(params, (value, key) => { each(params, (value, key) => {
if (key === 'description' || /* Always include description, because it might be empty */ /* Always include description and locked, because it might be empty or false */
value) { if (key === 'description' || key === 'locked' || value) {
form.append(key, value) form.append(key, value)
} }
}) })
@ -216,6 +221,22 @@ const unblockUser = ({id, credentials}) => {
}).then((data) => data.json()) }).then((data) => data.json())
} }
const approveUser = ({id, credentials}) => {
let url = `${APPROVE_USER_URL}?user_id=${id}`
return fetch(url, {
headers: authHeaders(credentials),
method: 'POST'
}).then((data) => data.json())
}
const denyUser = ({id, credentials}) => {
let url = `${DENY_USER_URL}?user_id=${id}`
return fetch(url, {
headers: authHeaders(credentials),
method: 'POST'
}).then((data) => data.json())
}
const fetchUser = ({id, credentials}) => { const fetchUser = ({id, credentials}) => {
let url = `${USER_URL}?user_id=${id}` let url = `${USER_URL}?user_id=${id}`
return fetch(url, { headers: authHeaders(credentials) }) return fetch(url, { headers: authHeaders(credentials) })
@ -240,6 +261,12 @@ const fetchAllFollowing = ({username, credentials}) => {
.then((data) => data.json()) .then((data) => data.json())
} }
const fetchFollowRequests = ({credentials}) => {
const url = FOLLOW_REQUESTS_URL
return fetch(url, { headers: authHeaders(credentials) })
.then((data) => data.json())
}
const fetchConversation = ({id, credentials}) => { const fetchConversation = ({id, credentials}) => {
let url = `${CONVERSATION_URL}/${id}.json?count=100` let url = `${CONVERSATION_URL}/${id}.json?count=100`
return fetch(url, { headers: authHeaders(credentials) }) return fetch(url, { headers: authHeaders(credentials) })
@ -442,7 +469,10 @@ const apiService = {
externalProfile, externalProfile,
followImport, followImport,
deleteAccount, deleteAccount,
changePassword changePassword,
fetchFollowRequests,
approveUser,
denyUser
} }
export default apiService export default apiService

View File

@ -42,6 +42,14 @@ const backendInteractorService = (credentials) => {
return apiService.unblockUser({credentials, id}) return apiService.unblockUser({credentials, id})
} }
const approveUser = (id) => {
return apiService.approveUser({credentials, id})
}
const denyUser = (id) => {
return apiService.denyUser({credentials, id})
}
const startFetching = ({timeline, store, userId = false}) => { const startFetching = ({timeline, store, userId = false}) => {
return timelineFetcherService.startFetching({timeline, store, credentials, userId}) return timelineFetcherService.startFetching({timeline, store, credentials, userId})
} }
@ -51,6 +59,7 @@ const backendInteractorService = (credentials) => {
} }
const fetchMutes = () => apiService.fetchMutes({credentials}) const fetchMutes = () => apiService.fetchMutes({credentials})
const fetchFollowRequests = () => apiService.fetchFollowRequests({credentials})
const register = (params) => apiService.register(params) const register = (params) => apiService.register(params)
const updateAvatar = ({params}) => apiService.updateAvatar({credentials, params}) const updateAvatar = ({params}) => apiService.updateAvatar({credentials, params})
@ -87,7 +96,10 @@ const backendInteractorService = (credentials) => {
externalProfile, externalProfile,
followImport, followImport,
deleteAccount, deleteAccount,
changePassword changePassword,
fetchFollowRequests,
approveUser,
denyUser
} }
return backendInteractorServiceInstance return backendInteractorServiceInstance