Merge branch 'feat/idempotency' into 'develop'
Status posting Idempotency See merge request pleroma/pleroma-fe!1194
This commit is contained in:
commit
0ea23a03ce
|
@ -51,6 +51,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- Videos are not cropped awkwardly in the uploads section anymore
|
||||
- Reply filtering options in Settings -> Filtering now work again using filtering on server
|
||||
- Don't show just blank-screen when cookies are disabled
|
||||
- Add status idempotency to prevent accidental double posting when posting returns an error
|
||||
|
||||
## [2.0.3] - 2020-05-02
|
||||
### Fixed
|
||||
|
|
|
@ -66,6 +66,7 @@ const PostStatusForm = {
|
|||
StatusContent
|
||||
},
|
||||
mounted () {
|
||||
this.updateIdempotencyKey()
|
||||
this.resize(this.$refs.textarea)
|
||||
|
||||
if (this.replyTo) {
|
||||
|
@ -116,7 +117,8 @@ const PostStatusForm = {
|
|||
dropStopTimeout: null,
|
||||
preview: null,
|
||||
previewLoading: false,
|
||||
emojiInputShown: false
|
||||
emojiInputShown: false,
|
||||
idempotencyKey: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -211,14 +213,43 @@ const PostStatusForm = {
|
|||
})
|
||||
},
|
||||
watch: {
|
||||
'newStatus.contentType': function () {
|
||||
this.autoPreview()
|
||||
},
|
||||
'newStatus.spoilerText': function () {
|
||||
this.autoPreview()
|
||||
'newStatus': {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.statusChanged()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
statusChanged () {
|
||||
this.autoPreview()
|
||||
this.updateIdempotencyKey()
|
||||
},
|
||||
clearStatus () {
|
||||
const newStatus = this.newStatus
|
||||
this.newStatus = {
|
||||
status: '',
|
||||
spoilerText: '',
|
||||
files: [],
|
||||
visibility: newStatus.visibility,
|
||||
contentType: newStatus.contentType,
|
||||
poll: {},
|
||||
mediaDescriptions: {}
|
||||
}
|
||||
this.pollFormVisible = false
|
||||
this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile()
|
||||
this.clearPollForm()
|
||||
if (this.preserveFocus) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.textarea.focus()
|
||||
})
|
||||
}
|
||||
let el = this.$el.querySelector('textarea')
|
||||
el.style.height = 'auto'
|
||||
el.style.height = undefined
|
||||
this.error = null
|
||||
if (this.preview) this.previewStatus()
|
||||
},
|
||||
async postStatus (event, newStatus, opts = {}) {
|
||||
if (this.posting) { return }
|
||||
if (this.disableSubmit) { return }
|
||||
|
@ -258,36 +289,16 @@ const PostStatusForm = {
|
|||
store: this.$store,
|
||||
inReplyToStatusId: this.replyTo,
|
||||
contentType: newStatus.contentType,
|
||||
poll
|
||||
poll,
|
||||
idempotencyKey: this.idempotencyKey
|
||||
}
|
||||
|
||||
const postHandler = this.postHandler ? this.postHandler : statusPoster.postStatus
|
||||
|
||||
postHandler(postingOptions).then((data) => {
|
||||
if (!data.error) {
|
||||
this.newStatus = {
|
||||
status: '',
|
||||
spoilerText: '',
|
||||
files: [],
|
||||
visibility: newStatus.visibility,
|
||||
contentType: newStatus.contentType,
|
||||
poll: {},
|
||||
mediaDescriptions: {}
|
||||
}
|
||||
this.pollFormVisible = false
|
||||
this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile()
|
||||
this.clearPollForm()
|
||||
this.clearStatus()
|
||||
this.$emit('posted', data)
|
||||
if (this.preserveFocus) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.textarea.focus()
|
||||
})
|
||||
}
|
||||
let el = this.$el.querySelector('textarea')
|
||||
el.style.height = 'auto'
|
||||
el.style.height = undefined
|
||||
this.error = null
|
||||
if (this.preview) this.previewStatus()
|
||||
} else {
|
||||
this.error = data.error
|
||||
}
|
||||
|
@ -404,7 +415,6 @@ const PostStatusForm = {
|
|||
}
|
||||
},
|
||||
onEmojiInputInput (e) {
|
||||
this.autoPreview()
|
||||
this.$nextTick(() => {
|
||||
this.resize(this.$refs['textarea'])
|
||||
})
|
||||
|
@ -542,6 +552,9 @@ const PostStatusForm = {
|
|||
},
|
||||
handleEmojiInputShow (value) {
|
||||
this.emojiInputShown = value
|
||||
},
|
||||
updateIdempotencyKey () {
|
||||
this.idempotencyKey = Date.now().toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -631,7 +631,8 @@ const postStatus = ({
|
|||
mediaIds = [],
|
||||
inReplyToStatusId,
|
||||
contentType,
|
||||
preview
|
||||
preview,
|
||||
idempotencyKey
|
||||
}) => {
|
||||
const form = new FormData()
|
||||
const pollOptions = poll.options || []
|
||||
|
@ -665,10 +666,15 @@ const postStatus = ({
|
|||
form.append('preview', 'true')
|
||||
}
|
||||
|
||||
let postHeaders = authHeaders(credentials)
|
||||
if (idempotencyKey) {
|
||||
postHeaders['idempotency-key'] = idempotencyKey
|
||||
}
|
||||
|
||||
return fetch(MASTODON_POST_STATUS_URL, {
|
||||
body: form,
|
||||
method: 'POST',
|
||||
headers: authHeaders(credentials)
|
||||
headers: postHeaders
|
||||
})
|
||||
.then((response) => {
|
||||
return response.json()
|
||||
|
|
|
@ -11,7 +11,8 @@ const postStatus = ({
|
|||
media = [],
|
||||
inReplyToStatusId = undefined,
|
||||
contentType = 'text/plain',
|
||||
preview = false
|
||||
preview = false,
|
||||
idempotencyKey = ''
|
||||
}) => {
|
||||
const mediaIds = map(media, 'id')
|
||||
|
||||
|
@ -25,7 +26,8 @@ const postStatus = ({
|
|||
inReplyToStatusId,
|
||||
contentType,
|
||||
poll,
|
||||
preview
|
||||
preview,
|
||||
idempotencyKey
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data.error && !preview) {
|
||||
|
|
Loading…
Reference in New Issue