Merge branch 'mastodon-configuration' into 'develop'

Normalize instance configuration for Mastodon

See merge request soapbox-pub/soapbox-fe!1022
improve-ci
Alex Gleason 2022-02-01 15:23:50 +00:00
commit d5ae29bfda
10 zmienionych plików z 465 dodań i 36 usunięć

Wyświetl plik

@ -0,0 +1,43 @@
{
"uri": "animalliberation.social",
"title": "Animal Liberation Network",
"short_description": "",
"description": "Animal Liberation Network is a community for <b>animal activists</b> on the Fediverse. You can connect with other activists through the <b>local timeline</b>, as well as spread your activism to the outside world with the <b>federated timeline</b>.",
"email": "alex@alexgleason.me",
"version": "3.0.0",
"urls": {
"streaming_api": "wss://animalliberation.social"
},
"stats": {
"user_count": 662,
"status_count": 2904,
"domain_count": 4003
},
"thumbnail": "https://animalliberation.social/packs/media/images/preview-9a17d32fc48369e8ccd910a75260e67d.jpg",
"languages": [
"en"
],
"registrations": true,
"approval_required": false,
"contact_account": {
"id": "1",
"username": "alex",
"acct": "alex",
"display_name": "Alex Gleason",
"locked": false,
"bot": false,
"created_at": "2016-11-30T22:19:42.956Z",
"note": "<p>Animal liberation free software Communist</p>",
"url": "https://animalliberation.social/@alex",
"avatar": "https://media.animalliberation.social/accounts/avatars/000/000/001/original/media.jpg",
"avatar_static": "https://media.animalliberation.social/accounts/avatars/000/000/001/original/media.jpg",
"header": "https://media.animalliberation.social/accounts/headers/000/000/001/original/09887023017e02c9.jpg",
"header_static": "https://media.animalliberation.social/accounts/headers/000/000/001/original/09887023017e02c9.jpg",
"followers_count": 236,
"following_count": 83,
"statuses_count": 357,
"last_status_at": "2021-02-20T19:28:24.353Z",
"emojis": [],
"fields": []
}
}

Wyświetl plik

@ -0,0 +1,128 @@
{
"uri": "mastodon.social",
"title": "Mastodon",
"short_description": "Server run by the main developers of the project <img draggable=\"false\" alt=\"🐘\" class=\"emojione\" src=\"https://mastodon.social/emoji/1f418.svg\" /> It is not focused on any particular niche interest - everyone is welcome as long as you follow our code of conduct!",
"description": "Server run by the main developers of the project <img draggable=\"false\" alt=\"🐘\" class=\"emojione\" src=\"https://mastodon.social/emoji/1f418.svg\" /> It is not focused on any particular niche interest - everyone is welcome as long as you follow our code of conduct!",
"email": "staff@mastodon.social",
"version": "3.4.3",
"urls": {
"streaming_api": "wss://mastodon.social"
},
"stats": {
"user_count": 619022,
"status_count": 33914684,
"domain_count": 21524
},
"thumbnail": "https://files.mastodon.social/site_uploads/files/000/000/001/original/vlcsnap-2018-08-27-16h43m11s127.png",
"languages": [
"en"
],
"registrations": true,
"approval_required": false,
"invites_enabled": true,
"configuration": {
"statuses": {
"max_characters": 500,
"max_media_attachments": 4,
"characters_reserved_per_url": 23
},
"media_attachments": {
"supported_mime_types": [
"image/jpeg",
"image/png",
"image/gif",
"video/webm",
"video/mp4",
"video/quicktime",
"video/ogg",
"audio/wave",
"audio/wav",
"audio/x-wav",
"audio/x-pn-wave",
"audio/ogg",
"audio/vorbis",
"audio/mpeg",
"audio/mp3",
"audio/webm",
"audio/flac",
"audio/aac",
"audio/m4a",
"audio/x-m4a",
"audio/mp4",
"audio/3gpp",
"video/x-ms-asf"
],
"image_size_limit": 10485760,
"image_matrix_limit": 16777216,
"video_size_limit": 41943040,
"video_frame_rate_limit": 60,
"video_matrix_limit": 2304000
},
"polls": {
"max_options": 4,
"max_characters_per_option": 50,
"min_expiration": 300,
"max_expiration": 2629746
}
},
"contact_account": {
"id": "1",
"username": "Gargron",
"acct": "Gargron",
"display_name": "Eugen 🎄",
"locked": false,
"bot": false,
"discoverable": true,
"group": false,
"created_at": "2016-03-16T00:00:00.000Z",
"note": "<p>Founder, CEO and lead developer <span class=\"h-card\"><a href=\"https://mastodon.social/@Mastodon\" class=\"u-url mention\">@<span>Mastodon</span></a></span>, Germany.</p>",
"url": "https://mastodon.social/@Gargron",
"avatar": "https://files.mastodon.social/accounts/avatars/000/000/001/original/ccb05a778962e171.png",
"avatar_static": "https://files.mastodon.social/accounts/avatars/000/000/001/original/ccb05a778962e171.png",
"header": "https://files.mastodon.social/accounts/headers/000/000/001/original/3b91c9965d00888b.jpeg",
"header_static": "https://files.mastodon.social/accounts/headers/000/000/001/original/3b91c9965d00888b.jpeg",
"followers_count": 98343,
"following_count": 271,
"statuses_count": 71288,
"last_status_at": "2022-01-31",
"emojis": [],
"fields": [
{
"name": "Patreon",
"value": "<a href=\"https://www.patreon.com/mastodon\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://www.</span><span class=\"\">patreon.com/mastodon</span><span class=\"invisible\"></span></a>",
"verified_at": null
},
{
"name": "Homepage",
"value": "<a href=\"https://zeonfederated.com\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">zeonfederated.com</span><span class=\"invisible\"></span></a>",
"verified_at": "2019-07-15T18:29:57.191+00:00"
}
]
},
"rules": [
{
"id": "1",
"text": "Sexually explicit or violent media must be marked as sensitive when posting"
},
{
"id": "2",
"text": "No racism, sexism, homophobia, transphobia, xenophobia, or casteism"
},
{
"id": "3",
"text": "No incitement of violence or promotion of violent ideologies"
},
{
"id": "4",
"text": "No harassment, dogpiling or doxxing of other users"
},
{
"id": "5",
"text": "No content illegal in Germany"
},
{
"id": "6",
"text": "No spam, advertising or bot accounts"
}
]
}

Wyświetl plik

@ -0,0 +1,131 @@
{
"approval_required": true,
"avatar_upload_limit": 2000000,
"background_image": "https://gleasonator.com/images/city.jpg",
"background_upload_limit": 4000000,
"banner_upload_limit": 4000000,
"description": "Building the next generation of the Fediverse. Speak freely.",
"description_limit": 5000,
"email": "alex@alexgleason.me",
"languages": [
"en"
],
"max_toot_chars": 5000,
"pleroma": {
"metadata": {
"account_activation_required": false,
"birthday_min_age": 0,
"birthday_required": false,
"features": [
"pleroma_api",
"mastodon_api",
"mastodon_api_streaming",
"polls",
"v2_suggestions",
"pleroma_explicit_addressing",
"shareable_emoji_packs",
"multifetch",
"pleroma:api/v1/notifications:include_types_filter",
"quote_posting",
"media_proxy",
"relay",
"pleroma_emoji_reactions",
"pleroma_chat_messages",
"email_list",
"profile_directory"
],
"federation": {
"enabled": true,
"exclusions": false,
"mrf_hashtag": {
"federated_timeline_removal": [],
"reject": [],
"sensitive": [
"nsfw"
]
},
"mrf_policies": [
"TagPolicy",
"SimplePolicy",
"InlineQuotePolicy",
"HashtagPolicy"
],
"mrf_simple": {
"accept": [],
"avatar_removal": [
"pawoo.net",
"sinblr.com",
"dajiaweibo.com",
"baraag.net"
],
"banner_removal": [
"pawoo.net",
"sinblr.com",
"dajiaweibo.com",
"baraag.net"
],
"federated_timeline_removal": [],
"followers_only": [],
"media_nsfw": [],
"media_removal": [
"pawoo.net",
"sinblr.com",
"dajiaweibo.com",
"baraag.net"
],
"reject": [
"solagg.com"
],
"reject_deletes": [],
"report_removal": []
},
"mrf_simple_info": {},
"quarantined_instances": [],
"quarantined_instances_info": {
"quarantined_instances": {}
}
},
"fields_limits": {
"max_fields": 15,
"max_remote_fields": 20,
"name_length": 512,
"value_length": 2048
},
"post_formats": [
"text/plain",
"text/html",
"text/markdown",
"text/bbcode"
],
"privileged_staff": true
},
"stats": {
"mau": 71
},
"vapid_public_key": "BLElLQVJVmY_e4F5JoYxI5jXiVOYNsJ9p-amkykc9NcI-jwa9T1Y2GIbDqbY-HqC6ayPkfW4K4o9vgBFKYmkuS4"
},
"poll_limits": {
"max_expiration": 31536000,
"max_option_chars": 200,
"max_options": 20,
"min_expiration": 0
},
"registrations": true,
"shout_limit": 5000,
"soapbox": {
"version": "1.1.1"
},
"stats": {
"domain_count": 8140,
"status_count": 101956,
"user_count": 421
},
"thumbnail": "https://media.gleasonator.com/c0d38bde6ef0b3baa483f574797662ebd83ef9e1a1162e8e4fcd930bb4b3c068.png",
"title": "Gleasonator",
"upload_limit": 100000000,
"uri": "https://gleasonator.com",
"urls": {
"streaming_api": "wss://gleasonator.com"
},
"version": "2.7.2 (compatible; Pleroma 2.4.51-1129-gf2cfef09-gleasonator)"
}

Wyświetl plik

@ -297,8 +297,7 @@ export function submitComposeFail(error) {
export function uploadCompose(files) {
return function(dispatch, getState) {
if (!isLoggedIn(getState)) return;
const instance = getState().get('instance');
const { attachmentLimit } = getFeatures(instance);
const attachmentLimit = getState().getIn(['instance', 'configuration', 'statuses', 'max_media_attachments']);
const media = getState().getIn(['compose', 'media_attachments']);
const progress = new Array(files.length).fill(0);

Wyświetl plik

@ -199,11 +199,11 @@ class PollForm extends ImmutablePureComponent {
}
const mapStateToProps = state => {
const pollLimits = state.getIn(['instance', 'poll_limits']);
const pollLimits = state.getIn(['instance', 'configuration', 'polls']);
return {
maxOptions: pollLimits.get('max_options'),
maxOptionChars: pollLimits.get('max_option_chars'),
maxOptionChars: pollLimits.get('max_characters_per_option'),
maxExpiration: pollLimits.get('max_expiration'),
minExpiration: pollLimits.get('min_expiration'),
};

Wyświetl plik

@ -27,7 +27,7 @@ const mapStateToProps = state => ({
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
isModalOpen: state.get('modal').modalType === 'COMPOSE',
maxTootChars: state.getIn(['instance', 'max_toot_chars']),
maxTootChars: state.getIn(['instance', 'configuration', 'statuses', 'max_characters']),
scheduledAt: state.getIn(['compose', 'schedule']),
scheduledStatusCount: state.get('scheduled_statuses').size,
});

Wyświetl plik

@ -1,19 +1,114 @@
import { Map as ImmutableMap } from 'immutable';
import { INSTANCE_REMEMBER_SUCCESS } from 'soapbox/actions/instance';
import reducer from '../instance';
describe('instance reducer', () => {
it('should return the initial state', () => {
expect(reducer(undefined, {})).toEqual(ImmutableMap({
max_toot_chars: 500,
description_limit: 1500,
poll_limits: ImmutableMap({
max_expiration: 2629746,
max_option_chars: 25,
max_options: 4,
min_expiration: 300,
configuration: ImmutableMap({
statuses: ImmutableMap({
max_characters: 500,
max_media_attachments: 4,
}),
polls: ImmutableMap({
max_options: 4,
max_characters_per_option: 25,
min_expiration: 300,
max_expiration: 2629746,
}),
}),
version: '0.0.0',
}));
});
describe('INSTANCE_REMEMBER_SUCCESS', () => {
it('normalizes Pleroma instance with Mastodon configuration format', () => {
const action = {
type: INSTANCE_REMEMBER_SUCCESS,
instance: require('soapbox/__fixtures__/pleroma-instance.json'),
};
const result = reducer(undefined, action);
const expected = {
configuration: {
statuses: {
max_characters: 5000,
max_media_attachments: Infinity,
},
polls: {
max_options: 20,
max_characters_per_option: 200,
min_expiration: 0,
max_expiration: 31536000,
},
},
};
expect(result.toJS()).toMatchObject(expected);
});
it('normalizes Mastodon instance with retained configuration', () => {
const action = {
type: INSTANCE_REMEMBER_SUCCESS,
instance: require('soapbox/__fixtures__/mastodon-instance.json'),
};
const result = reducer(undefined, action);
const expected = {
configuration: {
statuses: {
max_characters: 500,
max_media_attachments: 4,
characters_reserved_per_url: 23,
},
media_attachments: {
image_size_limit: 10485760,
image_matrix_limit: 16777216,
video_size_limit: 41943040,
video_frame_rate_limit: 60,
video_matrix_limit: 2304000,
},
polls: {
max_options: 4,
max_characters_per_option: 50,
min_expiration: 300,
max_expiration: 2629746,
},
},
};
expect(result.toJS()).toMatchObject(expected);
});
it('normalizes Mastodon 3.0.0 instance with default configuration', () => {
const action = {
type: INSTANCE_REMEMBER_SUCCESS,
instance: require('soapbox/__fixtures__/mastodon-3.0.0-instance.json'),
};
const result = reducer(undefined, action);
const expected = {
configuration: {
statuses: {
max_characters: 500,
max_media_attachments: 4,
},
polls: {
max_options: 4,
max_characters_per_option: 25,
min_expiration: 300,
max_expiration: 2629746,
},
},
};
expect(result.toJS()).toMatchObject(expected);
});
});
});

Wyświetl plik

@ -4,6 +4,8 @@ import { ADMIN_CONFIG_UPDATE_REQUEST, ADMIN_CONFIG_UPDATE_SUCCESS } from 'soapbo
import { PLEROMA_PRELOAD_IMPORT } from 'soapbox/actions/preload';
import KVStore from 'soapbox/storage/kv_store';
import { ConfigDB } from 'soapbox/utils/config_db';
import { parseVersion, PLEROMA } from 'soapbox/utils/features';
import { isNumber } from 'soapbox/utils/numbers';
import {
INSTANCE_REMEMBER_SUCCESS,
@ -28,21 +30,69 @@ const nodeinfoToInstance = nodeinfo => {
});
};
// Set Mastodon defaults, overridden by Pleroma servers
// Use Mastodon defaults
const initialState = ImmutableMap({
max_toot_chars: 500,
description_limit: 1500,
poll_limits: ImmutableMap({
max_expiration: 2629746,
max_option_chars: 25,
max_options: 4,
min_expiration: 300,
configuration: ImmutableMap({
statuses: ImmutableMap({
max_characters: 500,
max_media_attachments: 4,
}),
polls: ImmutableMap({
max_options: 4,
max_characters_per_option: 25,
min_expiration: 300,
max_expiration: 2629746,
}),
}),
version: '0.0.0',
});
// Build Mastodon configuration from Pleroma instance
const pleromaToMastodonConfig = instance => {
return {
statuses: ImmutableMap({
max_characters: instance.get('max_toot_chars'),
}),
polls: ImmutableMap({
max_options: instance.getIn(['poll_limits', 'max_options']),
max_characters_per_option: instance.getIn(['poll_limits', 'max_option_chars']),
min_expiration: instance.getIn(['poll_limits', 'min_expiration']),
max_expiration: instance.getIn(['poll_limits', 'max_expiration']),
}),
};
};
// Use new value only if old value is undefined
const mergeDefined = (oldVal, newVal) => oldVal === undefined ? newVal : oldVal;
// Get the software's default attachment limit
const getAttachmentLimit = software => software === PLEROMA ? Infinity : 4;
// Normalize instance (Pleroma, Mastodon, etc.) to Mastodon's format
const normalizeInstance = instance => {
const { software } = parseVersion(instance.get('version'));
const mastodonConfig = pleromaToMastodonConfig(instance);
return instance.withMutations(instance => {
// Merge configuration
instance.update('configuration', ImmutableMap(), configuration => (
configuration.mergeDeepWith(mergeDefined, mastodonConfig)
));
// If max attachments isn't set, check the backend software
instance.updateIn(['configuration', 'statuses', 'max_media_attachments'], value => {
return isNumber(value) ? value : getAttachmentLimit(software);
});
// Merge defaults & cleanup
instance.mergeDeepWith(mergeDefined, initialState);
instance.deleteAll(['max_toot_chars', 'poll_limits']);
});
};
const importInstance = (state, instance) => {
return initialState.mergeDeep(instance);
return normalizeInstance(instance);
};
const importNodeinfo = (state, nodeinfo) => {

Wyświetl plik

@ -94,22 +94,6 @@ describe('getFeatures', () => {
});
});
describe('attachmentLimit', () => {
it('is 4 by default', () => {
const instance = ImmutableMap({ version: '3.1.4' });
const features = getFeatures(instance);
expect(features.attachmentLimit).toEqual(4);
});
it('is Infinity for Pleroma', () => {
const instance = ImmutableMap({
version: '2.7.2 (compatible; Pleroma 1.1.50-42-g3d9ac6ae-develop)',
});
const features = getFeatures(instance);
expect(features.attachmentLimit).toEqual(Infinity);
});
});
describe('focalPoint', () => {
it('is true for Mastodon 2.3.0+', () => {
const instance = ImmutableMap({ version: '2.3.0' });

Wyświetl plik

@ -49,7 +49,6 @@ export const getFeatures = createSelector([
]),
emojiReacts: v.software === PLEROMA && gte(v.version, '2.0.0'),
emojiReactsRGI: v.software === PLEROMA && gte(v.version, '2.2.49'),
attachmentLimit: v.software === PLEROMA ? Infinity : 4,
focalPoint: v.software === MASTODON && gte(v.compatVersion, '2.3.0'),
importAPI: v.software === PLEROMA,
importMutes: v.software === PLEROMA && gte(v.version, '2.2.0'),