Merge branch '437-user-profile-settings' into 'develop'

Transition to MastoAPI: user profile settings

Closes #437

See merge request pleroma/pleroma-fe!682
This commit is contained in:
HJ 2019-04-30 06:05:52 +00:00
commit 0f7f685c5e
5 changed files with 66 additions and 136 deletions

View file

@ -70,22 +70,10 @@ const ImageCropper = {
this.dataUrl = undefined this.dataUrl = undefined
this.$emit('close') this.$emit('close')
}, },
submit () { submit (cropping = true) {
this.submitting = true this.submitting = true
this.avatarUploadError = null this.avatarUploadError = null
this.submitHandler(this.cropper, this.file) this.submitHandler(cropping && this.cropper, this.file)
.then(() => this.destroy())
.catch((err) => {
this.submitError = err
})
.finally(() => {
this.submitting = false
})
},
submitWithoutCropping () {
this.submitting = true
this.avatarUploadError = null
this.submitHandler(false, this.dataUrl)
.then(() => this.destroy()) .then(() => this.destroy())
.catch((err) => { .catch((err) => {
this.submitError = err this.submitError = err

View file

@ -5,9 +5,9 @@
<img ref="img" :src="dataUrl" alt="" @load.stop="createCropper" /> <img ref="img" :src="dataUrl" alt="" @load.stop="createCropper" />
</div> </div>
<div class="image-cropper-buttons-wrapper"> <div class="image-cropper-buttons-wrapper">
<button class="btn" type="button" :disabled="submitting" @click="submit" v-text="saveText"></button> <button class="btn" type="button" :disabled="submitting" @click="submit()" v-text="saveText"></button>
<button class="btn" type="button" :disabled="submitting" @click="destroy" v-text="cancelText"></button> <button class="btn" type="button" :disabled="submitting" @click="destroy" v-text="cancelText"></button>
<button class="btn" type="button" :disabled="submitting" @click="submitWithoutCropping" v-text="saveWithoutCroppingText"></button> <button class="btn" type="button" :disabled="submitting" @click="submit(false)" v-text="saveWithoutCroppingText"></button>
<i class="icon-spin4 animate-spin" v-if="submitting"></i> <i class="icon-spin4 animate-spin" v-if="submitting"></i>
</div> </div>
<div class="alert error" v-if="submitError"> <div class="alert error" v-if="submitError">

View file

@ -109,37 +109,23 @@ const UserSettings = {
}, },
methods: { methods: {
updateProfile () { updateProfile () {
const name = this.newName
const description = this.newBio
const locked = this.newLocked
// Backend notation.
/* eslint-disable camelcase */
const default_scope = this.newDefaultScope
const no_rich_text = this.newNoRichText
const hide_follows = this.hideFollows
const hide_followers = this.hideFollowers
const show_role = this.showRole
/* eslint-enable camelcase */
this.$store.state.api.backendInteractor this.$store.state.api.backendInteractor
.updateProfile({ .updateProfile({
params: { params: {
name, note: this.newBio,
description, locked: this.newLocked,
locked,
// Backend notation. // Backend notation.
/* eslint-disable camelcase */ /* eslint-disable camelcase */
default_scope, display_name: this.newName,
no_rich_text, default_scope: this.newDefaultScope,
hide_follows, no_rich_text: this.newNoRichText,
hide_followers, hide_follows: this.hideFollows,
show_role hide_followers: this.hideFollowers,
show_role: this.showRole
/* eslint-enable camelcase */ /* eslint-enable camelcase */
}}).then((user) => { }}).then((user) => {
if (!user.error) {
this.$store.commit('addNewUsers', [user]) this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user) this.$store.commit('setCurrentUser', user)
}
}) })
}, },
changeVis (visibility) { changeVis (visibility) {
@ -159,23 +145,29 @@ const UserSettings = {
reader.onload = ({target}) => { reader.onload = ({target}) => {
const img = target.result const img = target.result
this[slot + 'Preview'] = img this[slot + 'Preview'] = img
this[slot] = file
} }
reader.readAsDataURL(file) reader.readAsDataURL(file)
}, },
submitAvatar (cropper, file) { submitAvatar (cropper, file) {
let img const that = this
if (cropper) { return new Promise((resolve, reject) => {
img = cropper.getCroppedCanvas().toDataURL(file.type) function updateAvatar (avatar) {
} else { that.$store.state.api.backendInteractor.updateAvatar({ avatar })
img = file .then((user) => {
that.$store.commit('addNewUsers', [user])
that.$store.commit('setCurrentUser', user)
resolve()
})
.catch((err) => {
reject(new Error(that.$t('upload.error.base') + ' ' + err.message))
})
} }
return this.$store.state.api.backendInteractor.updateAvatar({ params: { img } }).then((user) => { if (cropper) {
if (!user.error) { cropper.getCroppedCanvas().toBlob(updateAvatar, file.type)
this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user)
} else { } else {
throw new Error(this.$t('upload.error.base') + user.error) updateAvatar(file)
} }
}) })
}, },
@ -185,30 +177,17 @@ const UserSettings = {
submitBanner () { submitBanner () {
if (!this.bannerPreview) { return } if (!this.bannerPreview) { return }
let banner = this.bannerPreview
// eslint-disable-next-line no-undef
let imginfo = new Image()
/* eslint-disable camelcase */
let offset_top, offset_left, width, height
imginfo.src = banner
width = imginfo.width
height = imginfo.height
offset_top = 0
offset_left = 0
this.bannerUploading = true this.bannerUploading = true
this.$store.state.api.backendInteractor.updateBanner({params: {banner, offset_top, offset_left, width, height}}).then((data) => { this.$store.state.api.backendInteractor.updateBanner({banner: this.banner})
if (!data.error) { .then((user) => {
let clone = JSON.parse(JSON.stringify(this.$store.state.users.currentUser)) this.$store.commit('addNewUsers', [user])
clone.cover_photo = data.url this.$store.commit('setCurrentUser', user)
this.$store.commit('addNewUsers', [clone])
this.$store.commit('setCurrentUser', clone)
this.bannerPreview = null this.bannerPreview = null
} else {
this.bannerUploadError = this.$t('upload.error.base') + data.error
}
this.bannerUploading = false
}) })
/* eslint-enable camelcase */ .catch((err) => {
this.bannerUploadError = this.$t('upload.error.base') + ' ' + err.message
})
.then(() => { this.bannerUploading = false })
}, },
submitBg () { submitBg () {
if (!this.backgroundPreview) { return } if (!this.backgroundPreview) { return }

View file

@ -3,10 +3,7 @@ const LOGIN_URL = '/api/account/verify_credentials.json'
const ALL_FOLLOWING_URL = '/api/qvitter/allfollowing' const ALL_FOLLOWING_URL = '/api/qvitter/allfollowing'
const MENTIONS_URL = '/api/statuses/mentions.json' const MENTIONS_URL = '/api/statuses/mentions.json'
const REGISTRATION_URL = '/api/account/register.json' const REGISTRATION_URL = '/api/account/register.json'
const AVATAR_UPDATE_URL = '/api/qvitter/update_avatar.json'
const BG_UPDATE_URL = '/api/qvitter/update_background_image.json' const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
const BANNER_UPDATE_URL = '/api/account/update_profile_banner.json'
const PROFILE_UPDATE_URL = '/api/account/update_profile.json'
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json' const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json' const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json'
const BLOCKS_IMPORT_URL = '/api/pleroma/blocks_import' const BLOCKS_IMPORT_URL = '/api/pleroma/blocks_import'
@ -50,6 +47,7 @@ const MASTODON_MUTE_USER_URL = id => `/api/v1/accounts/${id}/mute`
const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute` const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute`
const MASTODON_POST_STATUS_URL = '/api/v1/statuses' const MASTODON_POST_STATUS_URL = '/api/v1/statuses'
const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media' const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media'
const MASTODON_PROFILE_UPDATE_URL = '/api/v1/accounts/update_credentials'
import { each, map, concat, last } from 'lodash' import { each, map, concat, last } from 'lodash'
import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js' import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
@ -79,28 +77,16 @@ const promisedRequest = (url, options) => {
}) })
} }
// Params const updateAvatar = ({credentials, avatar}) => {
// cropH
// cropW
// cropX
// cropY
// img (base 64 encodend data url)
const updateAvatar = ({credentials, params}) => {
let url = AVATAR_UPDATE_URL
const form = new FormData() const form = new FormData()
form.append('avatar', avatar)
each(params, (value, key) => { return fetch(MASTODON_PROFILE_UPDATE_URL, {
if (value) {
form.append(key, value)
}
})
return fetch(url, {
headers: authHeaders(credentials), headers: authHeaders(credentials),
method: 'POST', method: 'PATCH',
body: form body: form
}).then((data) => data.json()) })
.then((data) => data.json())
.then((data) => parseUser(data))
} }
const updateBg = ({credentials, params}) => { const updateBg = ({credentials, params}) => {
@ -121,52 +107,29 @@ const updateBg = ({credentials, params}) => {
}).then((data) => data.json()) }).then((data) => data.json())
} }
// Params const updateBanner = ({credentials, banner}) => {
// height
// width
// offset_left
// offset_top
// banner (base 64 encodend data url)
const updateBanner = ({credentials, params}) => {
let url = BANNER_UPDATE_URL
const form = new FormData() const form = new FormData()
form.append('header', banner)
each(params, (value, key) => { return fetch(MASTODON_PROFILE_UPDATE_URL, {
if (value) {
form.append(key, value)
}
})
return fetch(url, {
headers: authHeaders(credentials), headers: authHeaders(credentials),
method: 'POST', method: 'PATCH',
body: form body: form
}).then((data) => data.json()) })
.then((data) => data.json())
.then((data) => parseUser(data))
} }
// Params
// name
// url
// location
// description
const updateProfile = ({credentials, params}) => { const updateProfile = ({credentials, params}) => {
// Always include these fields, because they might be empty or false return promisedRequest(MASTODON_PROFILE_UPDATE_URL, {
const fields = ['description', 'locked', 'no_rich_text', 'hide_follows', 'hide_followers', 'show_role'] headers: {
let url = PROFILE_UPDATE_URL 'Accept': 'application/json',
'Content-Type': 'application/json',
const form = new FormData() ...authHeaders(credentials)
},
each(params, (value, key) => { method: 'PATCH',
if (fields.includes(key) || value) { body: JSON.stringify(params)
form.append(key, value)
}
}) })
return fetch(url, { .then((data) => parseUser(data))
headers: authHeaders(credentials),
method: 'POST',
body: form
}).then((data) => data.json())
} }
// Params needed: // Params needed:

View file

@ -101,9 +101,9 @@ const backendInteractorService = (credentials) => {
const getCaptcha = () => apiService.getCaptcha() const getCaptcha = () => apiService.getCaptcha()
const register = (params) => apiService.register(params) const register = (params) => apiService.register(params)
const updateAvatar = ({params}) => apiService.updateAvatar({credentials, params}) const updateAvatar = ({avatar}) => apiService.updateAvatar({credentials, avatar})
const updateBg = ({params}) => apiService.updateBg({credentials, params}) const updateBg = ({params}) => apiService.updateBg({credentials, params})
const updateBanner = ({params}) => apiService.updateBanner({credentials, params}) const updateBanner = ({banner}) => apiService.updateBanner({credentials, banner})
const updateProfile = ({params}) => apiService.updateProfile({credentials, params}) const updateProfile = ({params}) => apiService.updateProfile({credentials, params})
const externalProfile = (profileUrl) => apiService.externalProfile({profileUrl, credentials}) const externalProfile = (profileUrl) => apiService.externalProfile({profileUrl, credentials})