diff --git a/src/boot/after_store.js b/src/boot/after_store.js index d45584c0..469cd2c4 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -67,14 +67,26 @@ const resolveLanguage = (instanceLanguages) => { const getInstanceConfig = async ({ store }) => { try { - const res = await preloadFetch('/api/v1/instance') + const res = await preloadFetch('/api/v2/instance') if (res.ok) { const data = await res.json() - const textlimit = data.max_toot_chars - const vapidPublicKey = data.pleroma.vapid_public_key + const textlimit = data.configuration.statuses.max_characters + const vapidPublicKey = data.configuration.vapid.public_key store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit }) - store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required }) + const uploadLimits = { + general: data.configuration.media_attachments.video_size_limit, + avatar: "2097152", + background: "2097152", + banner: "2097152" + } + store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) }) + store.dispatch('setInstanceOption', { name: 'avatarlimit', value: parseInt(uploadLimits.avatar) }) + store.dispatch('setInstanceOption', { name: 'backgroundlimit', value: parseInt(uploadLimits.background) }) + store.dispatch('setInstanceOption', { name: 'bannerlimit', value: parseInt(uploadLimits.banner) }) + + store.dispatch('setInstanceOption', { name: 'postFormats', value: data.configuration.statuses.supported_mime_types }) + store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.registrations.approval_required }) // don't override cookie if set if (!Cookies.get('userLanguage')) { store.dispatch('setOption', { name: 'interfaceLanguage', value: resolveLanguage(data.languages) }) @@ -83,6 +95,8 @@ const getInstanceConfig = async ({ store }) => { if (vapidPublicKey) { store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey }) } + + resolveStaffAccounts({ store, accounts: [data.contact.account.id] }) } else { throw (res) } @@ -269,42 +283,33 @@ const getNodeInfo = async ({ store }) => { if (res.ok) { const data = await res.json() const metadata = data.metadata - const features = metadata.features store.dispatch('setInstanceOption', { name: 'name', value: metadata.nodeName }) - store.dispatch('setInstanceOption', { name: 'registrationOpen', value: data.openRegistrations }) - store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') }) - store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') }) - store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') }) - store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') }) + store.dispatch('setInstanceOption', { name: 'registrationOpen', value: false }) // registration should be done through the default interface + store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: false }) + store.dispatch('setInstanceOption', { name: 'safeDM', value: false }) + store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: true }) + store.dispatch('setInstanceOption', { name: 'editingAvailable', value: true }) store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits }) store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled }) - store.dispatch('setInstanceOption', { name: 'translationEnabled', value: features.includes('akkoma:machine_translation') }) + store.dispatch('setInstanceOption', { name: 'translationEnabled', value: false }) // idk - const uploadLimits = metadata.uploadLimits - store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) }) - store.dispatch('setInstanceOption', { name: 'avatarlimit', value: parseInt(uploadLimits.avatar) }) - store.dispatch('setInstanceOption', { name: 'backgroundlimit', value: parseInt(uploadLimits.background) }) - store.dispatch('setInstanceOption', { name: 'bannerlimit', value: parseInt(uploadLimits.banner) }) - store.dispatch('setInstanceOption', { name: 'fieldsLimits', value: metadata.fieldsLimits }) + store.dispatch('setInstanceOption', { name: 'fieldsLimits', value: 6 }) // todo: expose this on the backend - store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: metadata.restrictedNicknames }) - store.dispatch('setInstanceOption', { name: 'postFormats', value: metadata.postFormats }) + store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: [] }) - const suggestions = metadata.suggestions - store.dispatch('setInstanceOption', { name: 'suggestionsEnabled', value: suggestions.enabled }) - store.dispatch('setInstanceOption', { name: 'suggestionsWeb', value: suggestions.web }) + store.dispatch('setInstanceOption', { name: 'suggestionsEnabled', value: true }) + store.dispatch('setInstanceOption', { name: 'suggestionsWeb', value: true }) const software = data.software store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version }) store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' }) - const priv = metadata.private - store.dispatch('setInstanceOption', { name: 'private', value: priv }) + store.dispatch('setInstanceOption', { name: 'private', value: false }) const frontendVersion = window.___pleromafe_commit_hash store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion }) - const federation = metadata.federation + const federation = {} store.dispatch('setInstanceOption', { name: 'tagPolicyAvailable', @@ -314,7 +319,7 @@ const getNodeInfo = async ({ store }) => { }) store.dispatch('setInstanceOption', { name: 'federationPolicy', value: federation }) - store.dispatch('setInstanceOption', { name: 'localBubbleInstances', value: metadata.localBubbleInstances }) + store.dispatch('setInstanceOption', { name: 'localBubbleInstances', value: [] }) store.dispatch('setInstanceOption', { name: 'federating', value: typeof federation.enabled === 'undefined' @@ -322,14 +327,11 @@ const getNodeInfo = async ({ store }) => { : federation.enabled }) - store.dispatch('setInstanceOption', { name: 'publicTimelineVisibility', value: metadata.publicTimelineVisibility }) - store.dispatch('setInstanceOption', { name: 'federatedTimelineAvailable', value: metadata.federatedTimelineAvailable }) + store.dispatch('setInstanceOption', { name: 'publicTimelineVisibility', value: { bubble: false, local: true, federated: true } }) + store.dispatch('setInstanceOption', { name: 'federatedTimelineAvailable', value: true }) const accountActivationRequired = metadata.accountActivationRequired - store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: accountActivationRequired }) - - const accounts = metadata.staffAccounts - resolveStaffAccounts({ store, accounts }) + store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: true }) } else { throw (res) } diff --git a/src/components/announcement/announcement.vue b/src/components/announcement/announcement.vue index 5f64232a..e7f6448e 100644 --- a/src/components/announcement/announcement.vue +++ b/src/components/announcement/announcement.vue @@ -44,20 +44,6 @@ > {{ $t('announcements.mark_as_read_action') }} - -
-
-
-
-

{{ $t('announcements.post_form_header') }}

-
-
- -
- -
-
{ - this.$store.state.api.backendInteractor.fetchUser({ id: i.acct }) + this.$store.state.api.backendInteractor.fetchUser({ id: i.id }) .then((externalUser) => { if (!externalUser.error) { this.$store.commit('addNewUsers', [externalUser]) diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js index 818e8bd5..a0fdabbe 100644 --- a/src/components/who_to_follow_panel/who_to_follow_panel.js +++ b/src/components/who_to_follow_panel/who_to_follow_panel.js @@ -9,11 +9,12 @@ function showWhoToFollow (panel, reply) { let user = shuffled[index] let img = user.avatar || this.$store.state.instance.defaultAvatar let name = user.acct + let id = user.id toFollow.img = img toFollow.name = name - panel.$store.state.api.backendInteractor.fetchUser({ id: name }) + panel.$store.state.api.backendInteractor.fetchUser({ id }) .then((externalUser) => { if (!externalUser.error) { panel.$store.commit('addNewUsers', [externalUser]) diff --git a/src/modules/announcements.js b/src/modules/announcements.js index 0f8b6d09..e9e3d4cd 100644 --- a/src/modules/announcements.js +++ b/src/modules/announcements.js @@ -48,7 +48,6 @@ const announcements = { return store.rootState.api.backendInteractor.fetchAnnouncements() } - const all = await store.rootState.api.backendInteractor.adminFetchAnnouncements() const visible = await store.rootState.api.backendInteractor.fetchAnnouncements() const visibleObject = visible.reduce((a, c) => { a[c.id] = c @@ -56,7 +55,7 @@ const announcements = { }, {}) const getWithinVisible = announcement => visibleObject[announcement.id] - all.forEach(announcement => { + visible.forEach(announcement => { const visibleAnnouncement = getWithinVisible(announcement) if (!visibleAnnouncement) { announcement.inactive = true @@ -65,7 +64,7 @@ const announcements = { } }) - return all + return visible } return getAnnouncements() diff --git a/src/modules/instance.js b/src/modules/instance.js index 0c856352..3f598e21 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -35,7 +35,7 @@ const defaultState = { hideWordFilteredPosts: false, hidePostStats: false, hideBotIndication: false, - hideSiteFavicon: false, + hideSiteFavicon: true, hideSiteName: false, hideUserStats: false, muteBotStatuses: false, @@ -177,22 +177,19 @@ const instance = { async getCustomEmoji ({ commit, state }) { try { - const res = await window.fetch('/api/v1/pleroma/emoji') + const res = await window.fetch('/api/v1/custom_emojis') if (res.ok) { const result = await res.json() - const values = Array.isArray(result) ? Object.assign({}, ...result) : result - const emoji = Object.entries(values).map(([key, value]) => { - const imageUrl = value.image_url - return { - displayText: key, - imageUrl: imageUrl ? state.server + imageUrl : value, - tags: imageUrl ? value.tags.sort((a, b) => a > b ? 1 : 0) : ['utf'], - replacement: `:${key}: ` - } - // Technically could use tags but those are kinda useless right now, - // should have been "pack" field, that would be more useful - }).sort((a, b) => a.displayText.toLowerCase() > b.displayText.toLowerCase() ? 1 : -1) - commit('setInstanceOption', { name: 'customEmoji', value: emoji }) + const emoji = [] + for (const emojiobj of result) { + emoji.push({ + displayText: emojiobj.shortcode, + imageUrl: emojiobj.url, + tags: emojiobj.category ? [`pack:${emojiobj.category.toLowerCase()}`] : ['pack:custom'], + replacement: `:${emojiobj.shortcode}: ` + }) + } + commit('setInstanceOption', { name: 'customEmoji', value: emoji.sort((a, b) => a.displayText.toLowerCase() > b.displayText.toLowerCase() ? 1 : -1) }) } else { throw (res) } diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 1080462c..649916a1 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -752,9 +752,9 @@ const statuses = { ) }, fetchEmojiReactionsBy ({ rootState, commit }, id) { - rootState.api.backendInteractor.fetchEmojiReactions({ id }).then( - emojiReactions => { - commit('addEmojiReactionsBy', { id, emojiReactions, currentUser: rootState.users.currentUser }) + rootState.api.backendInteractor.fetchStatus({ id }).then( + status => { + commit('addEmojiReactionsBy', { id, emojiReactions: status.emoji_reactions, currentUser: rootState.users.currentUser }) } ) }, diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index de21ef3b..226ecc95 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -20,7 +20,7 @@ const ADMIN_USERS_URL = '/api/v1/pleroma/admin/users' const SUGGESTIONS_URL = '/api/v1/suggestions' const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings' const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read' -const ADMIN_REPORTS_URL = '/api/v1/pleroma/admin/reports' +const ADMIN_REPORTS_URL = '/api/v1/admin/reports' const ADMIN_REPORT_NOTES_URL = id => `/api/v1/pleroma/admin/reports/${id}/notes` const ADMIN_REPORT_NOTE_URL = (report, note) => `/api/v1/pleroma/admin/reports/${report}/notes/${note}` @@ -99,9 +99,9 @@ const MASTODON_STREAMING = '/api/v1/streaming' const MASTODON_KNOWN_DOMAIN_LIST_URL = '/api/v1/instance/peers' const MASTODON_ANNOUNCEMENTS_URL = '/api/v1/announcements' const MASTODON_ANNOUNCEMENTS_DISMISS_URL = id => `/api/v1/announcements/${id}/dismiss` -const PLEROMA_EMOJI_REACTIONS_URL = id => `/api/v1/pleroma/statuses/${id}/reactions` -const PLEROMA_EMOJI_REACT_URL = (id, emoji) => `/api/v1/pleroma/statuses/${id}/reactions/${emoji}` -const PLEROMA_EMOJI_UNREACT_URL = (id, emoji) => `/api/v1/pleroma/statuses/${id}/reactions/${emoji}` +const PLEROMA_EMOJI_REACTIONS_URL = id => `/api/v1/statuses/${id}/reactions` +const PLEROMA_EMOJI_REACT_URL = (id, emoji) => `/api/v1/statuses/${id}/react/${emoji}` +const PLEROMA_EMOJI_UNREACT_URL = (id, emoji) => `/api/v1/statuses/${id}/react/${emoji}` const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups' const PLEROMA_ANNOUNCEMENTS_URL = '/api/v1/pleroma/admin/announcements' const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements' @@ -647,7 +647,7 @@ const getReports = ({ state, limit, page, pageSize, credentials }) => { url = url + (args ? '?' + args : '') return fetch(url, { headers: authHeaders(credentials) }) .then((data) => data.json()) - .then((data) => data?.reports?.map(parseReport) ?? []) + .then((data) => data?.map(parseReport) ?? []) } const updateReportStates = ({ credentials, reports }) => { diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 4fddd875..4357973c 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -126,6 +126,34 @@ export const parseUser = (data) => { } else { output.role = 'member' } + } else { + output.relationship = { + muting: [], + blocking: [], + followed_by: [], + following: [] + } + + output.rights = { + moderator: false, + admin: false + } + + // todo: find a better way to map masto roles to akkoma roles + const roles = data.roles + if (roles) { + if (!roles[0]) { + output.role = 'member' + } else if (roles[0].id === "1") { + output.role = 'moderator' + output.rights.moderator = true + } else if (roles[0].id === "2" || roles[0].id === "3") { + output.role = 'admin' + output.rights.admin = true + } else { + output.role = 'member' + } + } } if (data.source) { @@ -297,6 +325,9 @@ export const parseStatus = (data) => { } else { output.text = data.content output.summary = data.spoiler_text + output.emoji_reactions = data.reactions + // todo: properly check if post is visible + output.parent_visible = true } if (data.akkoma) { @@ -405,14 +436,16 @@ export const parseStatus = (data) => { export const parseNotification = (data) => { const mastoDict = { 'favourite': 'like', - 'reblog': 'repeat' + 'reblog': 'repeat', + 'reaction': 'pleroma:emoji_reaction' } const masto = !data.hasOwnProperty('ntype') const output = {} if (masto) { output.type = mastoDict[data.type] || data.type - output.seen = data.pleroma.is_seen + // todo: figure out how to tell if a notification has been seen or not + output.seen = true if (data.status) { output.status = isStatusNotification(output.type) ? parseStatus(data.status) : null output.action = output.status // TODO: Refactor, this is unneeded @@ -443,15 +476,12 @@ export const parseNotification = (data) => { export const parseReport = (data) => { const report = {} - report.account = parseUser(data.account) - report.actor = parseUser(data.actor) + report.account = parseUser(data.target_account.account) + report.actor = parseUser(data.account.account) report.statuses = data.statuses.map(parseStatus) - report.notes = data.notes.map(note => { - note.user = parseUser(note.user) - return note - }) - report.state = data.state - report.content = data.content + report.notes = [] + report.state = data.action_taken ? "closed" : "open" + report.content = data.comment report.created_at = data.created_at report.id = data.id diff --git a/src/services/new_api/oauth.js b/src/services/new_api/oauth.js index 3c8e64bd..9f7010ac 100644 --- a/src/services/new_api/oauth.js +++ b/src/services/new_api/oauth.js @@ -10,9 +10,9 @@ export const getOrCreateApp = ({ clientId, clientSecret, instance, commit }) => const url = `${instance}/api/v1/apps` const form = new window.FormData() - form.append('client_name', `PleromaFE_${window.___pleromafe_commit_hash}_${(new Date()).toISOString()}`) + form.append('client_name', "AkkomaFE") form.append('redirect_uris', REDIRECT_URI) - form.append('scopes', 'read write follow push admin') + form.append('scopes', 'read write follow push admin:read admin:write') return window.fetch(url, { method: 'POST', @@ -28,7 +28,7 @@ const login = ({ instance, clientId }) => { response_type: 'code', client_id: clientId, redirect_uri: REDIRECT_URI, - scope: 'read write follow push admin' + scope: 'read write follow push admin:read admin:write' } const dataString = reduce(data, (acc, v, k) => { diff --git a/static/config.json b/static/config.json index b1d412e7..b4f8feb7 100644 --- a/static/config.json +++ b/static/config.json @@ -1,6 +1,6 @@ { "alwaysShowSubjectInput": true, - "background": "/static/aurora_borealis.jpg", + "background": "/static/wdwskyboxbanner.png", "collapseMessageWithSubject": false, "greentext": false, "hideFilteredStatuses": false, @@ -8,15 +8,15 @@ "hidePostStats": false, "hideSitename": false, "hideUserStats": false, - "loginMethod": "password", - "logo": "/static/logo.svg", + "loginMethod": "token", + "logo": "/static/logo.png", "logoMargin": ".1em", - "logoMask": true, + "logoMask": false, "logoLeft": false, "nsfwCensorImage": "", "postContentType": "text/plain", "redirectRootLogin": "/main/friends", - "redirectRootNoLogin": "/main/all", + "redirectRootNoLogin": "/main/public", "showFeaturesPanel": true, "showInstanceSpecificPanel": false, "sidebarRight": false, diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 00000000..194bcd05 Binary files /dev/null and b/static/logo.png differ diff --git a/static/terms-of-service.html b/static/terms-of-service.html index 46633629..8302265a 100644 --- a/static/terms-of-service.html +++ b/static/terms-of-service.html @@ -1,5 +1,3 @@ -

Terms of Service

+

This is Akkoma-FE modified to work on top of Mastodon/Chuckya. Note that while most of it should work fine, there are still a few differences between Akkoma and Mastodon that may cause things to break.

-

This is a placeholder, overwrite this by putting a file at

$STATIC_DIR/static/terms-of-service.html

- -

See the Static Directory docs for more info.

\ No newline at end of file +

Source code: https://akkoma.dev/esm/akkoma-fe

diff --git a/static/wdwskyboxbanner.png b/static/wdwskyboxbanner.png new file mode 100644 index 00000000..08895537 Binary files /dev/null and b/static/wdwskyboxbanner.png differ