Merge branch 'friendica' into 'develop'

Friendica support

See merge request soapbox-pub/soapbox!1044
environments/review-develop-3zknud/deployments/2361
marcin mikołajczak 2 years ago
commit cb5702db15

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Admin: redirect the homepage to any URL. - Admin: redirect the homepage to any URL.
- Compatibility: added compatibility with Friendica.
### Changed ### Changed
@ -52,7 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Chats: fix jumpy scrollbar. - Chats: fix jumpy scrollbar.
- Composer: fix alignment of icon in submit button. - Composer: fix alignment of icon in submit button.
- Login: add a border around QR codes. - Login: add a border around QR codes.
- Composer: don't display action button in reply indicator - Composer: don't display action button in reply indicator.
## [3.0.0] - 2022-12-25 ## [3.0.0] - 2022-12-25

@ -1,3 +1,4 @@
import { List as ImmutableList } from 'immutable';
import React, { useState, useEffect, useMemo } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
@ -125,7 +126,7 @@ const accountToCredentials = (account: Account): AccountCredentials => {
display_name: account.display_name, display_name: account.display_name,
note: account.source.get('note'), note: account.source.get('note'),
locked: account.locked, locked: account.locked,
fields_attributes: [...account.source.get<Iterable<AccountCredentialsField>>('fields', []).toJS()], fields_attributes: [...account.source.get<Iterable<AccountCredentialsField>>('fields', ImmutableList()).toJS()],
stranger_notifications: account.getIn(['pleroma', 'notification_settings', 'block_from_strangers']) === true, stranger_notifications: account.getIn(['pleroma', 'notification_settings', 'block_from_strangers']) === true,
accepts_email_list: account.getIn(['pleroma', 'accepts_email_list']) === true, accepts_email_list: account.getIn(['pleroma', 'accepts_email_list']) === true,
hide_followers: hideNetwork, hide_followers: hideNetwork,

@ -140,6 +140,9 @@ export const normalizeInstance = (instance: Record<string, any>) => {
return isNumber(value) ? value : getAttachmentLimit(software); return isNumber(value) ? value : getAttachmentLimit(software);
}); });
// Urls can't be null, fix for Friendica
if (instance.get('urls') === null) instance.delete('urls');
// Normalize version // Normalize version
normalizeVersion(instance); normalizeVersion(instance);
fixTakahe(instance); fixTakahe(instance);

@ -1,6 +1,7 @@
/* eslint sort-keys: "error" */ /* eslint sort-keys: "error" */
import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import semverCoerce from 'semver/functions/coerce';
import gte from 'semver/functions/gte'; import gte from 'semver/functions/gte';
import lt from 'semver/functions/lt'; import lt from 'semver/functions/lt';
import semverParse from 'semver/functions/parse'; import semverParse from 'semver/functions/parse';
@ -16,16 +17,16 @@ const overrides = custom('features');
const any = (arr: Array<any>): boolean => arr.some(Boolean); const any = (arr: Array<any>): boolean => arr.some(Boolean);
/** /**
* Mastodon, the software upon which this is all based. * Friendica, decentralized social platform implementing multiple federation protocols.
* @see {@link https://joinmastodon.org/} * @see {@link https://friendi.ca/}
*/ */
export const MASTODON = 'Mastodon'; export const FRIENDICA = 'Friendica';
/** /**
* Pleroma, a feature-rich alternative written in Elixir. * Mastodon, the software upon which this is all based.
* @see {@link https://pleroma.social/} * @see {@link https://joinmastodon.org/}
*/ */
export const PLEROMA = 'Pleroma'; export const MASTODON = 'Mastodon';
/** /**
* Mitra, a Rust backend with deep Ethereum integrations. * Mitra, a Rust backend with deep Ethereum integrations.
@ -40,23 +41,27 @@ export const MITRA = 'Mitra';
export const PIXELFED = 'Pixelfed'; export const PIXELFED = 'Pixelfed';
/** /**
* Truth Social, the Mastodon fork powering truthsocial.com * Pleroma, a feature-rich alternative written in Elixir.
* @see {@link https://help.truthsocial.com/open-source} * @see {@link https://pleroma.social/}
*/ */
export const TRUTHSOCIAL = 'TruthSocial'; export const PLEROMA = 'Pleroma';
/** /**
* Rebased, the recommended backend for Soapbox. * Takahē, backend with support for serving multiple domains.
* @see {@link https://gitlab.com/soapbox-pub/rebased} * @see {@link https://jointakahe.org/}
*/ */
// NOTE: Rebased is named 'soapbox' for legacy reasons. export const TAKAHE = 'Takahe';
export const REBASED = 'soapbox';
/** /**
* glitch-soc, fork of Mastodon with a number of experimental features. * Truth Social, the Mastodon fork powering truthsocial.com
* @see {@link https://glitch-soc.github.io/docs/} * @see {@link https://help.truthsocial.com/open-source}
*/ */
export const GLITCH = 'glitch'; export const TRUTHSOCIAL = 'TruthSocial';
/**
* Wildebeest, backend running on top of Cloudflare Pages.
*/
export const WILDEBEEST = 'Wildebeest';
/** /**
* Akkoma, a Pleroma fork. * Akkoma, a Pleroma fork.
@ -65,15 +70,17 @@ export const GLITCH = 'glitch';
export const AKKOMA = 'akkoma'; export const AKKOMA = 'akkoma';
/** /**
* Takahē, backend with support for serving multiple domains. * glitch-soc, fork of Mastodon with a number of experimental features.
* @see {@link https://jointakahe.org/} * @see {@link https://glitch-soc.github.io/docs/}
*/ */
export const TAKAHE = 'Takahe'; export const GLITCH = 'glitch';
/** /**
* Wildebeest, backend running on top of Cloudflare Pages. * Rebased, the recommended backend for Soapbox.
* @see {@link https://gitlab.com/soapbox-pub/rebased}
*/ */
export const WILDEBEEST = 'Wildebeest'; // NOTE: Rebased is named 'soapbox' for legacy reasons.
export const REBASED = 'soapbox';
/** Parse features for the given instance */ /** Parse features for the given instance */
const getInstanceFeatures = (instance: Instance) => { const getInstanceFeatures = (instance: Instance) => {
@ -207,6 +214,7 @@ const getInstanceFeatures = (instance: Instance) => {
* @see GET /api/v1/bookmarks * @see GET /api/v1/bookmarks
*/ */
bookmarks: any([ bookmarks: any([
v.software === FRIENDICA,
v.software === MASTODON && gte(v.compatVersion, '3.1.0'), v.software === MASTODON && gte(v.compatVersion, '3.1.0'),
v.software === PLEROMA && gte(v.version, '0.9.9'), v.software === PLEROMA && gte(v.version, '0.9.9'),
v.software === PIXELFED, v.software === PIXELFED,
@ -301,6 +309,7 @@ const getInstanceFeatures = (instance: Instance) => {
* @see {@link https://docs.joinmastodon.org/methods/timelines/conversations/} * @see {@link https://docs.joinmastodon.org/methods/timelines/conversations/}
*/ */
conversations: any([ conversations: any([
v.software === FRIENDICA,
v.software === MASTODON && gte(v.compatVersion, '2.6.0'), v.software === MASTODON && gte(v.compatVersion, '2.6.0'),
v.software === PLEROMA && gte(v.version, '0.9.9'), v.software === PLEROMA && gte(v.version, '0.9.9'),
v.software === PIXELFED, v.software === PIXELFED,
@ -312,6 +321,7 @@ const getInstanceFeatures = (instance: Instance) => {
* @see GET /api/v1/timelines/direct * @see GET /api/v1/timelines/direct
*/ */
directTimeline: any([ directTimeline: any([
v.software === FRIENDICA,
v.software === MASTODON && lt(v.compatVersion, '3.0.0'), v.software === MASTODON && lt(v.compatVersion, '3.0.0'),
v.software === PLEROMA && gte(v.version, '0.9.9'), v.software === PLEROMA && gte(v.version, '0.9.9'),
]), ]),
@ -321,6 +331,7 @@ const getInstanceFeatures = (instance: Instance) => {
* @see PATCH /api/v1/accounts/update_credentials * @see PATCH /api/v1/accounts/update_credentials
*/ */
editProfile: any([ editProfile: any([
v.software === FRIENDICA,
v.software === MASTODON, v.software === MASTODON,
v.software === MITRA, v.software === MITRA,
v.software === PIXELFED, v.software === PIXELFED,
@ -479,6 +490,7 @@ const getInstanceFeatures = (instance: Instance) => {
* @see GET /api/v1/timelines/list/:list_id * @see GET /api/v1/timelines/list/:list_id
*/ */
lists: any([ lists: any([
v.software === FRIENDICA,
v.software === MASTODON && gte(v.compatVersion, '2.1.0'), v.software === MASTODON && gte(v.compatVersion, '2.1.0'),
v.software === PLEROMA && gte(v.version, '0.9.9'), v.software === PLEROMA && gte(v.version, '0.9.9'),
]), ]),
@ -592,6 +604,7 @@ const getInstanceFeatures = (instance: Instance) => {
* @see {@link https://docs.joinmastodon.org/methods/instance/directory/} * @see {@link https://docs.joinmastodon.org/methods/instance/directory/}
*/ */
profileDirectory: any([ profileDirectory: any([
v.software === FRIENDICA,
v.software === MASTODON && gte(v.compatVersion, '3.0.0'), v.software === MASTODON && gte(v.compatVersion, '3.0.0'),
features.includes('profile_directory'), features.includes('profile_directory'),
]), ]),
@ -611,6 +624,7 @@ const getInstanceFeatures = (instance: Instance) => {
* @see GET /api/v1/timelines/public * @see GET /api/v1/timelines/public
*/ */
publicTimeline: any([ publicTimeline: any([
v.software === FRIENDICA,
v.software === MASTODON, v.software === MASTODON,
v.software === PLEROMA, v.software === PLEROMA,
v.software === TAKAHE, v.software === TAKAHE,
@ -736,6 +750,7 @@ const getInstanceFeatures = (instance: Instance) => {
* @see GET /api/v2/suggestions * @see GET /api/v2/suggestions
*/ */
suggestionsV2: any([ suggestionsV2: any([
v.software === FRIENDICA,
v.software === MASTODON && gte(v.compatVersion, '3.4.0'), v.software === MASTODON && gte(v.compatVersion, '3.4.0'),
v.software === TRUTHSOCIAL, v.software === TRUTHSOCIAL,
features.includes('v2_suggestions'), features.includes('v2_suggestions'),
@ -816,8 +831,9 @@ export const parseVersion = (version: string): Backend => {
const regex = /^([\w+.]*)(?: \(compatible; ([\w]*) (.*)\))?$/; const regex = /^([\w+.]*)(?: \(compatible; ([\w]*) (.*)\))?$/;
const match = regex.exec(version); const match = regex.exec(version);
const semver = match ? semverParse(match[3] || match[1]) : null; const semverString = match && (match[3] || match[1]);
const compat = match ? semverParse(match[1]) : null; const semver = match ? semverParse(semverString) || semverCoerce(semverString) : null;
const compat = match ? semverParse(match[1]) || semverCoerce(match[1]) : null;
if (match && semver && compat) { if (match && semver && compat) {
return { return {

@ -1,6 +1,6 @@
/** Convert HTML to a plaintext representation, preserving whitespace. */ /** Convert HTML to a plaintext representation, preserving whitespace. */
// NB: This function can still return unsafe HTML // NB: This function can still return unsafe HTML
export const unescapeHTML = (html: string): string => { export const unescapeHTML = (html: string = ''): string => {
const wrapper = document.createElement('div'); const wrapper = document.createElement('div');
wrapper.innerHTML = html.replace(/<br\s*\/?>/g, '\n').replace(/<\/p><[^>]*>/g, '\n\n').replace(/<[^>]*>/g, ''); wrapper.innerHTML = html.replace(/<br\s*\/?>/g, '\n').replace(/<\/p><[^>]*>/g, '\n\n').replace(/<[^>]*>/g, '');
return wrapper.textContent || ''; return wrapper.textContent || '';

@ -175,7 +175,7 @@
"sass": "^1.20.3", "sass": "^1.20.3",
"sass-loader": "^13.0.0", "sass-loader": "^13.0.0",
"seedrandom": "^3.0.5", "seedrandom": "^3.0.5",
"semver": "^7.3.2", "semver": "^7.3.8",
"stringz": "^2.0.0", "stringz": "^2.0.0",
"substring-trie": "^1.0.2", "substring-trie": "^1.0.2",
"terser-webpack-plugin": "^5.2.3", "terser-webpack-plugin": "^5.2.3",

@ -10220,7 +10220,7 @@ semver@7.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@7.3.5, semver@7.x, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: semver@7.3.5, semver@7.x, semver@^7.3.4, semver@^7.3.5:
version "7.3.5" version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==

Loading…
Cancel
Save