diff options
38 files changed, 286 insertions, 40 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..c5b9ea10 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +/build/webpack.prod.conf.js export-subst diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb72931..fe382b96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,31 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 2.6.0 +### Added +- add the initial i18n translation file for Taiwanese (Hokkien), and modify some related files. +- Implemented a very basic instance administration screen +- Implement quoting + +### Fixed +- Keep aspect ratio of custom emoji reaction in notification +- Fix openSettingsModalTab so that it correctly opens Settings modal instead of Admin modal +- Add alt text to emoji picker buttons +- Use export-subst gitattribute to allow tarball builds +- fix reports now showing reason/content +- Fix HTML attribute parsing, discard attributes not strating with a letter +- Make MentionsLine aware of line breaking by non-br elements +- Fix a bug where mentioning a user twice will not fill the mention into the textarea +- Fix parsing non-ascii tags +- Fix OAuth2 token lingering after revocation +- fix regex issue in HTML parser/renderer +- don't display quoted status twice +- fix typo in code that prevented cards from showing at all +- Fix react button not working if reaction accounts are not loaded +- Fix react button misalignment on safari ios +- Fix pinned statuses gone when reloading user timeline +- Fix scrolling emoji selector in modal in safari ios + ## 2.5.1 ### Fixed - Checkboxes in settings can now work with screenreaders diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js index 7de93721..7a108f68 100644 --- a/build/webpack.prod.conf.js +++ b/build/webpack.prod.conf.js @@ -11,9 +11,16 @@ var env = process.env.NODE_ENV === 'testing' ? require('../config/test.env') : config.build.env -let commitHash = require('child_process') - .execSync('git rev-parse --short HEAD') - .toString(); +let commitHash = (() => { + const subst = "$Format:%h$"; + if(!subst.match(/Format:/)) { + return subst; + } else { + return require('child_process') + .execSync('git rev-parse --short HEAD') + .toString(); + } +})(); var webpackConfig = merge(baseWebpackConfig, { mode: 'production', diff --git a/changelog.d/add-taiwanese-aka-hokkien-i18n-support.add b/changelog.d/add-taiwanese-aka-hokkien-i18n-support.add deleted file mode 100644 index 53d89805..00000000 --- a/changelog.d/add-taiwanese-aka-hokkien-i18n-support.add +++ /dev/null @@ -1 +0,0 @@ -add the initial i18n translation file for Taiwanese (Hokkien), and modify some related files.
\ No newline at end of file diff --git a/changelog.d/adminfe.add b/changelog.d/adminfe.add deleted file mode 100644 index 188c4555..00000000 --- a/changelog.d/adminfe.add +++ /dev/null @@ -1 +0,0 @@ -Implemented a very basic instance administration screen diff --git a/changelog.d/check-changelog.skip b/changelog.d/check-changelog.skip deleted file mode 100644 index e69de29b..00000000 --- a/changelog.d/check-changelog.skip +++ /dev/null diff --git a/changelog.d/custom-emoji-notif-width.fix b/changelog.d/custom-emoji-notif-width.fix deleted file mode 100644 index da118f6b..00000000 --- a/changelog.d/custom-emoji-notif-width.fix +++ /dev/null @@ -1 +0,0 @@ -Keep aspect ratio of custom emoji reaction in notification diff --git a/changelog.d/edit-profile-button.fix b/changelog.d/edit-profile-button.fix deleted file mode 100644 index 5a92765c..00000000 --- a/changelog.d/edit-profile-button.fix +++ /dev/null @@ -1 +0,0 @@ -Fix openSettingsModalTab so that it correctly opens Settings modal instead of Admin modal diff --git a/changelog.d/mention-twice.fix b/changelog.d/mention-twice.fix deleted file mode 100644 index 0e4b71df..00000000 --- a/changelog.d/mention-twice.fix +++ /dev/null @@ -1 +0,0 @@ -Fix a bug where mentioning a user twice will not fill the mention into the textarea diff --git a/changelog.d/mentionsline-shouldbreak.fix b/changelog.d/mentionsline-shouldbreak.fix deleted file mode 100644 index 33ee8d2c..00000000 --- a/changelog.d/mentionsline-shouldbreak.fix +++ /dev/null @@ -1 +0,0 @@ -Make MentionsLine aware of line breaking by non-br elements diff --git a/changelog.d/parser.fix b/changelog.d/parser.fix deleted file mode 100644 index 13bac0bf..00000000 --- a/changelog.d/parser.fix +++ /dev/null @@ -1 +0,0 @@ -fix regex issue in HTML parser/renderer diff --git a/changelog.d/react-button-safari.fix b/changelog.d/react-button-safari.fix deleted file mode 100644 index 9846d50d..00000000 --- a/changelog.d/react-button-safari.fix +++ /dev/null @@ -1 +0,0 @@ -Fix react button misalignment on safari ios diff --git a/changelog.d/react-button.fix b/changelog.d/react-button.fix deleted file mode 100644 index c2222fb6..00000000 --- a/changelog.d/react-button.fix +++ /dev/null @@ -1 +0,0 @@ -Fix react button not working if reaction accounts are not loaded diff --git a/changelog.d/scroll-emoji-selector-safari.fix b/changelog.d/scroll-emoji-selector-safari.fix deleted file mode 100644 index 3f5dda7d..00000000 --- a/changelog.d/scroll-emoji-selector-safari.fix +++ /dev/null @@ -1 +0,0 @@ -Fix scrolling emoji selector in modal in safari ios diff --git a/package.json b/package.json index 4824df82..5d3b50ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pleroma_fe", - "version": "2.5.0", + "version": "2.6.0", "description": "Pleroma frontend, the default frontend of Pleroma social network server", "author": "Pleroma contributors <https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/CONTRIBUTORS.md>", "private": false, @@ -35,9 +35,9 @@ "js-cookie": "3.0.1", "localforage": "1.10.0", "parse-link-header": "2.0.0", - "phoenix": "1.6.2", + "phoenix": "1.7.7", "punycode.js": "2.3.0", - "qrcode": "1.5.1", + "qrcode": "1.5.3", "querystring-es3": "0.2.1", "url": "0.11.0", "utf8": "3.0.0", @@ -97,7 +97,7 @@ "karma-spec-reporter": "0.0.36", "karma-webpack": "5.0.0", "lodash": "4.17.21", - "mini-css-extract-plugin": "2.7.5", + "mini-css-extract-plugin": "2.7.6", "mocha": "10.2.0", "nightwatch": "2.6.20", "opn": "5.5.0", diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 9c1f007b..395d4834 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -259,6 +259,7 @@ const getNodeInfo = async ({ store }) => { store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') }) store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits }) store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled }) + store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') }) const uploadLimits = metadata.uploadLimits store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) }) diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index 227d7718..b8d33309 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -28,6 +28,7 @@ active: activeGroupView === group.id }" :title="group.text" + role="button" @click.prevent="highlight(group.id)" > <span @@ -116,6 +117,7 @@ :key="group.id + emoji.displayText" :title="maybeLocalizedEmojiName(emoji)" class="emoji-item" + role="button" @click.stop.prevent="onEmoji(emoji)" > <span @@ -126,6 +128,7 @@ v-else class="emoji-picker-emoji -custom" loading="lazy" + :alt="maybeLocalizedEmojiName(emoji)" :src="emoji.imageUrl" :data-emoji-name="group.id + emoji.displayText" /> diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index b75fee69..ba49961d 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -156,11 +156,13 @@ const PostStatusForm = { poll: this.statusPoll || {}, mediaDescriptions: this.statusMediaDescriptions || {}, visibility: this.statusScope || scope, - contentType: statusContentType + contentType: statusContentType, + quoting: false } } return { + randomSeed: `${Math.random()}`.replace('.', '-'), dropFiles: [], uploadingFiles: false, error: null, @@ -265,6 +267,30 @@ const PostStatusForm = { isEdit () { return typeof this.statusId !== 'undefined' && this.statusId.trim() !== '' }, + quotable () { + if (!this.$store.state.instance.quotingAvailable) { + return false + } + + if (!this.replyTo) { + return false + } + + const repliedStatus = this.$store.state.statuses.allStatusesObject[this.replyTo] + if (!repliedStatus) { + return false + } + + if (repliedStatus.visibility === 'public' || + repliedStatus.visibility === 'unlisted' || + repliedStatus.visibility === 'local') { + return true + } else if (repliedStatus.visibility === 'private') { + return repliedStatus.user.id === this.$store.state.users.currentUser.id + } + + return false + }, ...mapGetters(['mergedConfig']), ...mapState({ mobileLayout: state => state.interface.mobileLayout @@ -292,7 +318,8 @@ const PostStatusForm = { visibility: newStatus.visibility, contentType: newStatus.contentType, poll: {}, - mediaDescriptions: {} + mediaDescriptions: {}, + quoting: false } this.pollFormVisible = false this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile() @@ -340,6 +367,8 @@ const PostStatusForm = { return } + const replyOrQuoteAttr = newStatus.quoting ? 'quoteId' : 'inReplyToStatusId' + const postingOptions = { status: newStatus.status, spoilerText: newStatus.spoilerText || null, @@ -347,7 +376,7 @@ const PostStatusForm = { sensitive: newStatus.nsfw, media: newStatus.files, store: this.$store, - inReplyToStatusId: this.replyTo, + [replyOrQuoteAttr]: this.replyTo, contentType: newStatus.contentType, poll, idempotencyKey: this.idempotencyKey @@ -373,6 +402,7 @@ const PostStatusForm = { } const newStatus = this.newStatus this.previewLoading = true + const replyOrQuoteAttr = newStatus.quoting ? 'quoteId' : 'inReplyToStatusId' statusPoster.postStatus({ status: newStatus.status, spoilerText: newStatus.spoilerText || null, @@ -380,7 +410,7 @@ const PostStatusForm = { sensitive: newStatus.nsfw, media: [], store: this.$store, - inReplyToStatusId: this.replyTo, + [replyOrQuoteAttr]: this.replyTo, contentType: newStatus.contentType, poll: {}, preview: true diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index 86c1f907..9b108a5a 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -126,6 +126,36 @@ class="preview-status" /> </div> + <div + v-if="quotable" + role="radiogroup" + class="btn-group reply-or-quote-selector" + > + <button + :id="`reply-or-quote-option-${randomSeed}-reply`" + class="btn button-default reply-or-quote-option" + :class="{ toggled: !newStatus.quoting }" + tabindex="0" + role="radio" + :aria-labelledby="`reply-or-quote-option-${randomSeed}-reply`" + :aria-checked="!newStatus.quoting" + @click="newStatus.quoting = false" + > + {{ $t('post_status.reply_option') }} + </button> + <button + :id="`reply-or-quote-option-${randomSeed}-quote`" + class="btn button-default reply-or-quote-option" + :class="{ toggled: newStatus.quoting }" + tabindex="0" + role="radio" + :aria-labelledby="`reply-or-quote-option-${randomSeed}-quote`" + :aria-checked="newStatus.quoting" + @click="newStatus.quoting = true" + > + {{ $t('post_status.quote_option') }} + </button> + </div> <EmojiInput v-if="!disableSubject && (newStatus.spoilerText || alwaysShowSubject)" v-model="newStatus.spoilerText" @@ -420,6 +450,10 @@ margin: 0; } + .reply-or-quote-selector { + margin-bottom: 0.5em; + } + .text-format { .only-format { color: $fallback--faint; diff --git a/src/components/report/report.js b/src/components/report/report.js index 76055764..5685aa25 100644 --- a/src/components/report/report.js +++ b/src/components/report/report.js @@ -1,6 +1,7 @@ import Select from '../select/select.vue' import StatusContent from '../status_content/status_content.vue' import Timeago from '../timeago/timeago.vue' +import RichContent from 'src/components/rich_content/rich_content.jsx' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' const Report = { @@ -10,10 +11,12 @@ const Report = { components: { Select, StatusContent, - Timeago + Timeago, + RichContent }, computed: { report () { + console.log(this.$store.state.reports.reports[this.reportId] || {}) return this.$store.state.reports.reports[this.reportId] || {} }, state: { diff --git a/src/components/status/status.js b/src/components/status/status.js index 9a9bca7a..e722a635 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -133,6 +133,7 @@ const Status = { 'showPinned', 'inProfile', 'profileUserId', + 'inQuote', 'simpleTree', 'controlledThreadDisplayStatus', @@ -159,7 +160,8 @@ const Status = { uncontrolledMediaPlaying: [], suspendable: true, error: null, - headTailLinks: null + headTailLinks: null, + displayQuote: !this.inQuote } }, computed: { @@ -401,6 +403,18 @@ const Status = { }, editingAvailable () { return this.$store.state.instance.editingAvailable + }, + hasVisibleQuote () { + return this.status.quote_url && this.status.quote_visible + }, + hasInvisibleQuote () { + return this.status.quote_url && !this.status.quote_visible + }, + quotedStatus () { + return this.status.quote_id ? this.$store.state.statuses.allStatusesObject[this.status.quote_id] : undefined + }, + shouldDisplayQuote () { + return this.quotedStatus && this.displayQuote } }, methods: { @@ -469,6 +483,18 @@ const Status = { window.scrollBy(0, rect.bottom - window.innerHeight + 50) } } + }, + toggleDisplayQuote () { + if (this.shouldDisplayQuote) { + this.displayQuote = false + } else if (!this.quotedStatus) { + this.$store.dispatch('fetchStatus', this.status.quote_id) + .then(() => { + this.displayQuote = true + }) + } else { + this.displayQuote = true + } } }, watch: { diff --git a/src/components/status/status.scss b/src/components/status/status.scss index 44812867..760c6ac1 100644 --- a/src/components/status/status.scss +++ b/src/components/status/status.scss @@ -422,4 +422,22 @@ } } } + + .quoted-status { + margin-top: 0.5em; + border: 1px solid var(--border, $fallback--border); + border-radius: var(--attachmentRadius, $fallback--attachmentRadius); + + &.-unavailable-prompt { + padding: 0.5em; + } + } + + .display-quoted-status-button { + margin: 0.5em; + + &-icon { + color: inherit; + } + } } diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 35b15362..c49a9e7b 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -364,6 +364,45 @@ @parseReady="setHeadTailLinks" /> + <article + v-if="hasVisibleQuote" + class="quoted-status" + > + <button + class="button-unstyled -link display-quoted-status-button" + :aria-expanded="shouldDisplayQuote" + @click="toggleDisplayQuote" + > + {{ shouldDisplayQuote ? $t('status.hide_quote') : $t('status.display_quote') }} + <FAIcon + class="display-quoted-status-button-icon" + :icon="shouldDisplayQuote ? 'chevron-up' : 'chevron-down'" + /> + </button> + <Status + v-if="shouldDisplayQuote" + :statusoid="quotedStatus" + :in-quote="true" + /> + </article> + <p + v-else-if="hasInvisibleQuote" + class="quoted-status -unavailable-prompt" + > + <i18n-t keypath="status.invisible_quote"> + <template #link> + <bdi> + <a + :href="status.quote_url" + target="_blank" + > + {{ status.quote_url }} + </a> + </bdi> + </template> + </i18n-t> + </p> + <div v-if="inConversation && !isPreview && replies && replies.length" class="replies" diff --git a/src/components/status_content/status_content.js b/src/components/status_content/status_content.js index 89f0aa51..8d8a91dc 100644 --- a/src/components/status_content/status_content.js +++ b/src/components/status_content/status_content.js @@ -73,6 +73,10 @@ const StatusContent = { }, computed: { ...controlledOrUncontrolledGetters(['showingTall', 'expandingSubject', 'showingLongSubject']), + statusCard () { + if (!this.status.card) return null + return this.status.card.url === this.status.quote_url ? null : this.status.card + }, hideAttachments () { return (this.mergedConfig.hideAttachments && !this.inConversation) || (this.mergedConfig.hideAttachmentsInConv && this.inConversation) diff --git a/src/components/status_content/status_content.vue b/src/components/status_content/status_content.vue index c0e5c0b9..e977d489 100644 --- a/src/components/status_content/status_content.vue +++ b/src/components/status_content/status_content.vue @@ -43,7 +43,7 @@ /> <div - v-if="status.card && !noHeading && !compact" + v-if="statusCard && !noHeading && !compact" class="link-preview media-body" > <link-preview diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js index b7414610..1050b87a 100644 --- a/src/components/timeline/timeline.js +++ b/src/components/timeline/timeline.js @@ -160,6 +160,9 @@ const Timeline = { if (this.timeline.flushMarker !== 0) { this.$store.commit('clearTimeline', { timeline: this.timelineName, excludeUserId: true }) this.$store.commit('queueFlush', { timeline: this.timelineName, id: 0 }) + if (this.timelineName === 'user') { + this.$store.dispatch('fetchPinnedStatuses', this.userId) + } this.fetchOlderStatuses() } else { this.blockClicksTemporarily() diff --git a/src/i18n/en.json b/src/i18n/en.json index 90e33648..1658a25d 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -267,6 +267,8 @@ "post_status": { "edit_status": "Edit status", "new_status": "Post new status", + "reply_option": "Reply to this status", + "quote_option": "Quote this status", "account_not_locked_warning": "Your account is not {0}. Anyone can follow you to view your follower-only posts.", "account_not_locked_warning_link": "locked", "attachments_sensitive": "Mark attachments as sensitive", @@ -1039,7 +1041,10 @@ "show_all_conversation": "Show full conversation ({numStatus} other status) | Show full conversation ({numStatus} other statuses)", "show_only_conversation_under_this": "Only show replies to this status", "status_history": "Status history", - "reaction_count_label": "{num} person reacted | {num} people reacted" + "reaction_count_label": "{num} person reacted | {num} people reacted", + "hide_quote": "Hide the quoted status", + "display_quote": "Display the quoted status", + "invisible_quote": "Quoted status unavailable: {link}" }, "user_card": { "approve": "Approve", diff --git a/src/modules/instance.js b/src/modules/instance.js index 3972bd29..034348ff 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -133,6 +133,7 @@ const defaultState = { mediaProxyAvailable: false, suggestionsEnabled: false, suggestionsWeb: '', + quotingAvailable: false, // Html stuff instanceSpecificPanelContent: '', diff --git a/src/modules/statuses.js b/src/modules/statuses.js index ed21a730..186bba3c 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -229,6 +229,10 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us timelineObject.newStatusCount += 1 } + if (status.quote) { + addStatus(status.quote, /* showImmediately = */ false, /* addToTimeline = */ false) + } + return status } diff --git a/src/modules/users.js b/src/modules/users.js index e976d875..50b4cb84 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -651,6 +651,12 @@ const users = { const response = data.error // Authentication failed commit('endLogin') + + // remove authentication token on client/authentication errors + if ([400, 401, 403, 422].includes(response.status)) { + commit('clearToken') + } + if (response.status === 401) { reject(new Error('Wrong username or password')) } else { diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index ac715678..c6bca10b 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -827,6 +827,7 @@ const postStatus = ({ poll, mediaIds = [], inReplyToStatusId, + quoteId, contentType, preview, idempotencyKey @@ -859,6 +860,9 @@ const postStatus = ({ if (inReplyToStatusId) { form.append('in_reply_to_id', inReplyToStatusId) } + if (quoteId) { + form.append('quote_id', quoteId) + } if (preview) { form.append('preview', 'true') } diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index adefc5a5..610ba1ab 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -325,6 +325,10 @@ export const parseStatus = (data) => { output.thread_muted = pleroma.thread_muted output.emoji_reactions = pleroma.emoji_reactions output.parent_visible = pleroma.parent_visible === undefined ? true : pleroma.parent_visible + output.quote = pleroma.quote ? parseStatus(pleroma.quote) : undefined + output.quote_id = pleroma.quote_id ? pleroma.quote_id : (output.quote ? output.quote.id : undefined) + output.quote_url = pleroma.quote_url + output.quote_visible = pleroma.quote_visible } else { output.text = data.content output.summary = data.spoiler_text diff --git a/src/services/html_converter/utility.service.js b/src/services/html_converter/utility.service.js index a1301353..f8e62dfe 100644 --- a/src/services/html_converter/utility.service.js +++ b/src/services/html_converter/utility.service.js @@ -22,7 +22,7 @@ export const getAttrs = (tag, filter) => { .replace(new RegExp('^' + getTagName(tag)), '') .replace(/\/?$/, '') .trim() - const attrs = Array.from(innertag.matchAll(/([a-z0-9-]+)(?:=("[^"]+?"|'[^']+?'))?/gi)) + const attrs = Array.from(innertag.matchAll(/([a-z]+[a-z0-9-]*)(?:=("[^"]+?"|'[^']+?'))?/gi)) .map(([trash, key, value]) => [key, value]) .map(([k, v]) => { if (!v) return [k, true] diff --git a/src/services/matcher/matcher.service.js b/src/services/matcher/matcher.service.js index b6c4e909..54f02d31 100644 --- a/src/services/matcher/matcher.service.js +++ b/src/services/matcher/matcher.service.js @@ -14,8 +14,11 @@ export const mentionMatchesUrl = (attention, url) => { * @param {string} url */ export const extractTagFromUrl = (url) => { - const regex = /tag[s]*\/(\w+)$/g - const result = regex.exec(url) + const decoded = decodeURI(url) + // https://git.pleroma.social/pleroma/elixir-libraries/linkify/-/blob/master/lib/linkify/parser.ex + // https://www.pcre.org/original/doc/html/pcrepattern.html + const regex = /tag[s]*\/([\p{L}\p{N}_]*[\p{Alphabetic}_·\u{200c}][\p{L}\p{N}_·\p{M}\u{200c}]*)$/ug + const result = regex.exec(decoded) if (!result) { return false } diff --git a/src/services/status_poster/status_poster.service.js b/src/services/status_poster/status_poster.service.js index 1eb10bb6..aaef5a7a 100644 --- a/src/services/status_poster/status_poster.service.js +++ b/src/services/status_poster/status_poster.service.js @@ -10,6 +10,7 @@ const postStatus = ({ poll, media = [], inReplyToStatusId = undefined, + quoteId = undefined, contentType = 'text/plain', preview = false, idempotencyKey = '' @@ -24,6 +25,7 @@ const postStatus = ({ sensitive, mediaIds, inReplyToStatusId, + quoteId, contentType, poll, preview, diff --git a/test/unit/specs/services/matcher/matcher.spec.js b/test/unit/specs/services/matcher/matcher.spec.js index 7a2494f0..c6e9719d 100644 --- a/test/unit/specs/services/matcher/matcher.spec.js +++ b/test/unit/specs/services/matcher/matcher.spec.js @@ -78,5 +78,11 @@ describe('MatcherService', () => { expect(MatcherService.extractTagFromUrl(url)).to.eql(false) }) + + it('should return tag name from non-ascii tags', () => { + const url = encodeURI('https://website.com/tag/喵喵喵') + + expect(MatcherService.extractTagFromUrl(url)).to.eql('喵喵喵') + }) }) }) diff --git a/tools/collect-changelog b/tools/collect-changelog new file mode 100755 index 00000000..1e12d564 --- /dev/null +++ b/tools/collect-changelog @@ -0,0 +1,27 @@ +#!/bin/sh + +collectType() { + local suffix="$1" + local header="$2" + local printed=0 + for file in changelog.d/*."$suffix"; do + if [ '!' -f "$file" ]; then + continue + fi + if [ "$printed" = 0 ]; then + echo + echo "### $header" + printed=1 + fi + # Normalize any trailing newlines/spaces, etc. + echo "- $(cat "$file")" + done +} + +collectType security Security +collectType change Changed +collectType add Added +collectType fix Fixed +collectType remove Removed + +rm changelog.d/* @@ -6523,10 +6523,10 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -mini-css-extract-plugin@2.7.5: - version "2.7.5" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz#afbb344977659ec0f1f6e050c7aea456b121cfc5" - integrity sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ== +mini-css-extract-plugin@2.7.6: + version "2.7.6" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz#282a3d38863fddcd2e0c220aaed5b90bc156564d" + integrity sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw== dependencies: schema-utils "^4.0.0" @@ -7141,10 +7141,10 @@ pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" -phoenix@1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/phoenix/-/phoenix-1.6.2.tgz#8d1d9f06e51cb893d08059e80488cd0de328e01a" - integrity sha512-VjR27NETvrLSj8rI6DlpVAfo7pCYth/9+1OCoTof4LKEbq0141ze/tdxFHHZzVQSok3gqJUo2h/tqbxR3r8eyw== +phoenix@1.7.7: + version "1.7.7" + resolved "https://registry.yarnpkg.com/phoenix/-/phoenix-1.7.7.tgz#829817ea65a83ef78a3a88e3e074125f502a034f" + integrity sha512-moAN6e4Z16x/x1nswUpnTR2v5gm7HsI7eluZ2YnYUUsBNzi3cY/5frmiJfXIEi877IQAafzTfp8hd6vEUMme+w== picocolors@^1.0.0: version "1.0.0" @@ -7622,10 +7622,10 @@ qjobs@^1.2.0: resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== -qrcode@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.1.tgz#0103f97317409f7bc91772ef30793a54cd59f0cb" - integrity sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg== +qrcode@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170" + integrity sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg== dependencies: dijkstrajs "^1.0.1" encode-utf8 "^1.0.3" |
