Merge remote-tracking branch 'origin/develop' into typescript
This commit is contained in:
commit
2b235a80e4
28
.eslintrc.js
28
.eslintrc.js
|
@ -69,6 +69,10 @@ module.exports = {
|
|||
eqeqeq: 'error',
|
||||
indent: ['error', 2],
|
||||
'jsx-quotes': ['error', 'prefer-single'],
|
||||
'key-spacing': [
|
||||
'error',
|
||||
{ mode: 'minimum' },
|
||||
],
|
||||
'no-catch-shadow': 'error',
|
||||
'no-cond-assign': 'error',
|
||||
'no-console': [
|
||||
|
@ -111,6 +115,13 @@ module.exports = {
|
|||
'prefer-const': 'error',
|
||||
quotes: ['error', 'single'],
|
||||
semi: 'error',
|
||||
'space-unary-ops': [
|
||||
'error',
|
||||
{
|
||||
words: true,
|
||||
nonwords: false,
|
||||
},
|
||||
],
|
||||
strict: 'off',
|
||||
'valid-typeof': 'error',
|
||||
|
||||
|
@ -212,6 +223,23 @@ module.exports = {
|
|||
],
|
||||
'import/no-unresolved': 'error',
|
||||
'import/no-webpack-loader-syntax': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
'internal',
|
||||
'parent',
|
||||
'sibling',
|
||||
'index',
|
||||
'object',
|
||||
'type',
|
||||
],
|
||||
'newlines-between': 'always',
|
||||
alphabetize: { order: 'asc' },
|
||||
},
|
||||
],
|
||||
|
||||
'promise/catch-or-return': 'error',
|
||||
|
||||
|
|
|
@ -12,3 +12,12 @@ yarn-error.log*
|
|||
/static-test/
|
||||
/public/
|
||||
/dist/
|
||||
|
||||
.idea
|
||||
.DS_Store
|
||||
|
||||
# surge.sh
|
||||
CNAME
|
||||
AUTH
|
||||
CORS
|
||||
ROUTER
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
inkscape:export-ydpi="240"
|
||||
inkscape:export-xdpi="240"
|
||||
inkscape:export-filename="/home/alex/Projects/docker-tribe/avi.png"
|
||||
sodipodi:docname="avatar.svg"
|
||||
width="120"
|
||||
height="120"
|
||||
viewBox="0 0 31.75 31.750001"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1019"
|
||||
inkscape:window-width="1920"
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="4.3194033"
|
||||
inkscape:cx="79.987899"
|
||||
inkscape:cy="64.129228"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0.80272198,1.2346106)">
|
||||
<rect
|
||||
style="fill:#10b3d1;fill-opacity:1;stroke:none;stroke-width:1.53052;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="rect853"
|
||||
width="31.75"
|
||||
height="31.75"
|
||||
x="-0.80272198"
|
||||
y="-1.2346106" />
|
||||
<path
|
||||
id="path857"
|
||||
style="fill:#f4962a;fill-opacity:1;stroke:#000000;stroke-width:1.48265;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 15.051525,3.9344041 A 10.434797,10.434797 0 0 0 4.6372555,14.368944 a 10.434797,10.434797 0 0 0 0,0.02075 v 0.03137 a 1.7839264,2.3625556 0 0 0 -0.9503056,-0.363423 1.7839264,2.3625556 0 0 0 -1.7838141,2.362493 1.7839264,2.3625556 0 0 0 1.7838141,2.362491 1.7839264,2.3625556 0 0 0 0.9503056,-0.363423 v 23.74268 H 25.507302 v -23.74268 a 1.7839264,2.3625556 0 0 0 0.950305,0.363423 1.7839264,2.3625556 0 0 0 1.783814,-2.362491 1.7839264,2.3625556 0 0 0 -1.783814,-2.362493 1.7839264,2.3625556 0 0 0 -0.950305,0.362941 v -0.05164 A 10.434797,10.434797 0 0 0 15.072278,3.9344041 a 10.434797,10.434797 0 0 0 -0.02075,0 z" />
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.900495;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path881-6"
|
||||
cx="11.218504"
|
||||
cy="13.292331"
|
||||
r="1.3086123" />
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.900495;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path881-7"
|
||||
cx="18.926052"
|
||||
cy="13.292331"
|
||||
r="1.3086123" />
|
||||
<ellipse
|
||||
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.88959;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path917"
|
||||
cx="15.072279"
|
||||
cy="18.343904"
|
||||
rx="7.1666903"
|
||||
ry="4.0659413" />
|
||||
<path
|
||||
id="path957"
|
||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.88959;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 21.900069,17.108362 a 7.1666903,4.0659412 0 0 1 -6.82779,2.8304 7.1666903,4.0659412 0 0 1 -6.8277959,-2.830413" />
|
||||
<path
|
||||
id="path1003"
|
||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.88959;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
inkscape:transform-center-y="-0.79831289"
|
||||
d="m 13.062455,16.997512 c 0.457808,-1.227486 1.336486,-2.475611 2.009822,-2.475611 0.673338,0 1.552013,1.248125 2.009824,2.475611" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 24.842957,6.3249745 c -1.070225,-0.4344716 -2.309802,0.1182843 -2.464817,1.0590207 0,0 -1.627232,-1.9230616 1.219705,-3.5847621"
|
||||
id="path1030"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.8 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95 95" width="100" height="100"><path d="M94.909 19.374C94.909 8.674 86.235 0 75.534 0c-10.647 0-19.28 8.591-19.365 19.217l-15.631 2.09c-1.961-6.007-7.598-10.35-14.258-10.35-8.284 0-15.002 6.716-15.002 15.002 0 6.642 4.321 12.267 10.303 14.24l-2.205 16.056c-10.66.049-19.285 8.7-19.285 19.37C.091 86.325 8.765 95 19.466 95c10.677 0 19.332-8.638 19.37-19.304l18.093-2.501c1.979 5.972 7.598 10.285 14.234 10.285 8.284 0 15.002-6.716 15.002-15.002 0-6.891-4.652-12.682-10.983-14.441l1.365-15.339c10.229-.53 18.363-8.966 18.363-19.324zM56.194 67.8l-18.116 2.505a19.39 19.39 0 0 0-13.312-13.3l2.205-16.077a14.98 14.98 0 0 0 14.27-14.222l15.655-2.094c1.894 6.757 7.351 12.009 14.225 13.612l-1.365 15.322c-7.4.688-13.224 6.753-13.562 14.254z" fill="#0482d8"/></svg>
|
After Width: | Height: | Size: 812 B |
|
@ -5,6 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, user-scalable=no">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link href="/manifest.json" rel="manifest">
|
||||
<!--server-generated-meta-->
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
</head>
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
{
|
||||
"id": "107673570598783346",
|
||||
"created_at": "2022-01-23T20:05:01.372Z",
|
||||
"in_reply_to_id": null,
|
||||
"in_reply_to_account_id": null,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"visibility": "public",
|
||||
"language": "en",
|
||||
"uri": "https://fedibird.com/users/alex/statuses/107673570598783346",
|
||||
"url": "https://fedibird.com/@alex/107673570598783346",
|
||||
"replies_count": 0,
|
||||
"reblogs_count": 0,
|
||||
"favourites_count": 0,
|
||||
"emoji_reactions_count": 0,
|
||||
"emoji_reactions": [],
|
||||
"content": "<p>test quote of a quote<span class=\"quote-inline\"><br/>QT: <a class=\"status-url-link\" data-status-account-acct=\"alex\" data-status-id=\"107673570082615319\" href=\"https://fedibird.com/@alex/107673570082615319\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">fedibird.com/@alex/10767357008</span><span class=\"invisible\">2615319</span></a></span></p>",
|
||||
"quote_id": "107673570082615319",
|
||||
"reblog": null,
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"account": {
|
||||
"id": "66768",
|
||||
"username": "alex",
|
||||
"acct": "alex",
|
||||
"display_name": "",
|
||||
"locked": false,
|
||||
"bot": false,
|
||||
"discoverable": null,
|
||||
"group": false,
|
||||
"created_at": "2020-01-27T00:00:00.000Z",
|
||||
"note": "<p></p>",
|
||||
"url": "https://fedibird.com/@alex",
|
||||
"avatar": "https://fedibird.com/avatars/original/missing.png",
|
||||
"avatar_static": "https://fedibird.com/avatars/original/missing.png",
|
||||
"header": "https://fedibird.com/headers/original/missing.png",
|
||||
"header_static": "https://fedibird.com/headers/original/missing.png",
|
||||
"followers_count": 0,
|
||||
"following_count": 1,
|
||||
"subscribing_count": 0,
|
||||
"statuses_count": 3,
|
||||
"last_status_at": "2022-01-23",
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
},
|
||||
"media_attachments": [],
|
||||
"mentions": [],
|
||||
"tags": [],
|
||||
"emojis": [],
|
||||
"card": null,
|
||||
"poll": null,
|
||||
"quote": {
|
||||
"id": "107673570082615319",
|
||||
"created_at": "2022-01-23T20:04:53.494Z",
|
||||
"in_reply_to_id": null,
|
||||
"in_reply_to_account_id": null,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"visibility": "public",
|
||||
"language": "en",
|
||||
"uri": "https://fedibird.com/users/alex/statuses/107673570082615319",
|
||||
"url": "https://fedibird.com/@alex/107673570082615319",
|
||||
"replies_count": 0,
|
||||
"reblogs_count": 0,
|
||||
"favourites_count": 0,
|
||||
"emoji_reactions_count": 0,
|
||||
"emoji_reactions": [],
|
||||
"content": "<p>test quote<span class=\"quote-inline\"><br/>QT: <a class=\"status-url-link\" data-status-account-acct=\"alex\" data-status-id=\"107673569214329435\" href=\"https://fedibird.com/@alex/107673569214329435\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">fedibird.com/@alex/10767356921</span><span class=\"invisible\">4329435</span></a></span></p>",
|
||||
"quote_id": "107673569214329435",
|
||||
"quote": null,
|
||||
"reblog": null,
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"account": {
|
||||
"id": "66768",
|
||||
"username": "alex",
|
||||
"acct": "alex",
|
||||
"display_name": "",
|
||||
"locked": false,
|
||||
"bot": false,
|
||||
"discoverable": null,
|
||||
"group": false,
|
||||
"created_at": "2020-01-27T00:00:00.000Z",
|
||||
"note": "<p></p>",
|
||||
"url": "https://fedibird.com/@alex",
|
||||
"avatar": "https://fedibird.com/avatars/original/missing.png",
|
||||
"avatar_static": "https://fedibird.com/avatars/original/missing.png",
|
||||
"header": "https://fedibird.com/headers/original/missing.png",
|
||||
"header_static": "https://fedibird.com/headers/original/missing.png",
|
||||
"followers_count": 0,
|
||||
"following_count": 1,
|
||||
"subscribing_count": 0,
|
||||
"statuses_count": 3,
|
||||
"last_status_at": "2022-01-23",
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
},
|
||||
"media_attachments": [],
|
||||
"mentions": [],
|
||||
"tags": [],
|
||||
"emojis": [],
|
||||
"card": null,
|
||||
"poll": null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
"id": "107673570082615319",
|
||||
"created_at": "2022-01-23T20:04:53.494Z",
|
||||
"in_reply_to_id": null,
|
||||
"in_reply_to_account_id": null,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"visibility": "public",
|
||||
"language": "en",
|
||||
"uri": "https://fedibird.com/users/alex/statuses/107673570082615319",
|
||||
"url": "https://fedibird.com/@alex/107673570082615319",
|
||||
"replies_count": 0,
|
||||
"reblogs_count": 0,
|
||||
"favourites_count": 0,
|
||||
"emoji_reactions_count": 0,
|
||||
"emoji_reactions": [],
|
||||
"content": "<p>test quote<span class=\"quote-inline\"><br/>QT: <a class=\"status-url-link\" data-status-account-acct=\"alex\" data-status-id=\"107673569214329435\" href=\"https://fedibird.com/@alex/107673569214329435\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">fedibird.com/@alex/10767356921</span><span class=\"invisible\">4329435</span></a></span></p>",
|
||||
"quote_id": "107673569214329435",
|
||||
"reblog": null,
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"account": {
|
||||
"id": "66768",
|
||||
"username": "alex",
|
||||
"acct": "alex",
|
||||
"display_name": "",
|
||||
"locked": false,
|
||||
"bot": false,
|
||||
"discoverable": null,
|
||||
"group": false,
|
||||
"created_at": "2020-01-27T00:00:00.000Z",
|
||||
"note": "<p></p>",
|
||||
"url": "https://fedibird.com/@alex",
|
||||
"avatar": "https://fedibird.com/avatars/original/missing.png",
|
||||
"avatar_static": "https://fedibird.com/avatars/original/missing.png",
|
||||
"header": "https://fedibird.com/headers/original/missing.png",
|
||||
"header_static": "https://fedibird.com/headers/original/missing.png",
|
||||
"followers_count": 0,
|
||||
"following_count": 1,
|
||||
"subscribing_count": 0,
|
||||
"statuses_count": 3,
|
||||
"last_status_at": "2022-01-23",
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
},
|
||||
"media_attachments": [],
|
||||
"mentions": [],
|
||||
"tags": [],
|
||||
"emojis": [],
|
||||
"card": null,
|
||||
"poll": null,
|
||||
"quote": {
|
||||
"id": "107673569214329435",
|
||||
"created_at": "2022-01-23T20:04:40.249Z",
|
||||
"in_reply_to_id": null,
|
||||
"in_reply_to_account_id": null,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"visibility": "public",
|
||||
"language": "en",
|
||||
"uri": "https://fedibird.com/users/alex/statuses/107673569214329435",
|
||||
"url": "https://fedibird.com/@alex/107673569214329435",
|
||||
"replies_count": 0,
|
||||
"reblogs_count": 0,
|
||||
"favourites_count": 0,
|
||||
"emoji_reactions_count": 0,
|
||||
"emoji_reactions": [],
|
||||
"content": "<p>test post</p>",
|
||||
"quote": null,
|
||||
"reblog": null,
|
||||
"application": {
|
||||
"name": "Web",
|
||||
"website": null
|
||||
},
|
||||
"account": {
|
||||
"id": "66768",
|
||||
"username": "alex",
|
||||
"acct": "alex",
|
||||
"display_name": "",
|
||||
"locked": false,
|
||||
"bot": false,
|
||||
"discoverable": null,
|
||||
"group": false,
|
||||
"created_at": "2020-01-27T00:00:00.000Z",
|
||||
"note": "<p></p>",
|
||||
"url": "https://fedibird.com/@alex",
|
||||
"avatar": "https://fedibird.com/avatars/original/missing.png",
|
||||
"avatar_static": "https://fedibird.com/avatars/original/missing.png",
|
||||
"header": "https://fedibird.com/headers/original/missing.png",
|
||||
"header_static": "https://fedibird.com/headers/original/missing.png",
|
||||
"followers_count": 0,
|
||||
"following_count": 1,
|
||||
"subscribing_count": 0,
|
||||
"statuses_count": 3,
|
||||
"last_status_at": "2022-01-23",
|
||||
"emojis": [],
|
||||
"fields": []
|
||||
},
|
||||
"media_attachments": [],
|
||||
"mentions": [],
|
||||
"tags": [],
|
||||
"emojis": [],
|
||||
"card": null,
|
||||
"poll": null
|
||||
}
|
||||
}
|
|
@ -106,7 +106,7 @@
|
|||
"confirmations.delete_list.confirm": "Delete",
|
||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||
"confirmations.domain_block.confirm": "Hide entire domain",
|
||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications.",
|
||||
"confirmations.mute.confirm": "Mute",
|
||||
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
|
@ -584,7 +584,7 @@
|
|||
"confirmations.delete_list.confirm": "Delete",
|
||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||
"confirmations.domain_block.confirm": "Hide entire domain",
|
||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications.",
|
||||
"confirmations.mute.confirm": "Mute",
|
||||
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
|
|
|
@ -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": []
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
[
|
||||
{
|
||||
"id": "017ed503-bc96-301a-e871-2c23b30ddd05",
|
||||
"uri": "https://mitra.social/objects/017ed503-bc96-301a-e871-2c23b30ddd05",
|
||||
"created_at": "2022-02-07T16:28:18.966874Z",
|
||||
"account": {
|
||||
"id": "017ed4f9-c121-2ae6-0805-15516cce02c3",
|
||||
"username": "alex",
|
||||
"acct": "alex",
|
||||
"url": "https://mitra.social/users/alex",
|
||||
"display_name": null,
|
||||
"created_at": "2022-02-07T16:17:24.769229Z",
|
||||
"note": null,
|
||||
"avatar": null,
|
||||
"header": null,
|
||||
"fields": [],
|
||||
"followers_count": 1,
|
||||
"following_count": 1,
|
||||
"statuses_count": 3,
|
||||
"source": null,
|
||||
"wallet_address": null
|
||||
},
|
||||
"content": "<span class=\"h-card\"><a class=\"u-url mention\" href=\"https://mitra.social/users/silverpill\">@silverpill</a></span> sup!",
|
||||
"in_reply_to_id": null,
|
||||
"reblog": null,
|
||||
"visibility": "public",
|
||||
"replies_count": 1,
|
||||
"favourites_count": 0,
|
||||
"reblogs_count": 0,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"id": "dd4ebc18-269d-4c7b-a310-03d29c6ab551",
|
||||
"username": "silverpill",
|
||||
"acct": "silverpill",
|
||||
"url": "https://mitra.social/users/silverpill"
|
||||
}
|
||||
],
|
||||
"tags": [],
|
||||
"favourited": false,
|
||||
"reblogged": false,
|
||||
"ipfs_cid": null,
|
||||
"token_id": null,
|
||||
"token_tx_id": null
|
||||
},
|
||||
{
|
||||
"id": "017ed505-5926-392f-256a-f86d5075df70",
|
||||
"uri": "https://mitra.social/objects/017ed505-5926-392f-256a-f86d5075df70",
|
||||
"created_at": "2022-02-07T16:30:04.582771Z",
|
||||
"account": {
|
||||
"id": "dd4ebc18-269d-4c7b-a310-03d29c6ab551",
|
||||
"username": "silverpill",
|
||||
"acct": "silverpill",
|
||||
"url": "https://mitra.social/users/silverpill",
|
||||
"display_name": "silverpill",
|
||||
"created_at": "2021-11-06T21:08:57.441927Z",
|
||||
"note": "Admin of <a href=\"https://mitra.social/\" rel=\"noopener noreferrer\">mitra.social</a> instance. It is running experimental ActivityPub server <a href=\"https://codeberg.org/silverpill/mitra\" rel=\"noopener noreferrer\">Mitra</a>.",
|
||||
"avatar": "https://mitra.social/media/6a785bf7dd05f61c3590e8935aa49156a499ac30fd1e402f79e7e164adb36e2c.png",
|
||||
"header": null,
|
||||
"fields": [
|
||||
{
|
||||
"name": "Matrix",
|
||||
"value": "@silverpill:poa.st"
|
||||
},
|
||||
{
|
||||
"name": "Alt",
|
||||
"value": "@silverpill@poa.st"
|
||||
},
|
||||
{
|
||||
"name": "Code",
|
||||
"value": "<a href=\"https://codeberg.org/silverpill/\" rel=\"noopener noreferrer\">https://codeberg.org/silverpill/</a>"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "884y9LmsWY7PQNsyR7bJy1dvj91tuF5spVabyCnPk4KfQtSuzFbQobTFC7xSemJgVW1FWAwnJbjTZX5zZWbBrfkv62DB62d"
|
||||
}
|
||||
],
|
||||
"followers_count": 27,
|
||||
"following_count": 15,
|
||||
"statuses_count": 110,
|
||||
"source": null,
|
||||
"wallet_address": null
|
||||
},
|
||||
"content": "<span class=\"h-card\"><a class=\"u-url mention\" href=\"https://mitra.social/users/alex\">@alex</a></span> welcome",
|
||||
"in_reply_to_id": "017ed503-bc96-301a-e871-2c23b30ddd05",
|
||||
"reblog": null,
|
||||
"visibility": "public",
|
||||
"replies_count": 0,
|
||||
"favourites_count": 1,
|
||||
"reblogs_count": 0,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"id": "017ed4f9-c121-2ae6-0805-15516cce02c3",
|
||||
"username": "alex",
|
||||
"acct": "alex",
|
||||
"url": "https://mitra.social/users/alex"
|
||||
}
|
||||
],
|
||||
"tags": [],
|
||||
"favourited": true,
|
||||
"reblogged": false,
|
||||
"ipfs_cid": null,
|
||||
"token_id": null,
|
||||
"token_tx_id": null
|
||||
}
|
||||
]
|
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
"id": "017eeb0e-e5e7-98fe-6b2b-ad02349251fb",
|
||||
"uri": "https://gleasonator.com/objects/aa5e66c9-0a10-4167-9c80-f40d9574aaec",
|
||||
"created_at": "2022-02-11T23:11:59.891770Z",
|
||||
"account": {
|
||||
"id": "8fe4d6ed-3a99-43e1-a7d4-66b4e635f756",
|
||||
"username": "alex",
|
||||
"acct": "alex@gleasonator.com",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"display_name": "Alex Gleason",
|
||||
"created_at": "2021-11-14T17:01:17.446307Z",
|
||||
"note": "I create Fediverse software that empowers people online.<br><br>I'm vegan btw<br><br>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"avatar": "https://mitra.social/media/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"header": "https://mitra.social/media/bdfb009adac0e31257e9fe527d3844a7234cc71f6e06dff2bec94354639555dd.png",
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"noopener noreferrer\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"noopener noreferrer\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "<a href=\"https://paypal.me/gleasonator\" rel=\"noopener noreferrer\">https://paypal.me/gleasonator</a>"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"followers_count": 2,
|
||||
"following_count": 2,
|
||||
"statuses_count": 970,
|
||||
"source": null,
|
||||
"wallet_address": null
|
||||
},
|
||||
"content": "<p>Test</p>",
|
||||
"in_reply_to_id": null,
|
||||
"reblog": null,
|
||||
"visibility": "public",
|
||||
"replies_count": 0,
|
||||
"favourites_count": 0,
|
||||
"reblogs_count": 0,
|
||||
"media_attachments": [
|
||||
{
|
||||
"id": "017eeb0e-e5df-30a4-77a7-a929145cb836",
|
||||
"type": "image",
|
||||
"url": "https://mitra.social/media/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png"
|
||||
},
|
||||
{
|
||||
"id": "017eeb0e-e5e4-2a48-2889-afdebf368a54",
|
||||
"type": "unknown",
|
||||
"url": "https://mitra.social/media/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac"
|
||||
},
|
||||
{
|
||||
"id": "017eeb0e-e5e5-79fd-6054-8b6869b1db49",
|
||||
"type": "unknown",
|
||||
"url": "https://mitra.social/media/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.oga"
|
||||
},
|
||||
{
|
||||
"id": "017eeb0e-e5e6-c416-a444-21e560c47839",
|
||||
"type": "unknown",
|
||||
"url": "https://mitra.social/media/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
"tags": [],
|
||||
"favourited": false,
|
||||
"reblogged": false,
|
||||
"ipfs_cid": null,
|
||||
"token_id": null,
|
||||
"token_tx_id": null
|
||||
}
|
|
@ -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)"
|
||||
}
|
|
@ -0,0 +1,371 @@
|
|||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"avatar_static": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "<a href=\"https://paypal.me/gleasonator\" rel=\"ugc\">https://paypal.me/gleasonator</a>"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"followers_count": 2220,
|
||||
"following_count": 1544,
|
||||
"fqn": "alex@gleasonator.com",
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"last_status_at": "2022-01-24T21:02:44",
|
||||
"locked": false,
|
||||
"note": "I create Fediverse software that empowers people online.<br/><br/>I'm vegan btw<br/><br/>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"also_known_as": [],
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_confirmed": true,
|
||||
"is_moderator": false,
|
||||
"is_suggested": true,
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": []
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "https://paypal.me/gleasonator"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"note": "I create Fediverse software that empowers people online.\r\n\r\nI'm vegan btw\r\n\r\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false
|
||||
},
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 23004,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Soapbox FE",
|
||||
"website": "https://soapbox.pub/"
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>Quote of quote post</p>",
|
||||
"created_at": "2022-01-24T21:02:43.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "AFmFNKmfrR9CxtV01g",
|
||||
"in_reply_to_account_id": null,
|
||||
"in_reply_to_id": null,
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "Quote of quote post"
|
||||
},
|
||||
"conversation_id": "AFmFNKkXzLRirIVIi8",
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": null,
|
||||
"local": true,
|
||||
"parent_visible": false,
|
||||
"pinned_at": null,
|
||||
"quote": {
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"avatar_static": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "<a href=\"https://paypal.me/gleasonator\" rel=\"ugc\">https://paypal.me/gleasonator</a>"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"followers_count": 2220,
|
||||
"following_count": 1544,
|
||||
"fqn": "alex@gleasonator.com",
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"last_status_at": "2022-01-24T21:02:44",
|
||||
"locked": false,
|
||||
"note": "I create Fediverse software that empowers people online.<br/><br/>I'm vegan btw<br/><br/>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"also_known_as": [],
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_confirmed": true,
|
||||
"is_moderator": false,
|
||||
"is_suggested": true,
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": []
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "https://paypal.me/gleasonator"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"note": "I create Fediverse software that empowers people online.\r\n\r\nI'm vegan btw\r\n\r\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false
|
||||
},
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 23004,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Soapbox FE",
|
||||
"website": "https://soapbox.pub/"
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>Quote post</p>",
|
||||
"created_at": "2022-01-24T21:02:34.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "AFmFMSpITT9xcOJKcK",
|
||||
"in_reply_to_account_id": null,
|
||||
"in_reply_to_id": null,
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "Quote post"
|
||||
},
|
||||
"conversation_id": "AFmFMSnWa3k3WtTur2",
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [
|
||||
{
|
||||
"count": 1,
|
||||
"me": false,
|
||||
"name": "👍"
|
||||
}
|
||||
],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": null,
|
||||
"local": true,
|
||||
"parent_visible": false,
|
||||
"pinned_at": null,
|
||||
"quote": null,
|
||||
"quote_url": "https://gleasonator.com/objects/4f35159c-3794-4037-9269-a7c84f7137c7",
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/54d93075-7d04-4016-a128-81f3843bca79",
|
||||
"url": "https://gleasonator.com/notice/AFmFMSpITT9xcOJKcK",
|
||||
"visibility": "public"
|
||||
},
|
||||
"quote_url": "https://gleasonator.com/objects/54d93075-7d04-4016-a128-81f3843bca79",
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 1,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/1e2cfb5a-ece5-42df-9ec1-13e5de6d9f5b",
|
||||
"url": "https://gleasonator.com/notice/AFmFNKmfrR9CxtV01g",
|
||||
"visibility": "public"
|
||||
}
|
|
@ -0,0 +1,364 @@
|
|||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"avatar_static": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "<a href=\"https://paypal.me/gleasonator\" rel=\"ugc\">https://paypal.me/gleasonator</a>"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"followers_count": 2220,
|
||||
"following_count": 1544,
|
||||
"fqn": "alex@gleasonator.com",
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"last_status_at": "2022-01-24T21:02:44",
|
||||
"locked": false,
|
||||
"note": "I create Fediverse software that empowers people online.<br/><br/>I'm vegan btw<br/><br/>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"also_known_as": [],
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_confirmed": true,
|
||||
"is_moderator": false,
|
||||
"is_suggested": true,
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": []
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "https://paypal.me/gleasonator"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"note": "I create Fediverse software that empowers people online.\r\n\r\nI'm vegan btw\r\n\r\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false
|
||||
},
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 23004,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Soapbox FE",
|
||||
"website": "https://soapbox.pub/"
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>Quote post</p>",
|
||||
"created_at": "2022-01-24T21:02:34.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "AFmFMSpITT9xcOJKcK",
|
||||
"in_reply_to_account_id": null,
|
||||
"in_reply_to_id": null,
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "Quote post"
|
||||
},
|
||||
"conversation_id": "AFmFMSnWa3k3WtTur2",
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [
|
||||
{
|
||||
"count": 1,
|
||||
"me": false,
|
||||
"name": "👍"
|
||||
}
|
||||
],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": null,
|
||||
"local": true,
|
||||
"parent_visible": false,
|
||||
"pinned_at": null,
|
||||
"quote": {
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"avatar_static": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "<a href=\"https://paypal.me/gleasonator\" rel=\"ugc\">https://paypal.me/gleasonator</a>"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"followers_count": 2220,
|
||||
"following_count": 1544,
|
||||
"fqn": "alex@gleasonator.com",
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"last_status_at": "2022-01-24T21:02:44",
|
||||
"locked": false,
|
||||
"note": "I create Fediverse software that empowers people online.<br/><br/>I'm vegan btw<br/><br/>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"also_known_as": [],
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_confirmed": true,
|
||||
"is_moderator": false,
|
||||
"is_suggested": true,
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": []
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "https://paypal.me/gleasonator"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"note": "I create Fediverse software that empowers people online.\r\n\r\nI'm vegan btw\r\n\r\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false
|
||||
},
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 23004,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Soapbox FE",
|
||||
"website": "https://soapbox.pub/"
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>Test post</p>",
|
||||
"created_at": "2022-01-24T21:02:25.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 0,
|
||||
"id": "AFmFLcd6XYVdjWCrOS",
|
||||
"in_reply_to_account_id": null,
|
||||
"in_reply_to_id": null,
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "Test post"
|
||||
},
|
||||
"conversation_id": "AFmFLcaGi6EzaisayO",
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": null,
|
||||
"local": true,
|
||||
"parent_visible": false,
|
||||
"pinned_at": null,
|
||||
"quote": null,
|
||||
"quote_url": null,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/4f35159c-3794-4037-9269-a7c84f7137c7",
|
||||
"url": "https://gleasonator.com/notice/AFmFLcd6XYVdjWCrOS",
|
||||
"visibility": "public"
|
||||
},
|
||||
"quote_url": "https://gleasonator.com/objects/4f35159c-3794-4037-9269-a7c84f7137c7",
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/54d93075-7d04-4016-a128-81f3843bca79",
|
||||
"url": "https://gleasonator.com/notice/AFmFMSpITT9xcOJKcK",
|
||||
"visibility": "public"
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
{
|
||||
"account": {
|
||||
"acct": "alex",
|
||||
"avatar": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"avatar_static": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
|
||||
"bot": false,
|
||||
"created_at": "2020-01-08T01:25:43.000Z",
|
||||
"display_name": "Alex Gleason",
|
||||
"emojis": [],
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "<a href=\"https://paypal.me/gleasonator\" rel=\"ugc\">https://paypal.me/gleasonator</a>"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"followers_count": 2344,
|
||||
"following_count": 1564,
|
||||
"fqn": "alex@gleasonator.com",
|
||||
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"last_status_at": "2022-02-11T23:12:00",
|
||||
"locked": false,
|
||||
"note": "I create Fediverse software that empowers people online.<br/><br/>I'm vegan btw<br/><br/>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"also_known_as": [],
|
||||
"ap_id": "https://gleasonator.com/users/alex",
|
||||
"background_image": null,
|
||||
"birthday": "1993-07-03",
|
||||
"favicon": "https://gleasonator.com/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": true,
|
||||
"is_confirmed": true,
|
||||
"is_moderator": false,
|
||||
"is_suggested": true,
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": []
|
||||
},
|
||||
"source": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "Website",
|
||||
"value": "https://alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Pleroma+Soapbox",
|
||||
"value": "https://soapbox.pub"
|
||||
},
|
||||
{
|
||||
"name": "Email",
|
||||
"value": "alex@alexgleason.me"
|
||||
},
|
||||
{
|
||||
"name": "Gender identity",
|
||||
"value": "Soyboy"
|
||||
},
|
||||
{
|
||||
"name": "Donate (PayPal)",
|
||||
"value": "https://paypal.me/gleasonator"
|
||||
},
|
||||
{
|
||||
"name": "$BTC",
|
||||
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
|
||||
},
|
||||
{
|
||||
"name": "$ETH",
|
||||
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
|
||||
},
|
||||
{
|
||||
"name": "$DOGE",
|
||||
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
|
||||
},
|
||||
{
|
||||
"name": "$XMR",
|
||||
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
|
||||
}
|
||||
],
|
||||
"note": "I create Fediverse software that empowers people online.\r\n\r\nI'm vegan btw\r\n\r\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false
|
||||
},
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 23357,
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
"application": {
|
||||
"name": "Soapbox FE",
|
||||
"website": "https://soapbox.pub/"
|
||||
},
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<p>Test</p>",
|
||||
"created_at": "2022-02-11T23:11:59.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 1,
|
||||
"id": "AGNkA21auFR5lnEAHw",
|
||||
"in_reply_to_account_id": null,
|
||||
"in_reply_to_id": null,
|
||||
"language": null,
|
||||
"media_attachments": [
|
||||
{
|
||||
"blurhash": "emLqe9t7~q%M%M-;WBt7ofRj%Moft7ofoft7ayWBj[of-;j[ayofM{",
|
||||
"description": "",
|
||||
"id": "974611173",
|
||||
"meta": {
|
||||
"original": {
|
||||
"aspect": 0.9944598337950139,
|
||||
"height": 1444,
|
||||
"width": 1436
|
||||
}
|
||||
},
|
||||
"pleroma": {
|
||||
"mime_type": "image/png"
|
||||
},
|
||||
"preview_url": "https://media.gleasonator.com/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png",
|
||||
"remote_url": "https://media.gleasonator.com/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png",
|
||||
"text_url": "https://media.gleasonator.com/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png",
|
||||
"type": "image",
|
||||
"url": "https://media.gleasonator.com/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png"
|
||||
},
|
||||
{
|
||||
"blurhash": null,
|
||||
"description": "",
|
||||
"id": "-1764036199",
|
||||
"pleroma": {
|
||||
"mime_type": "application/x-nes-rom"
|
||||
},
|
||||
"preview_url": "https://media.gleasonator.com/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac.nes",
|
||||
"remote_url": "https://media.gleasonator.com/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac.nes",
|
||||
"text_url": "https://media.gleasonator.com/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac.nes",
|
||||
"type": "unknown",
|
||||
"url": "https://media.gleasonator.com/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac.nes"
|
||||
},
|
||||
{
|
||||
"blurhash": null,
|
||||
"description": "",
|
||||
"id": "-636167741",
|
||||
"pleroma": {
|
||||
"mime_type": "audio/ogg"
|
||||
},
|
||||
"preview_url": "https://media.gleasonator.com/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.ogg",
|
||||
"remote_url": "https://media.gleasonator.com/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.ogg",
|
||||
"text_url": "https://media.gleasonator.com/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.ogg",
|
||||
"type": "audio",
|
||||
"url": "https://media.gleasonator.com/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.ogg"
|
||||
},
|
||||
{
|
||||
"blurhash": null,
|
||||
"description": "",
|
||||
"id": "517941208",
|
||||
"pleroma": {
|
||||
"mime_type": "text/plain"
|
||||
},
|
||||
"preview_url": "https://media.gleasonator.com/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0.LICENSE",
|
||||
"remote_url": "https://media.gleasonator.com/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0.LICENSE",
|
||||
"text_url": "https://media.gleasonator.com/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0.LICENSE",
|
||||
"type": "unknown",
|
||||
"url": "https://media.gleasonator.com/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0.LICENSE"
|
||||
}
|
||||
],
|
||||
"mentions": [],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "Test"
|
||||
},
|
||||
"conversation_id": "AGNkA1yP66srbtjcJc",
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": null,
|
||||
"local": true,
|
||||
"parent_visible": false,
|
||||
"pinned_at": null,
|
||||
"quote": null,
|
||||
"quote_url": null,
|
||||
"quote_visible": false,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://gleasonator.com/objects/aa5e66c9-0a10-4167-9c80-f40d9574aaec",
|
||||
"url": "https://gleasonator.com/notice/AGNkA21auFR5lnEAHw",
|
||||
"visibility": "public"
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
{
|
||||
"account": {
|
||||
"acct": "apropos@freespeechextremist.com",
|
||||
"avatar": "https://gleasonator.com/proxy/WVdkCbG7AOZ_eqMzskzXQoyjq8o/aHR0cHM6Ly9mcmVlc3BlZWNoZXh0cmVtaXN0LmNvbS9tZWRpYS8zN2I4MDMzZC03OGQ1LTQ0YmMtYmY5NC0xYTI2NzY5NTQwM2YvYmxvYi5wbmc_bmFtZT1ibG9iLnBuZw/blob.png",
|
||||
"avatar_static": "https://gleasonator.com/proxy/WVdkCbG7AOZ_eqMzskzXQoyjq8o/aHR0cHM6Ly9mcmVlc3BlZWNoZXh0cmVtaXN0LmNvbS9tZWRpYS8zN2I4MDMzZC03OGQ1LTQ0YmMtYmY5NC0xYTI2NzY5NTQwM2YvYmxvYi5wbmc_bmFtZT1ibG9iLnBuZw/blob.png",
|
||||
"bot": false,
|
||||
"created_at": "2020-05-21T07:20:46.000Z",
|
||||
"display_name": "of nothing",
|
||||
"emojis": [],
|
||||
"fields": [],
|
||||
"followers_count": 87,
|
||||
"following_count": 85,
|
||||
"fqn": "apropos@freespeechextremist.com",
|
||||
"header": "https://gleasonator.com/proxy/pIracLGWm_skCfOOgdwcCNqES5s/aHR0cHM6Ly9mcmVlc3BlZWNoZXh0cmVtaXN0LmNvbS9tZWRpYS8yZDEwYmRjZC01NDUwLTRjZjYtYWFhZS1hNTJjMzYwYjk2YjYvdHJhY2tzb25tYXJzLmpwZz9uYW1lPXRyYWNrc29ubWFycy5qcGc/tracksonmars.jpg",
|
||||
"header_static": "https://gleasonator.com/proxy/pIracLGWm_skCfOOgdwcCNqES5s/aHR0cHM6Ly9mcmVlc3BlZWNoZXh0cmVtaXN0LmNvbS9tZWRpYS8yZDEwYmRjZC01NDUwLTRjZjYtYWFhZS1hNTJjMzYwYjk2YjYvdHJhY2tzb25tYXJzLmpwZz9uYW1lPXRyYWNrc29ubWFycy5qcGc/tracksonmars.jpg",
|
||||
"id": "9vGR3IWmWVYRkKUZ4i",
|
||||
"last_status_at": "2022-01-07T21:47:39",
|
||||
"locked": false,
|
||||
"note": "If you wait by the river long enough, the bodies of your enemies will float by.<br/><br/>Deo Vindice",
|
||||
"pleroma": {
|
||||
"accepts_chat_messages": true,
|
||||
"also_known_as": [],
|
||||
"ap_id": "https://freespeechextremist.com/users/apropos",
|
||||
"background_image": null,
|
||||
"favicon": "https://gleasonator.com/proxy/EN7BSaEEYTRpmRj4lITIjgWp2sg/aHR0cHM6Ly9mcmVlc3BlZWNoZXh0cmVtaXN0LmNvbS9mYXZpY29uLnBuZw/favicon.png",
|
||||
"hide_favorites": true,
|
||||
"hide_followers": false,
|
||||
"hide_followers_count": false,
|
||||
"hide_follows": false,
|
||||
"hide_follows_count": false,
|
||||
"is_admin": false,
|
||||
"is_confirmed": true,
|
||||
"is_moderator": false,
|
||||
"is_suggested": false,
|
||||
"relationship": {},
|
||||
"skip_thread_containment": false,
|
||||
"tags": []
|
||||
},
|
||||
"source": {
|
||||
"fields": [],
|
||||
"note": "",
|
||||
"pleroma": {
|
||||
"actor_type": "Person",
|
||||
"discoverable": false
|
||||
},
|
||||
"sensitive": false
|
||||
},
|
||||
"statuses_count": 7087,
|
||||
"url": "https://freespeechextremist.com/users/apropos",
|
||||
"username": "apropos"
|
||||
},
|
||||
"application": null,
|
||||
"bookmarked": false,
|
||||
"card": null,
|
||||
"content": "<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"9r7CIa1GGezUtzTFyq\" href=\"https://iddqd.social/users/NEETzsche\" rel=\"ugc\">@<span>NEETzsche</span></a></span> <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"9qoN7ZXtt7bllprZtw\" href=\"https://gleasonator.com/users/alex\" rel=\"ugc\">@<span>alex</span></a></span> <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"A3dBnkLBdLgHFdxV2G\" href=\"https://pleroma.skyshanty.xyz/users/Lumeinshin\" rel=\"ugc\">@<span>Lumeinshin</span></a></span> <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"ACrsGCVvaMiNdATg7E\" href=\"https://social.silkky.cloud/users/sneeden\" rel=\"ugc\">@<span>sneeden</span></a></span> <br/>>seething<br/>'posting', just like you.",
|
||||
"created_at": "2022-01-07T17:29:58.000Z",
|
||||
"emojis": [],
|
||||
"favourited": false,
|
||||
"favourites_count": 1,
|
||||
"id": "AFChectaqZjmOVkXZ2",
|
||||
"in_reply_to_account_id": "9v5bw7hEGBPc9nrpzc",
|
||||
"in_reply_to_id": "AFChbnWqrAZ2VIlPJw",
|
||||
"language": null,
|
||||
"media_attachments": [],
|
||||
"mentions": [
|
||||
{
|
||||
"acct": "alex",
|
||||
"id": "9v5bmRalQvjOy0ECcC",
|
||||
"url": "https://gleasonator.com/users/alex",
|
||||
"username": "alex"
|
||||
},
|
||||
{
|
||||
"acct": "NEETzsche@iddqd.social",
|
||||
"id": "9v5bw7hEGBPc9nrpzc",
|
||||
"url": "https://iddqd.social/users/NEETzsche",
|
||||
"username": "NEETzsche"
|
||||
},
|
||||
{
|
||||
"acct": "Lumeinshin@pleroma.skyshanty.xyz",
|
||||
"id": "A3dFSwTkwgRfd998iG",
|
||||
"url": "https://pleroma.skyshanty.xyz/users/Lumeinshin",
|
||||
"username": "Lumeinshin"
|
||||
},
|
||||
{
|
||||
"acct": "sneeden@social.silkky.cloud",
|
||||
"id": "ACrsPAbAOPh3GbKZhQ",
|
||||
"url": "https://social.silkky.cloud/users/sneeden",
|
||||
"username": "sneeden"
|
||||
}
|
||||
],
|
||||
"muted": false,
|
||||
"pinned": false,
|
||||
"pleroma": {
|
||||
"content": {
|
||||
"text/plain": "@NEETzsche @alex @Lumeinshin @sneeden >seething'posting', just like you."
|
||||
},
|
||||
"conversation_id": "AFCYCBFN9SgOwoIWTg",
|
||||
"direct_conversation_id": null,
|
||||
"emoji_reactions": [],
|
||||
"expires_at": null,
|
||||
"in_reply_to_account_acct": "NEETzsche@iddqd.social",
|
||||
"local": false,
|
||||
"parent_visible": true,
|
||||
"pinned_at": null,
|
||||
"spoiler_text": {
|
||||
"text/plain": ""
|
||||
},
|
||||
"thread_muted": false
|
||||
},
|
||||
"poll": null,
|
||||
"reblog": null,
|
||||
"reblogged": false,
|
||||
"reblogs_count": 0,
|
||||
"replies_count": 0,
|
||||
"sensitive": false,
|
||||
"spoiler_text": "",
|
||||
"tags": [],
|
||||
"text": null,
|
||||
"uri": "https://freespeechextremist.com/objects/714b0e04-bec4-4a2a-9514-312814380064",
|
||||
"url": "https://freespeechextremist.com/objects/714b0e04-bec4-4a2a-9514-312814380064",
|
||||
"visibility": "public"
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import { staticClient } from 'soapbox/api';
|
||||
import { mockStore } from 'soapbox/test_helpers';
|
||||
|
||||
import {
|
||||
FETCH_ABOUT_PAGE_REQUEST,
|
||||
FETCH_ABOUT_PAGE_SUCCESS,
|
||||
FETCH_ABOUT_PAGE_FAIL,
|
||||
fetchAboutPage,
|
||||
} from '../about';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { staticClient } from 'soapbox/api';
|
||||
import { mockStore } from 'soapbox/test_helpers';
|
||||
|
||||
describe('fetchAboutPage()', () => {
|
||||
it('creates the expected actions on success', () => {
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import { __stub } from 'soapbox/api';
|
||||
import { mockStore } from 'soapbox/test_helpers';
|
||||
|
||||
import { VERIFY_CREDENTIALS_REQUEST } from '../auth';
|
||||
import { ACCOUNTS_IMPORT } from '../importer';
|
||||
import {
|
||||
MASTODON_PRELOAD_IMPORT,
|
||||
preloadMastodon,
|
||||
} from '../preload';
|
||||
import { VERIFY_CREDENTIALS_REQUEST } from '../auth';
|
||||
import { ACCOUNTS_IMPORT } from '../importer';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { __stub } from 'soapbox/api';
|
||||
import { mockStore } from 'soapbox/test_helpers';
|
||||
|
||||
describe('preloadMastodon()', () => {
|
||||
it('creates the expected actions', () => {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import { STATUSES_IMPORT } from 'soapbox/actions/importer';
|
||||
import { __stub } from 'soapbox/api';
|
||||
import { mockStore } from 'soapbox/test_helpers';
|
||||
|
||||
import { fetchContext } from '../statuses';
|
||||
|
||||
describe('fetchContext()', () => {
|
||||
it('handles Mitra context', done => {
|
||||
const statuses = require('soapbox/__fixtures__/mitra-context.json');
|
||||
|
||||
__stub(mock => {
|
||||
mock.onGet('/api/v1/statuses/017ed505-5926-392f-256a-f86d5075df70/context')
|
||||
.reply(200, statuses);
|
||||
});
|
||||
|
||||
const store = mockStore(ImmutableMap());
|
||||
|
||||
store.dispatch(fetchContext('017ed505-5926-392f-256a-f86d5075df70')).then(context => {
|
||||
const actions = store.getActions();
|
||||
|
||||
expect(actions[3].type).toEqual(STATUSES_IMPORT);
|
||||
expect(actions[3].statuses[0].id).toEqual('017ed503-bc96-301a-e871-2c23b30ddd05');
|
||||
|
||||
done();
|
||||
}).catch(console.error);
|
||||
});
|
||||
});
|
|
@ -1,11 +1,13 @@
|
|||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import {
|
||||
importFetchedAccount,
|
||||
importFetchedAccounts,
|
||||
importErrorWhileFetchingAccountByUsername,
|
||||
} from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
export const ACCOUNT_CREATE_REQUEST = 'ACCOUNT_CREATE_REQUEST';
|
||||
export const ACCOUNT_CREATE_SUCCESS = 'ACCOUNT_CREATE_SUCCESS';
|
||||
|
@ -55,10 +57,18 @@ export const ACCOUNT_UNPIN_REQUEST = 'ACCOUNT_UNPIN_REQUEST';
|
|||
export const ACCOUNT_UNPIN_SUCCESS = 'ACCOUNT_UNPIN_SUCCESS';
|
||||
export const ACCOUNT_UNPIN_FAIL = 'ACCOUNT_UNPIN_FAIL';
|
||||
|
||||
export const PINNED_ACCOUNTS_FETCH_REQUEST = 'PINNED_ACCOUNTS_FETCH_REQUEST';
|
||||
export const PINNED_ACCOUNTS_FETCH_SUCCESS = 'PINNED_ACCOUNTS_FETCH_SUCCESS';
|
||||
export const PINNED_ACCOUNTS_FETCH_FAIL = 'PINNED_ACCOUNTS_FETCH_FAIL';
|
||||
|
||||
export const ACCOUNT_SEARCH_REQUEST = 'ACCOUNT_SEARCH_REQUEST';
|
||||
export const ACCOUNT_SEARCH_SUCCESS = 'ACCOUNT_SEARCH_SUCCESS';
|
||||
export const ACCOUNT_SEARCH_FAIL = 'ACCOUNT_SEARCH_FAIL';
|
||||
|
||||
export const ACCOUNT_LOOKUP_REQUEST = 'ACCOUNT_LOOKUP_REQUEST';
|
||||
export const ACCOUNT_LOOKUP_SUCCESS = 'ACCOUNT_LOOKUP_SUCCESS';
|
||||
export const ACCOUNT_LOOKUP_FAIL = 'ACCOUNT_LOOKUP_FAIL';
|
||||
|
||||
export const FOLLOWERS_FETCH_REQUEST = 'FOLLOWERS_FETCH_REQUEST';
|
||||
export const FOLLOWERS_FETCH_SUCCESS = 'FOLLOWERS_FETCH_SUCCESS';
|
||||
export const FOLLOWERS_FETCH_FAIL = 'FOLLOWERS_FETCH_FAIL';
|
||||
|
@ -99,6 +109,10 @@ export const NOTIFICATION_SETTINGS_REQUEST = 'NOTIFICATION_SETTINGS_REQUEST';
|
|||
export const NOTIFICATION_SETTINGS_SUCCESS = 'NOTIFICATION_SETTINGS_SUCCESS';
|
||||
export const NOTIFICATION_SETTINGS_FAIL = 'NOTIFICATION_SETTINGS_FAIL';
|
||||
|
||||
export const BIRTHDAY_REMINDERS_FETCH_REQUEST = 'BIRTHDAY_REMINDERS_FETCH_REQUEST';
|
||||
export const BIRTHDAY_REMINDERS_FETCH_SUCCESS = 'BIRTHDAY_REMINDERS_FETCH_SUCCESS';
|
||||
export const BIRTHDAY_REMINDERS_FETCH_FAIL = 'BIRTHDAY_REMINDERS_FETCH_FAIL';
|
||||
|
||||
export function createAccount(params) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: ACCOUNT_CREATE_REQUEST, params });
|
||||
|
@ -144,8 +158,9 @@ export function fetchAccountByUsername(username) {
|
|||
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
const me = state.get('me');
|
||||
|
||||
if (features.accountByUsername) {
|
||||
if (features.accountByUsername && (me || !features.accountLookup)) {
|
||||
api(getState).get(`/api/v1/accounts/${username}`).then(response => {
|
||||
dispatch(fetchRelationships([response.data.id]));
|
||||
dispatch(importFetchedAccount(response.data));
|
||||
|
@ -154,6 +169,13 @@ export function fetchAccountByUsername(username) {
|
|||
dispatch(fetchAccountFail(null, error));
|
||||
dispatch(importErrorWhileFetchingAccountByUsername(username));
|
||||
});
|
||||
} else if (features.accountLookup) {
|
||||
dispatch(accountLookup(username)).then(account => {
|
||||
dispatch(fetchAccountSuccess(account));
|
||||
}).catch(error => {
|
||||
dispatch(fetchAccountFail(null, error));
|
||||
dispatch(importErrorWhileFetchingAccountByUsername(username));
|
||||
});
|
||||
} else {
|
||||
dispatch(accountSearch({
|
||||
q: username,
|
||||
|
@ -199,7 +221,7 @@ export function fetchAccountFail(id, error) {
|
|||
};
|
||||
}
|
||||
|
||||
export function followAccount(id, reblogs = true) {
|
||||
export function followAccount(id, options = { reblogs: true }) {
|
||||
return (dispatch, getState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
|
@ -208,7 +230,7 @@ export function followAccount(id, reblogs = true) {
|
|||
|
||||
dispatch(followAccountRequest(id, locked));
|
||||
|
||||
api(getState).post(`/api/v1/accounts/${id}/follow`, { reblogs }).then(response => {
|
||||
api(getState).post(`/api/v1/accounts/${id}/follow`, options).then(response => {
|
||||
dispatch(followAccountSuccess(response.data, alreadyFollowing));
|
||||
}).catch(error => {
|
||||
dispatch(followAccountFail(error, locked));
|
||||
|
@ -948,6 +970,43 @@ export function unpinAccountFail(error) {
|
|||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedAccounts(id) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(fetchPinnedAccountsRequest(id));
|
||||
|
||||
api(getState).get(`/api/v1/pleroma/accounts/${id}/endorsements`).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch(fetchPinnedAccountsSuccess(id, response.data, null));
|
||||
}).catch(error => {
|
||||
dispatch(fetchPinnedAccountsFail(id, error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedAccountsRequest(id) {
|
||||
return {
|
||||
type: PINNED_ACCOUNTS_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedAccountsSuccess(id, accounts, next) {
|
||||
return {
|
||||
type: PINNED_ACCOUNTS_FETCH_SUCCESS,
|
||||
id,
|
||||
accounts,
|
||||
next,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedAccountsFail(id, error) {
|
||||
return {
|
||||
type: PINNED_ACCOUNTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function accountSearch(params, cancelToken) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: ACCOUNT_SEARCH_REQUEST, params });
|
||||
|
@ -961,3 +1020,40 @@ export function accountSearch(params, cancelToken) {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function accountLookup(acct, cancelToken) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: ACCOUNT_LOOKUP_REQUEST, acct });
|
||||
return api(getState).get('/api/v1/accounts/lookup', { params: { acct }, cancelToken }).then(({ data: account }) => {
|
||||
if (account && account.id) dispatch(importFetchedAccount(account));
|
||||
dispatch({ type: ACCOUNT_LOOKUP_SUCCESS, account });
|
||||
return account;
|
||||
}).catch(error => {
|
||||
dispatch({ type: ACCOUNT_LOOKUP_FAIL });
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBirthdayReminders(day, month) {
|
||||
return (dispatch, getState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
const me = getState().get('me');
|
||||
|
||||
dispatch({ type: BIRTHDAY_REMINDERS_FETCH_REQUEST, day, month, id: me });
|
||||
|
||||
api(getState).get('/api/v1/pleroma/birthdays', { params: { day, month } }).then(response => {
|
||||
dispatch(importFetchedAccounts(response.data));
|
||||
dispatch({
|
||||
type: BIRTHDAY_REMINDERS_FETCH_SUCCESS,
|
||||
accounts: response.data,
|
||||
day,
|
||||
month,
|
||||
id: me,
|
||||
});
|
||||
}).catch(error => {
|
||||
dispatch({ type: BIRTHDAY_REMINDERS_FETCH_FAIL, day, month, id: me });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccount, importFetchedStatuses } from 'soapbox/actions/importer';
|
||||
import { fetchRelationships } from 'soapbox/actions/accounts';
|
||||
import { importFetchedAccount, importFetchedStatuses } from 'soapbox/actions/importer';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
export const ADMIN_CONFIG_FETCH_REQUEST = 'ADMIN_CONFIG_FETCH_REQUEST';
|
||||
export const ADMIN_CONFIG_FETCH_SUCCESS = 'ADMIN_CONFIG_FETCH_SUCCESS';
|
||||
|
@ -62,6 +63,14 @@ export const ADMIN_REMOVE_PERMISSION_GROUP_REQUEST = 'ADMIN_REMOVE_PERMISSION_GR
|
|||
export const ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS = 'ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS';
|
||||
export const ADMIN_REMOVE_PERMISSION_GROUP_FAIL = 'ADMIN_REMOVE_PERMISSION_GROUP_FAIL';
|
||||
|
||||
export const ADMIN_USERS_SUGGEST_REQUEST = 'ADMIN_USERS_SUGGEST_REQUEST';
|
||||
export const ADMIN_USERS_SUGGEST_SUCCESS = 'ADMIN_USERS_SUGGEST_SUCCESS';
|
||||
export const ADMIN_USERS_SUGGEST_FAIL = 'ADMIN_USERS_SUGGEST_FAIL';
|
||||
|
||||
export const ADMIN_USERS_UNSUGGEST_REQUEST = 'ADMIN_USERS_UNSUGGEST_REQUEST';
|
||||
export const ADMIN_USERS_UNSUGGEST_SUCCESS = 'ADMIN_USERS_UNSUGGEST_SUCCESS';
|
||||
export const ADMIN_USERS_UNSUGGEST_FAIL = 'ADMIN_USERS_UNSUGGEST_FAIL';
|
||||
|
||||
const nicknamesFromIds = (getState, ids) => ids.map(id => getState().getIn(['accounts', id, 'acct']));
|
||||
|
||||
export function fetchConfig() {
|
||||
|
@ -319,3 +328,31 @@ export function demoteToUser(accountId) {
|
|||
]);
|
||||
};
|
||||
}
|
||||
|
||||
export function suggestUsers(accountIds) {
|
||||
return (dispatch, getState) => {
|
||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||
dispatch({ type: ADMIN_USERS_SUGGEST_REQUEST, accountIds });
|
||||
return api(getState)
|
||||
.patch('/api/pleroma/admin/users/suggest', { nicknames })
|
||||
.then(({ data: { users } }) => {
|
||||
dispatch({ type: ADMIN_USERS_SUGGEST_SUCCESS, users, accountIds });
|
||||
}).catch(error => {
|
||||
dispatch({ type: ADMIN_USERS_SUGGEST_FAIL, error, accountIds });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function unsuggestUsers(accountIds) {
|
||||
return (dispatch, getState) => {
|
||||
const nicknames = nicknamesFromIds(getState, accountIds);
|
||||
dispatch({ type: ADMIN_USERS_UNSUGGEST_REQUEST, accountIds });
|
||||
return api(getState)
|
||||
.patch('/api/pleroma/admin/users/unsuggest', { nicknames })
|
||||
.then(({ data: { users } }) => {
|
||||
dispatch({ type: ADMIN_USERS_UNSUGGEST_SUCCESS, users, accountIds });
|
||||
}).catch(error => {
|
||||
dispatch({ type: ADMIN_USERS_UNSUGGEST_FAIL, error, accountIds });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
import { defineMessages } from 'react-intl';
|
||||
import api from '../api';
|
||||
import { importFetchedAccount, importFetchedAccounts } from './importer';
|
||||
import { showAlertForError } from './alerts';
|
||||
import snackbar from './snackbar';
|
||||
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { ME_PATCH_SUCCESS } from './me';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { showAlertForError } from './alerts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { patchMeSuccess } from './me';
|
||||
import snackbar from './snackbar';
|
||||
|
||||
export const ALIASES_FETCH_REQUEST = 'ALIASES_FETCH_REQUEST';
|
||||
export const ALIASES_FETCH_SUCCESS = 'ALIASES_FETCH_SUCCESS';
|
||||
export const ALIASES_FETCH_FAIL = 'ALIASES_FETCH_FAIL';
|
||||
|
||||
export const ALIASES_SUGGESTIONS_CHANGE = 'ALIASES_SUGGESTIONS_CHANGE';
|
||||
export const ALIASES_SUGGESTIONS_READY = 'ALIASES_SUGGESTIONS_READY';
|
||||
|
@ -23,6 +31,38 @@ const messages = defineMessages({
|
|||
removeSuccess: { id: 'aliases.success.remove', defaultMessage: 'Account alias removed successfully' },
|
||||
});
|
||||
|
||||
export const fetchAliases = (dispatch, getState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
const state = getState();
|
||||
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
|
||||
if (!features.accountMoving) return;
|
||||
|
||||
dispatch(fetchAliasesRequest());
|
||||
|
||||
api(getState).get('/api/pleroma/aliases')
|
||||
.then(response => {
|
||||
dispatch(fetchAliasesSuccess(response.data.aliases));
|
||||
})
|
||||
.catch(err => dispatch(fetchAliasesFail(err)));
|
||||
};
|
||||
|
||||
export const fetchAliasesRequest = () => ({
|
||||
type: ALIASES_FETCH_REQUEST,
|
||||
});
|
||||
|
||||
export const fetchAliasesSuccess = aliases => ({
|
||||
type: ALIASES_FETCH_SUCCESS,
|
||||
value: aliases,
|
||||
});
|
||||
|
||||
export const fetchAliasesFail = error => ({
|
||||
type: ALIASES_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
export const fetchAliasesSuggestions = q => (dispatch, getState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
|
@ -53,80 +93,104 @@ export const changeAliasesSuggestions = value => ({
|
|||
value,
|
||||
});
|
||||
|
||||
export const addToAliases = (intl, apId) => (dispatch, getState) => {
|
||||
export const addToAliases = (intl, account) => (dispatch, getState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
const state = getState();
|
||||
|
||||
const me = state.get('me');
|
||||
const alsoKnownAs = state.getIn(['accounts_meta', me, 'pleroma', 'also_known_as']);
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
|
||||
dispatch(addToAliasesRequest(apId));
|
||||
if (!features.accountMoving) {
|
||||
const me = state.get('me');
|
||||
const alsoKnownAs = state.getIn(['accounts_meta', me, 'pleroma', 'also_known_as']);
|
||||
|
||||
api(getState).patch('/api/v1/accounts/update_credentials', { also_known_as: [...alsoKnownAs, apId] })
|
||||
.then((response => {
|
||||
dispatch(addToAliasesRequest());
|
||||
|
||||
api(getState).patch('/api/v1/accounts/update_credentials', { also_known_as: [...alsoKnownAs, account.getIn(['pleroma', 'ap_id'])] })
|
||||
.then((response => {
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.createSuccess)));
|
||||
dispatch(addToAliasesSuccess);
|
||||
dispatch(patchMeSuccess(response.data));
|
||||
}))
|
||||
.catch(err => dispatch(addToAliasesFail(err)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(addToAliasesRequest());
|
||||
|
||||
api(getState).put('/api/pleroma/aliases', {
|
||||
alias: account.get('acct'),
|
||||
})
|
||||
.then(response => {
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.createSuccess)));
|
||||
dispatch(addToAliasesSuccess(response.data));
|
||||
}))
|
||||
.catch(err => dispatch(addToAliasesFail(err)));
|
||||
dispatch(addToAliasesSuccess);
|
||||
dispatch(fetchAliases);
|
||||
})
|
||||
.catch(err => dispatch(fetchAliasesFail(err)));
|
||||
};
|
||||
|
||||
export const addToAliasesRequest = (apId) => ({
|
||||
export const addToAliasesRequest = () => ({
|
||||
type: ALIASES_ADD_REQUEST,
|
||||
apId,
|
||||
});
|
||||
|
||||
export const addToAliasesSuccess = me => dispatch => {
|
||||
dispatch(importFetchedAccount(me));
|
||||
dispatch({
|
||||
type: ME_PATCH_SUCCESS,
|
||||
me,
|
||||
});
|
||||
dispatch({
|
||||
type: ALIASES_ADD_SUCCESS,
|
||||
});
|
||||
};
|
||||
export const addToAliasesSuccess = () => ({
|
||||
type: ALIASES_ADD_SUCCESS,
|
||||
});
|
||||
|
||||
export const addToAliasesFail = (apId, error) => ({
|
||||
export const addToAliasesFail = error => ({
|
||||
type: ALIASES_ADD_FAIL,
|
||||
apId,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeFromAliases = (intl, apId) => (dispatch, getState) => {
|
||||
export const removeFromAliases = (intl, account) => (dispatch, getState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
const state = getState();
|
||||
|
||||
const me = state.get('me');
|
||||
const alsoKnownAs = state.getIn(['accounts_meta', me, 'pleroma', 'also_known_as']);
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
|
||||
dispatch(removeFromAliasesRequest(apId));
|
||||
if (!features.accountMoving) {
|
||||
const me = state.get('me');
|
||||
const alsoKnownAs = state.getIn(['accounts_meta', me, 'pleroma', 'also_known_as']);
|
||||
|
||||
api(getState).patch('/api/v1/accounts/update_credentials', { also_known_as: alsoKnownAs.filter(id => id !== apId) })
|
||||
dispatch(removeFromAliasesRequest());
|
||||
|
||||
api(getState).patch('/api/v1/accounts/update_credentials', { also_known_as: alsoKnownAs.filter(id => id !== account) })
|
||||
.then(response => {
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.removeSuccess)));
|
||||
dispatch(removeFromAliasesSuccess);
|
||||
dispatch(patchMeSuccess(response.data));
|
||||
})
|
||||
.catch(err => dispatch(removeFromAliasesFail(err)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(addToAliasesRequest());
|
||||
|
||||
api(getState).delete('/api/pleroma/aliases', {
|
||||
data: {
|
||||
alias: account,
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.removeSuccess)));
|
||||
dispatch(removeFromAliasesSuccess(response.data));
|
||||
dispatch(removeFromAliasesSuccess);
|
||||
dispatch(fetchAliases);
|
||||
})
|
||||
.catch(err => dispatch(removeFromAliasesFail(apId, err)));
|
||||
.catch(err => dispatch(fetchAliasesFail(err)));
|
||||
};
|
||||
|
||||
export const removeFromAliasesRequest = (apId) => ({
|
||||
export const removeFromAliasesRequest = () => ({
|
||||
type: ALIASES_REMOVE_REQUEST,
|
||||
apId,
|
||||
});
|
||||
|
||||
export const removeFromAliasesSuccess = me => dispatch => {
|
||||
dispatch(importFetchedAccount(me));
|
||||
dispatch({
|
||||
type: ME_PATCH_SUCCESS,
|
||||
me,
|
||||
});
|
||||
dispatch({
|
||||
type: ALIASES_REMOVE_SUCCESS,
|
||||
});
|
||||
};
|
||||
export const removeFromAliasesSuccess = () => ({
|
||||
type: ALIASES_REMOVE_SUCCESS,
|
||||
});
|
||||
|
||||
export const removeFromAliasesFail = (apId, error) => ({
|
||||
export const removeFromAliasesFail = error => ({
|
||||
type: ALIASES_REMOVE_FAIL,
|
||||
apId,
|
||||
error,
|
||||
});
|
||||
|
|
|
@ -8,18 +8,21 @@
|
|||
*/
|
||||
|
||||
import { defineMessages } from 'react-intl';
|
||||
import api, { baseClient } from '../api';
|
||||
import { importFetchedAccount } from './importer';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
|
||||
import { createAccount } from 'soapbox/actions/accounts';
|
||||
import { fetchMeSuccess, fetchMeFail } from 'soapbox/actions/me';
|
||||
import { getLoggedInAccount, parseBaseURL } from 'soapbox/utils/auth';
|
||||
import { createApp } from 'soapbox/actions/apps';
|
||||
import { fetchMeSuccess, fetchMeFail } from 'soapbox/actions/me';
|
||||
import { obtainOAuthToken, revokeOAuthToken } from 'soapbox/actions/oauth';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import KVStore from 'soapbox/storage/kv_store';
|
||||
import { getLoggedInAccount, parseBaseURL } from 'soapbox/utils/auth';
|
||||
import sourceCode from 'soapbox/utils/code';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
import KVStore from 'soapbox/storage/kv_store';
|
||||
|
||||
import api, { baseClient } from '../api';
|
||||
|
||||
import { importFetchedAccount } from './importer';
|
||||
|
||||
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
|
||||
|
||||
|
@ -140,6 +143,7 @@ export function otpVerify(code, mfa_token) {
|
|||
code: code,
|
||||
challenge_type: 'totp',
|
||||
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
||||
scope: getScopes(getState()),
|
||||
}).then(({ data: token }) => dispatch(authLoggedIn(token)));
|
||||
};
|
||||
}
|
||||
|
@ -186,7 +190,7 @@ export function loadCredentials(token, accountUrl) {
|
|||
|
||||
export function logIn(intl, username, password) {
|
||||
return (dispatch, getState) => {
|
||||
return dispatch(createAppAndToken()).then(() => {
|
||||
return dispatch(createAuthApp()).then(() => {
|
||||
return dispatch(createUserToken(username, password));
|
||||
}).catch(error => {
|
||||
if (error.response.data.error === 'mfa_required') {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getNextLinkName } from 'soapbox/utils/quirks';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST';
|
||||
export const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS';
|
||||
export const BLOCKS_FETCH_FAIL = 'BLOCKS_FETCH_FAIL';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import api, { getLinks } from '../api';
|
||||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
export const BOOKMARKED_STATUSES_FETCH_REQUEST = 'BOOKMARKED_STATUSES_FETCH_REQUEST';
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import api from '../api';
|
||||
import { getSettings, changeSetting } from 'soapbox/actions/settings';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { getSettings, changeSetting } from 'soapbox/actions/settings';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
export const CHATS_FETCH_REQUEST = 'CHATS_FETCH_REQUEST';
|
||||
export const CHATS_FETCH_SUCCESS = 'CHATS_FETCH_SUCCESS';
|
||||
export const CHATS_FETCH_FAIL = 'CHATS_FETCH_FAIL';
|
||||
|
||||
export const CHATS_EXPAND_REQUEST = 'CHATS_EXPAND_REQUEST';
|
||||
export const CHATS_EXPAND_SUCCESS = 'CHATS_EXPAND_SUCCESS';
|
||||
export const CHATS_EXPAND_FAIL = 'CHATS_EXPAND_FAIL';
|
||||
|
||||
export const CHAT_MESSAGES_FETCH_REQUEST = 'CHAT_MESSAGES_FETCH_REQUEST';
|
||||
export const CHAT_MESSAGES_FETCH_SUCCESS = 'CHAT_MESSAGES_FETCH_SUCCESS';
|
||||
export const CHAT_MESSAGES_FETCH_FAIL = 'CHAT_MESSAGES_FETCH_FAIL';
|
||||
|
@ -27,14 +34,61 @@ export const CHAT_MESSAGE_DELETE_REQUEST = 'CHAT_MESSAGE_DELETE_REQUEST';
|
|||
export const CHAT_MESSAGE_DELETE_SUCCESS = 'CHAT_MESSAGE_DELETE_SUCCESS';
|
||||
export const CHAT_MESSAGE_DELETE_FAIL = 'CHAT_MESSAGE_DELETE_FAIL';
|
||||
|
||||
export function fetchChats() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: CHATS_FETCH_REQUEST });
|
||||
return api(getState).get('/api/v1/pleroma/chats').then(({ data }) => {
|
||||
dispatch({ type: CHATS_FETCH_SUCCESS, chats: data });
|
||||
export function fetchChatsV1() {
|
||||
return (dispatch, getState) =>
|
||||
api(getState).get('/api/v1/pleroma/chats').then((response) => {
|
||||
dispatch({ type: CHATS_FETCH_SUCCESS, chats: response.data });
|
||||
}).catch(error => {
|
||||
dispatch({ type: CHATS_FETCH_FAIL, error });
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchChatsV2() {
|
||||
return (dispatch, getState) =>
|
||||
api(getState).get('/api/v2/pleroma/chats').then((response) => {
|
||||
let next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
if (!next && response.data.length) {
|
||||
next = { uri: `/api/v2/pleroma/chats?max_id=${response.data[response.data.length - 1].id}&offset=0` };
|
||||
}
|
||||
|
||||
dispatch({ type: CHATS_FETCH_SUCCESS, chats: response.data, next: next ? next.uri : null });
|
||||
}).catch(error => {
|
||||
dispatch({ type: CHATS_FETCH_FAIL, error });
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchChats() {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
|
||||
dispatch({ type: CHATS_FETCH_REQUEST });
|
||||
if (features.chatsV2) {
|
||||
dispatch(fetchChatsV2());
|
||||
} else {
|
||||
dispatch(fetchChatsV1());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function expandChats() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['chats', 'next']);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({ type: CHATS_EXPAND_REQUEST });
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch({ type: CHATS_EXPAND_SUCCESS, chats: response.data, next: next ? next.uri : null });
|
||||
}).catch(error => {
|
||||
dispatch({ type: CHATS_EXPAND_FAIL, error });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -140,7 +194,7 @@ export function startChat(accountId) {
|
|||
|
||||
export function markChatRead(chatId, lastReadId) {
|
||||
return (dispatch, getState) => {
|
||||
const chat = getState().getIn(['chats', chatId]);
|
||||
const chat = getState().getIn(['chats', 'items', chatId]);
|
||||
if (!lastReadId) lastReadId = chat.get('last_message');
|
||||
|
||||
if (chat.get('unread') < 1) return;
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
import api from '../api';
|
||||
import { CancelToken, isCancel } from 'axios';
|
||||
import { throttle } from 'lodash';
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import api from '../api';
|
||||
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
|
||||
import { tagHistory } from '../settings';
|
||||
import { useEmoji } from './emojis';
|
||||
import resizeImage from '../utils/resize_image';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
import { showAlert, showAlertForError } from './alerts';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import { openModal, closeModal } from './modal';
|
||||
import { getSettings } from './settings';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { useEmoji } from './emojis';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { uploadMedia, fetchMedia, updateMedia } from './media';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { openModal, closeModal } from './modals';
|
||||
import { getSettings } from './settings';
|
||||
import { createStatus } from './statuses';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
|
||||
let cancelFetchComposeSuggestionsAccounts;
|
||||
|
||||
|
@ -24,6 +27,8 @@ export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
|||
export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
||||
export const COMPOSE_REPLY = 'COMPOSE_REPLY';
|
||||
export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
|
||||
export const COMPOSE_QUOTE = 'COMPOSE_QUOTE';
|
||||
export const COMPOSE_QUOTE_CANCEL = 'COMPOSE_QUOTE_CANCEL';
|
||||
export const COMPOSE_DIRECT = 'COMPOSE_DIRECT';
|
||||
export const COMPOSE_MENTION = 'COMPOSE_MENTION';
|
||||
export const COMPOSE_RESET = 'COMPOSE_RESET';
|
||||
|
@ -68,11 +73,15 @@ export const COMPOSE_SCHEDULE_ADD = 'COMPOSE_SCHEDULE_ADD';
|
|||
export const COMPOSE_SCHEDULE_SET = 'COMPOSE_SCHEDULE_SET';
|
||||
export const COMPOSE_SCHEDULE_REMOVE = 'COMPOSE_SCHEDULE_REMOVE';
|
||||
|
||||
export const COMPOSE_ADD_TO_MENTIONS = 'COMPOSE_ADD_TO_MENTIONS';
|
||||
export const COMPOSE_REMOVE_FROM_MENTIONS = 'COMPOSE_REMOVE_FROM_MENTIONS';
|
||||
|
||||
const messages = defineMessages({
|
||||
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
|
||||
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
|
||||
scheduleError: { id: 'compose.invalid_schedule', defaultMessage: 'You must schedule a post at least 5 minutes out.' },
|
||||
success: { id: 'compose.submit_success', defaultMessage: 'Your post was sent' },
|
||||
view: { id: 'snackbar.view', defaultMessage: 'View' },
|
||||
});
|
||||
|
||||
const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1);
|
||||
|
@ -93,10 +102,14 @@ export function changeCompose(text) {
|
|||
export function replyCompose(status, routerHistory) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const instance = state.get('instance');
|
||||
const { explicitAddressing } = getFeatures(instance);
|
||||
|
||||
dispatch({
|
||||
type: COMPOSE_REPLY,
|
||||
status: status,
|
||||
account: state.getIn(['accounts', state.get('me')]),
|
||||
explicitAddressing,
|
||||
});
|
||||
|
||||
dispatch(openModal('COMPOSE'));
|
||||
|
@ -109,6 +122,29 @@ export function cancelReplyCompose() {
|
|||
};
|
||||
}
|
||||
|
||||
export function quoteCompose(status, routerHistory) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const instance = state.get('instance');
|
||||
const { explicitAddressing } = getFeatures(instance);
|
||||
|
||||
dispatch({
|
||||
type: COMPOSE_QUOTE,
|
||||
status: status,
|
||||
account: state.getIn(['accounts', state.get('me')]),
|
||||
explicitAddressing,
|
||||
});
|
||||
|
||||
dispatch(openModal('COMPOSE'));
|
||||
};
|
||||
}
|
||||
|
||||
export function cancelQuoteCompose() {
|
||||
return {
|
||||
type: COMPOSE_QUOTE_CANCEL,
|
||||
};
|
||||
}
|
||||
|
||||
export function resetCompose() {
|
||||
return {
|
||||
type: COMPOSE_RESET,
|
||||
|
@ -155,7 +191,7 @@ export function handleComposeSubmit(dispatch, getState, data, status) {
|
|||
|
||||
dispatch(insertIntoTagHistory(data.tags || [], status));
|
||||
dispatch(submitComposeSuccess({ ...data }));
|
||||
dispatch(snackbar.success(messages.success));
|
||||
dispatch(snackbar.success(messages.success, messages.view, `/@${data.account.acct}/posts/${data.id}`));
|
||||
}
|
||||
|
||||
const needsDescriptions = state => {
|
||||
|
@ -183,6 +219,7 @@ export function submitCompose(routerHistory, force = false) {
|
|||
|
||||
const status = state.getIn(['compose', 'text'], '');
|
||||
const media = state.getIn(['compose', 'media_attachments']);
|
||||
let to = state.getIn(['compose', 'to'], null);
|
||||
|
||||
if (!validateSchedule(state)) {
|
||||
dispatch(snackbar.error(messages.scheduleError));
|
||||
|
@ -200,6 +237,13 @@ export function submitCompose(routerHistory, force = false) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (to && status) {
|
||||
const mentions = status.match(/(?:^|\s|\.)@([a-z0-9_]+(?:@[a-z0-9\.\-]+)?)/gi); // not a perfect regex
|
||||
|
||||
if (mentions)
|
||||
to = to.union(mentions.map(mention => mention.trim().slice(1)));
|
||||
}
|
||||
|
||||
dispatch(submitComposeRequest());
|
||||
dispatch(closeModal());
|
||||
|
||||
|
@ -208,6 +252,7 @@ export function submitCompose(routerHistory, force = false) {
|
|||
const params = {
|
||||
status,
|
||||
in_reply_to_id: state.getIn(['compose', 'in_reply_to'], null),
|
||||
quote_id: state.getIn(['compose', 'quote'], null),
|
||||
media_ids: media.map(item => item.get('id')),
|
||||
sensitive: state.getIn(['compose', 'sensitive']),
|
||||
spoiler_text: state.getIn(['compose', 'spoiler_text'], ''),
|
||||
|
@ -215,6 +260,7 @@ export function submitCompose(routerHistory, force = false) {
|
|||
content_type: state.getIn(['compose', 'content_type']),
|
||||
poll: state.getIn(['compose', 'poll'], null),
|
||||
scheduled_at: state.getIn(['compose', 'schedule'], null),
|
||||
to,
|
||||
};
|
||||
|
||||
dispatch(createStatus(params, idempotencyKey)).then(function(data) {
|
||||
|
@ -251,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);
|
||||
|
@ -643,3 +688,27 @@ export function openComposeWithText(text = '') {
|
|||
dispatch(changeCompose(text));
|
||||
};
|
||||
}
|
||||
|
||||
export function addToMentions(accountId) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
||||
|
||||
return dispatch({
|
||||
type: COMPOSE_ADD_TO_MENTIONS,
|
||||
account: acct,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function removeFromMentions(accountId) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
||||
|
||||
return dispatch({
|
||||
type: COMPOSE_REMOVE_FROM_MENTIONS,
|
||||
account: acct,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import {
|
||||
importFetchedAccounts,
|
||||
importFetchedStatuses,
|
||||
importFetchedStatus,
|
||||
} from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
export const CONVERSATIONS_MOUNT = 'CONVERSATIONS_MOUNT';
|
||||
export const CONVERSATIONS_UNMOUNT = 'CONVERSATIONS_UNMOUNT';
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import api from '../api';
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
export const DIRECTORY_FETCH_REQUEST = 'DIRECTORY_FETCH_REQUEST';
|
||||
export const DIRECTORY_FETCH_SUCCESS = 'DIRECTORY_FETCH_SUCCESS';
|
||||
export const DIRECTORY_FETCH_FAIL = 'DIRECTORY_FETCH_FAIL';
|
||||
|
||||
export const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST';
|
||||
export const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS';
|
||||
export const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL';
|
||||
|
||||
export const fetchDirectory = params => (dispatch, getState) => {
|
||||
dispatch(fetchDirectoryRequest());
|
||||
|
||||
api(getState).get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchDirectorySuccess(data));
|
||||
dispatch(fetchRelationships(data.map(x => x.id)));
|
||||
}).catch(error => dispatch(fetchDirectoryFail(error)));
|
||||
};
|
||||
|
||||
export const fetchDirectoryRequest = () => ({
|
||||
type: DIRECTORY_FETCH_REQUEST,
|
||||
});
|
||||
|
||||
export const fetchDirectorySuccess = accounts => ({
|
||||
type: DIRECTORY_FETCH_SUCCESS,
|
||||
accounts,
|
||||
});
|
||||
|
||||
export const fetchDirectoryFail = error => ({
|
||||
type: DIRECTORY_FETCH_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
export const expandDirectory = params => (dispatch, getState) => {
|
||||
dispatch(expandDirectoryRequest());
|
||||
|
||||
const loadedItems = getState().getIn(['user_lists', 'directory', 'items']).size;
|
||||
|
||||
api(getState).get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(expandDirectorySuccess(data));
|
||||
dispatch(fetchRelationships(data.map(x => x.id)));
|
||||
}).catch(error => dispatch(expandDirectoryFail(error)));
|
||||
};
|
||||
|
||||
export const expandDirectoryRequest = () => ({
|
||||
type: DIRECTORY_EXPAND_REQUEST,
|
||||
});
|
||||
|
||||
export const expandDirectorySuccess = accounts => ({
|
||||
type: DIRECTORY_EXPAND_SUCCESS,
|
||||
accounts,
|
||||
});
|
||||
|
||||
export const expandDirectoryFail = error => ({
|
||||
type: DIRECTORY_EXPAND_FAIL,
|
||||
error,
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
export const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST';
|
||||
export const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS';
|
||||
export const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL';
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import { List as ImmutableList } from 'immutable';
|
||||
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
import { favourite, unfavourite } from './interactions';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
|
||||
export const EMOJI_REACT_REQUEST = 'EMOJI_REACT_REQUEST';
|
||||
export const EMOJI_REACT_SUCCESS = 'EMOJI_REACT_SUCCESS';
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { defineMessages } from 'react-intl';
|
||||
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
export const EXPORT_FOLLOWS_REQUEST = 'EXPORT_FOLLOWS_REQUEST';
|
||||
|
|
|
@ -6,21 +6,25 @@
|
|||
* @see module:soapbox/actions/oauth
|
||||
*/
|
||||
|
||||
import { baseClient } from '../api';
|
||||
import { createApp } from 'soapbox/actions/apps';
|
||||
import { obtainOAuthToken } from 'soapbox/actions/oauth';
|
||||
import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
|
||||
import { parseBaseURL } from 'soapbox/utils/auth';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import sourceCode from 'soapbox/utils/code';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
||||
import { createApp } from 'soapbox/actions/apps';
|
||||
import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
|
||||
import { obtainOAuthToken } from 'soapbox/actions/oauth';
|
||||
import { parseBaseURL } from 'soapbox/utils/auth';
|
||||
import sourceCode from 'soapbox/utils/code';
|
||||
import { getWalletAndSign } from 'soapbox/utils/ethereum';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { getQuirks } from 'soapbox/utils/quirks';
|
||||
|
||||
import { baseClient } from '../api';
|
||||
|
||||
const fetchExternalInstance = baseURL => {
|
||||
return baseClient(null, baseURL)
|
||||
.get('/api/v1/instance')
|
||||
.then(({ data: instance }) => fromJS(instance))
|
||||
.catch(error => {
|
||||
if (error.response && error.response.status === 401) {
|
||||
if (error.response?.status === 401) {
|
||||
// Authenticated fetch is enabled.
|
||||
// Continue with a limited featureset.
|
||||
return ImmutableMap({ version: '0.0.0' });
|
||||
|
@ -30,36 +34,86 @@ const fetchExternalInstance = baseURL => {
|
|||
});
|
||||
};
|
||||
|
||||
export function createAppAndRedirect(host) {
|
||||
function createExternalApp(instance, baseURL) {
|
||||
return (dispatch, getState) => {
|
||||
// Mitra: skip creating the auth app
|
||||
if (getQuirks(instance).noApps) return new Promise(f => f({}));
|
||||
|
||||
const { scopes } = getFeatures(instance);
|
||||
|
||||
const params = {
|
||||
client_name: sourceCode.displayName,
|
||||
redirect_uris: `${window.location.origin}/auth/external`,
|
||||
website: sourceCode.homepage,
|
||||
scopes,
|
||||
};
|
||||
|
||||
return dispatch(createApp(params, baseURL));
|
||||
};
|
||||
}
|
||||
|
||||
function externalAuthorize(instance, baseURL) {
|
||||
return (dispatch, getState) => {
|
||||
const { scopes } = getFeatures(instance);
|
||||
|
||||
return dispatch(createExternalApp(instance, baseURL)).then(app => {
|
||||
const { client_id, redirect_uri } = app;
|
||||
|
||||
const query = new URLSearchParams({
|
||||
client_id,
|
||||
redirect_uri,
|
||||
response_type: 'code',
|
||||
scope: scopes,
|
||||
});
|
||||
|
||||
localStorage.setItem('soapbox:external:app', JSON.stringify(app));
|
||||
localStorage.setItem('soapbox:external:baseurl', baseURL);
|
||||
localStorage.setItem('soapbox:external:scopes', scopes);
|
||||
|
||||
window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function externalEthereumLogin(instance, baseURL) {
|
||||
return (dispatch, getState) => {
|
||||
const loginMessage = instance.get('login_message');
|
||||
|
||||
return getWalletAndSign(loginMessage).then(({ wallet, signature }) => {
|
||||
return dispatch(createExternalApp(instance, baseURL)).then(app => {
|
||||
const params = {
|
||||
grant_type: 'ethereum',
|
||||
wallet_address: wallet.toLowerCase(),
|
||||
client_id: app.client_id,
|
||||
client_secret: app.client_secret,
|
||||
password: signature,
|
||||
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
||||
scope: getFeatures(instance).scopes,
|
||||
};
|
||||
|
||||
return dispatch(obtainOAuthToken(params, baseURL))
|
||||
.then(token => dispatch(authLoggedIn(token)))
|
||||
.then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL)))
|
||||
.then(account => dispatch(switchAccount(account.id)))
|
||||
.then(() => window.location.href = '/');
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function externalLogin(host) {
|
||||
return (dispatch, getState) => {
|
||||
const baseURL = parseBaseURL(host) || parseBaseURL(`https://${host}`);
|
||||
|
||||
return fetchExternalInstance(baseURL).then(instance => {
|
||||
const { scopes } = getFeatures(instance);
|
||||
const features = getFeatures(instance);
|
||||
const quirks = getQuirks(instance);
|
||||
|
||||
const params = {
|
||||
client_name: sourceCode.displayName,
|
||||
redirect_uris: `${window.location.origin}/auth/external`,
|
||||
website: sourceCode.homepage,
|
||||
scopes,
|
||||
};
|
||||
|
||||
return dispatch(createApp(params, baseURL)).then(app => {
|
||||
const { client_id, redirect_uri } = app;
|
||||
|
||||
const query = new URLSearchParams({
|
||||
client_id,
|
||||
redirect_uri,
|
||||
response_type: 'code',
|
||||
scope: scopes,
|
||||
});
|
||||
|
||||
localStorage.setItem('soapbox:external:app', JSON.stringify(app));
|
||||
localStorage.setItem('soapbox:external:baseurl', baseURL);
|
||||
localStorage.setItem('soapbox:external:scopes', scopes);
|
||||
|
||||
window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`;
|
||||
});
|
||||
if (features.ethereumLogin && quirks.noOAuthForm) {
|
||||
return dispatch(externalEthereumLogin(instance, baseURL));
|
||||
} else {
|
||||
return dispatch(externalAuthorize(instance, baseURL));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { importFetchedStatuses } from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
export const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST';
|
||||
export const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS';
|
||||
export const FAVOURITED_STATUSES_FETCH_FAIL = 'FAVOURITED_STATUSES_FETCH_FAIL';
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { defineMessages } from 'react-intl';
|
||||
import api from '../api';
|
||||
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST';
|
||||
export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS';
|
||||
export const FILTERS_FETCH_FAIL = 'FILTERS_FETCH_FAIL';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import api from '../api';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
export const GROUP_CREATE_REQUEST = 'GROUP_CREATE_REQUEST';
|
||||
export const GROUP_CREATE_SUCCESS = 'GROUP_CREATE_SUCCESS';
|
||||
export const GROUP_CREATE_FAIL = 'GROUP_CREATE_FAIL';
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
export const GROUP_FETCH_REQUEST = 'GROUP_FETCH_REQUEST';
|
||||
export const GROUP_FETCH_SUCCESS = 'GROUP_FETCH_SUCCESS';
|
||||
export const GROUP_FETCH_FAIL = 'GROUP_FETCH_FAIL';
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { defineMessages } from 'react-intl';
|
||||
import api from '../api';
|
||||
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
export const IMPORT_FOLLOWS_REQUEST = 'IMPORT_FOLLOWS_REQUEST';
|
||||
export const IMPORT_FOLLOWS_SUCCESS = 'IMPORT_FOLLOWS_SUCCESS';
|
||||
export const IMPORT_FOLLOWS_FAIL = 'IMPORT_FOLLOWS_FAIL';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { getSettings } from '../settings';
|
||||
|
||||
import {
|
||||
normalizeAccount,
|
||||
normalizeStatus,
|
||||
|
@ -12,12 +13,6 @@ export const STATUSES_IMPORT = 'STATUSES_IMPORT';
|
|||
export const POLLS_IMPORT = 'POLLS_IMPORT';
|
||||
export const ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP = 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP';
|
||||
|
||||
function pushUnique(array, object) {
|
||||
if (array.every(element => element.id !== object.id)) {
|
||||
array.push(object);
|
||||
}
|
||||
}
|
||||
|
||||
export function importAccount(account) {
|
||||
return { type: ACCOUNT_IMPORT, account };
|
||||
}
|
||||
|
@ -48,7 +43,7 @@ export function importFetchedAccounts(accounts) {
|
|||
function processAccount(account) {
|
||||
if (!account.id) return;
|
||||
|
||||
pushUnique(normalAccounts, normalizeAccount(account));
|
||||
normalAccounts.push(normalizeAccount(account));
|
||||
|
||||
if (account.moved) {
|
||||
processAccount(account.moved);
|
||||
|
@ -70,11 +65,20 @@ export function importFetchedStatus(status, idempotencyKey) {
|
|||
|
||||
const normalizedStatus = normalizeStatus(status, normalOldStatus, expandSpoilers);
|
||||
|
||||
if (status.reblog && status.reblog.id) {
|
||||
if (status.reblog?.id) {
|
||||
dispatch(importFetchedStatus(status.reblog));
|
||||
}
|
||||
|
||||
if (status.poll && status.poll.id) {
|
||||
// Fedibird quotes
|
||||
if (status.quote?.id) {
|
||||
dispatch(importFetchedStatus(status.quote));
|
||||
}
|
||||
|
||||
if (status.pleroma?.quote?.id) {
|
||||
dispatch(importFetchedStatus(status.pleroma.quote));
|
||||
}
|
||||
|
||||
if (status.poll?.id) {
|
||||
dispatch(importFetchedPoll(status.poll));
|
||||
}
|
||||
|
||||
|
@ -112,15 +116,24 @@ export function importFetchedStatuses(statuses) {
|
|||
const normalOldStatus = getState().getIn(['statuses', status.id]);
|
||||
const expandSpoilers = getSettings(getState()).get('expandSpoilers');
|
||||
|
||||
pushUnique(normalStatuses, normalizeStatus(status, normalOldStatus, expandSpoilers));
|
||||
pushUnique(accounts, status.account);
|
||||
normalStatuses.push(normalizeStatus(status, normalOldStatus, expandSpoilers));
|
||||
accounts.push(status.account);
|
||||
|
||||
if (status.reblog && status.reblog.id) {
|
||||
if (status.reblog?.id) {
|
||||
processStatus(status.reblog);
|
||||
}
|
||||
|
||||
if (status.poll && status.poll.id) {
|
||||
pushUnique(polls, normalizePoll(status.poll));
|
||||
// Fedibird quotes
|
||||
if (status.quote?.id) {
|
||||
processStatus(status.quote);
|
||||
}
|
||||
|
||||
if (status.pleroma?.quote?.id) {
|
||||
processStatus(status.pleroma.quote);
|
||||
}
|
||||
|
||||
if (status.poll?.id) {
|
||||
polls.push(normalizePoll(status.poll));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import escapeTextContentForBrowser from 'escape-html';
|
||||
|
||||
import { stripCompatibilityFeatures } from 'soapbox/utils/html';
|
||||
|
||||
import emojify from '../../features/emoji/emoji';
|
||||
import { unescapeHTML } from '../../utils/html';
|
||||
|
||||
|
@ -12,6 +15,13 @@ const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
|
|||
export function normalizeAccount(account) {
|
||||
account = { ...account };
|
||||
|
||||
// Some backends can return null, or omit these required fields
|
||||
if (!account.emojis) account.emojis = [];
|
||||
if (!account.display_name) account.display_name = '';
|
||||
if (!account.note) account.note = '';
|
||||
if (!account.avatar) account.avatar = account.avatar_static || require('images/avatar-missing.png');
|
||||
if (!account.avatar_static) account.avatar_static = account.avatar;
|
||||
|
||||
const emojiMap = makeEmojiMap(account);
|
||||
const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name;
|
||||
|
||||
|
@ -36,18 +46,39 @@ export function normalizeAccount(account) {
|
|||
}
|
||||
|
||||
export function normalizeStatus(status, normalOldStatus, expandSpoilers) {
|
||||
const normalStatus = { ...status };
|
||||
const normalStatus = { ...status };
|
||||
|
||||
// Some backends can return null, or omit these required fields
|
||||
if (!normalStatus.emojis) normalStatus.emojis = [];
|
||||
if (!normalStatus.spoiler_text) normalStatus.spoiler_text = '';
|
||||
|
||||
// Copy the pleroma object too, so we can modify our copy
|
||||
if (status.pleroma) {
|
||||
normalStatus.pleroma = { ...status.pleroma };
|
||||
}
|
||||
|
||||
normalStatus.account = status.account.id;
|
||||
|
||||
if (status.reblog && status.reblog.id) {
|
||||
if (status.reblog?.id) {
|
||||
normalStatus.reblog = status.reblog.id;
|
||||
}
|
||||
|
||||
if (status.poll && status.poll.id) {
|
||||
if (status.poll?.id) {
|
||||
normalStatus.poll = status.poll.id;
|
||||
}
|
||||
|
||||
if (status.pleroma?.quote?.id) {
|
||||
// Normalize quote to the top-level, so delete the original for performance
|
||||
normalStatus.quote = status.pleroma.quote.id;
|
||||
delete normalStatus.pleroma.quote;
|
||||
} else if (status.quote?.id) {
|
||||
// Fedibird compatibility, because why not
|
||||
normalStatus.quote = status.quote.id;
|
||||
} else if (status.quote_id) {
|
||||
// Fedibird: fall back to quote_id
|
||||
normalStatus.quote = status.quote_id;
|
||||
}
|
||||
|
||||
// Only calculate these values when status first encountered
|
||||
// Otherwise keep the ones already in the reducer
|
||||
if (normalOldStatus) {
|
||||
|
@ -57,11 +88,11 @@ export function normalizeStatus(status, normalOldStatus, expandSpoilers) {
|
|||
normalStatus.hidden = normalOldStatus.get('hidden');
|
||||
} else {
|
||||
const spoilerText = normalStatus.spoiler_text || '';
|
||||
const searchContent = ([spoilerText, status.content].concat((status.poll && status.poll.options) ? status.poll.options.map(option => option.title) : [])).join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
|
||||
const searchContent = ([spoilerText, status.content].concat((status.poll?.options) ? status.poll.options.map(option => option.title) : [])).join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
|
||||
const emojiMap = makeEmojiMap(normalStatus);
|
||||
|
||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
|
||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||
normalStatus.contentHtml = stripCompatibilityFeatures(emojify(normalStatus.content, emojiMap));
|
||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
|
||||
}
|
||||
|
@ -76,7 +107,7 @@ export function normalizePoll(poll) {
|
|||
|
||||
normalPoll.options = poll.options.map((option, index) => ({
|
||||
...option,
|
||||
voted: poll.own_votes && poll.own_votes.includes(index),
|
||||
voted: Boolean(poll.own_votes?.includes(index)),
|
||||
title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap),
|
||||
}));
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import api from '../api';
|
||||
import { get } from 'lodash';
|
||||
import { parseVersion } from 'soapbox/utils/features';
|
||||
import { getAuthUserUrl } from 'soapbox/utils/auth';
|
||||
|
||||
import KVStore from 'soapbox/storage/kv_store';
|
||||
import { getAuthUserUrl } from 'soapbox/utils/auth';
|
||||
import { parseVersion } from 'soapbox/utils/features';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
export const INSTANCE_FETCH_REQUEST = 'INSTANCE_FETCH_REQUEST';
|
||||
export const INSTANCE_FETCH_SUCCESS = 'INSTANCE_FETCH_SUCCESS';
|
||||
|
@ -22,7 +24,7 @@ const getMeUrl = state => {
|
|||
};
|
||||
|
||||
// Figure out the appropriate instance to fetch depending on the state
|
||||
const getHost = state => {
|
||||
export const getHost = state => {
|
||||
const accountUrl = getMeUrl(state) || getAuthUserUrl(state);
|
||||
|
||||
try {
|
||||
|
@ -59,6 +61,7 @@ export function fetchInstance() {
|
|||
dispatch(fetchNodeinfo()); // Pleroma < 2.1 backwards compatibility
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
dispatch({ type: INSTANCE_FETCH_FAIL, error, skipAlert: true });
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { defineMessages } from 'react-intl';
|
||||
import api from '../api';
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
||||
|
||||
export const REBLOG_REQUEST = 'REBLOG_REQUEST';
|
||||
export const REBLOG_SUCCESS = 'REBLOG_SUCCESS';
|
||||
export const REBLOG_FAIL = 'REBLOG_FAIL';
|
||||
|
@ -48,9 +51,14 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST';
|
|||
export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS';
|
||||
export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL';
|
||||
|
||||
export const REMOTE_INTERACTION_REQUEST = 'REMOTE_INTERACTION_REQUEST';
|
||||
export const REMOTE_INTERACTION_SUCCESS = 'REMOTE_INTERACTION_SUCCESS';
|
||||
export const REMOTE_INTERACTION_FAIL = 'REMOTE_INTERACTION_FAIL';
|
||||
|
||||
const messages = defineMessages({
|
||||
bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' },
|
||||
bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' },
|
||||
view: { id: 'snackbar.view', defaultMessage: 'View' },
|
||||
});
|
||||
|
||||
export function reblog(status) {
|
||||
|
@ -77,7 +85,6 @@ export function unreblog(status) {
|
|||
dispatch(unreblogRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unreblogSuccess(status));
|
||||
}).catch(error => {
|
||||
dispatch(unreblogFail(status, error));
|
||||
|
@ -157,7 +164,6 @@ export function unfavourite(status) {
|
|||
dispatch(unfavouriteRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unfavouriteSuccess(status));
|
||||
}).catch(error => {
|
||||
dispatch(unfavouriteFail(status, error));
|
||||
|
@ -215,28 +221,28 @@ export function unfavouriteFail(status, error) {
|
|||
};
|
||||
}
|
||||
|
||||
export function bookmark(intl, status) {
|
||||
export function bookmark(status) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(bookmarkRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function(response) {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(bookmarkSuccess(status, response.data));
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.bookmarkAdded)));
|
||||
dispatch(snackbar.success(messages.bookmarkAdded, messages.view, '/bookmarks'));
|
||||
}).catch(function(error) {
|
||||
dispatch(bookmarkFail(status, error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function unbookmark(intl, status) {
|
||||
export function unbookmark(status) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unbookmarkRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
dispatch(unbookmarkSuccess(status, response.data));
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.bookmarkRemoved)));
|
||||
dispatch(snackbar.success(messages.bookmarkRemoved));
|
||||
}).catch(error => {
|
||||
dispatch(unbookmarkFail(status, error));
|
||||
});
|
||||
|
@ -477,3 +483,46 @@ export function unpinFail(status, error) {
|
|||
skipLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function remoteInteraction(ap_id, profile) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(remoteInteractionRequest(ap_id, profile));
|
||||
|
||||
return api(getState).post('/api/v1/pleroma/remote_interaction', { ap_id, profile }).then(({ data }) => {
|
||||
if (data.error) throw new Error(data.error);
|
||||
|
||||
dispatch(remoteInteractionSuccess(ap_id, profile, data.url));
|
||||
|
||||
return data.url;
|
||||
}).catch(error => {
|
||||
dispatch(remoteInteractionFail(ap_id, profile, error));
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function remoteInteractionRequest(ap_id, profile) {
|
||||
return {
|
||||
type: REMOTE_INTERACTION_REQUEST,
|
||||
ap_id,
|
||||
profile,
|
||||
};
|
||||
}
|
||||
|
||||
export function remoteInteractionSuccess(ap_id, profile, url) {
|
||||
return {
|
||||
type: REMOTE_INTERACTION_SUCCESS,
|
||||
ap_id,
|
||||
profile,
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
||||
export function remoteInteractionFail(ap_id, profile, error) {
|
||||
return {
|
||||
type: REMOTE_INTERACTION_FAIL,
|
||||
ap_id,
|
||||
profile,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { showAlertForError } from './alerts';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { showAlertForError } from './alerts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
|
||||
export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
|
||||
export const LIST_FETCH_FAIL = 'LIST_FETCH_FAIL';
|
||||
|
@ -367,7 +369,7 @@ export const fetchAccountLists = accountId => (dispatch, getState) => {
|
|||
};
|
||||
|
||||
export const fetchAccountListsRequest = id => ({
|
||||
type:LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||
type: LIST_ADDER_LISTS_FETCH_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccount } from './importer';
|
||||
import { loadCredentials } from './auth';
|
||||
import { getAuthUserId, getAuthUserUrl } from 'soapbox/utils/auth';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { loadCredentials } from './auth';
|
||||
import { importFetchedAccount } from './importer';
|
||||
|
||||
export const ME_FETCH_REQUEST = 'ME_FETCH_REQUEST';
|
||||
export const ME_FETCH_SUCCESS = 'ME_FETCH_SUCCESS';
|
||||
export const ME_FETCH_FAIL = 'ME_FETCH_FAIL';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import api from '../api';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
const noOp = () => {};
|
||||
|
||||
export function fetchMedia(mediaId) {
|
||||
|
|
|
@ -1,180 +1,84 @@
|
|||
import api from '../api';
|
||||
|
||||
export const TOTP_SETTINGS_FETCH_REQUEST = 'TOTP_SETTINGS_FETCH_REQUEST';
|
||||
export const TOTP_SETTINGS_FETCH_SUCCESS = 'TOTP_SETTINGS_FETCH_SUCCESS';
|
||||
export const TOTP_SETTINGS_FETCH_FAIL = 'TOTP_SETTINGS_FETCH_FAIL';
|
||||
export const MFA_FETCH_REQUEST = 'MFA_FETCH_REQUEST';
|
||||
export const MFA_FETCH_SUCCESS = 'MFA_FETCH_SUCCESS';
|
||||
export const MFA_FETCH_FAIL = 'MFA_FETCH_FAIL';
|
||||
|
||||
export const BACKUP_CODES_FETCH_REQUEST = 'BACKUP_CODES_FETCH_REQUEST';
|
||||
export const BACKUP_CODES_FETCH_SUCCESS = 'BACKUP_CODES_FETCH_SUCCESS';
|
||||
export const BACKUP_CODES_FETCH_FAIL = 'BACKUP_CODES_FETCH_FAIL';
|
||||
export const MFA_BACKUP_CODES_FETCH_REQUEST = 'MFA_BACKUP_CODES_FETCH_REQUEST';
|
||||
export const MFA_BACKUP_CODES_FETCH_SUCCESS = 'MFA_BACKUP_CODES_FETCH_SUCCESS';
|
||||
export const MFA_BACKUP_CODES_FETCH_FAIL = 'MFA_BACKUP_CODES_FETCH_FAIL';
|
||||
|
||||
export const TOTP_SETUP_FETCH_REQUEST = 'TOTP_SETUP_FETCH_REQUEST';
|
||||
export const TOTP_SETUP_FETCH_SUCCESS = 'TOTP_SETUP_FETCH_SUCCESS';
|
||||
export const TOTP_SETUP_FETCH_FAIL = 'TOTP_SETUP_FETCH_FAIL';
|
||||
export const MFA_SETUP_REQUEST = 'MFA_SETUP_REQUEST';
|
||||
export const MFA_SETUP_SUCCESS = 'MFA_SETUP_SUCCESS';
|
||||
export const MFA_SETUP_FAIL = 'MFA_SETUP_FAIL';
|
||||
|
||||
export const CONFIRM_TOTP_REQUEST = 'CONFIRM_TOTP_REQUEST';
|
||||
export const CONFIRM_TOTP_SUCCESS = 'CONFIRM_TOTP_SUCCESS';
|
||||
export const CONFIRM_TOTP_FAIL = 'CONFIRM_TOTP_FAIL';
|
||||
export const MFA_CONFIRM_REQUEST = 'MFA_CONFIRM_REQUEST';
|
||||
export const MFA_CONFIRM_SUCCESS = 'MFA_CONFIRM_SUCCESS';
|
||||
export const MFA_CONFIRM_FAIL = 'MFA_CONFIRM_FAIL';
|
||||
|
||||
export const DISABLE_TOTP_REQUEST = 'DISABLE_TOTP_REQUEST';
|
||||
export const DISABLE_TOTP_SUCCESS = 'DISABLE_TOTP_SUCCESS';
|
||||
export const DISABLE_TOTP_FAIL = 'DISABLE_TOTP_FAIL';
|
||||
export const MFA_DISABLE_REQUEST = 'MFA_DISABLE_REQUEST';
|
||||
export const MFA_DISABLE_SUCCESS = 'MFA_DISABLE_SUCCESS';
|
||||
export const MFA_DISABLE_FAIL = 'MFA_DISABLE_FAIL';
|
||||
|
||||
export function fetchUserMfaSettings() {
|
||||
export function fetchMfa() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: TOTP_SETTINGS_FETCH_REQUEST });
|
||||
return api(getState).get('/api/pleroma/accounts/mfa').then(response => {
|
||||
dispatch({ type: TOTP_SETTINGS_FETCH_SUCCESS, totpEnabled: response.data.totp });
|
||||
return response;
|
||||
dispatch({ type: MFA_FETCH_REQUEST });
|
||||
return api(getState).get('/api/pleroma/accounts/mfa').then(({ data }) => {
|
||||
dispatch({ type: MFA_FETCH_SUCCESS, data });
|
||||
}).catch(error => {
|
||||
dispatch({ type: TOTP_SETTINGS_FETCH_FAIL });
|
||||
dispatch({ type: MFA_FETCH_FAIL });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchUserMfaSettingsRequest() {
|
||||
return {
|
||||
type: TOTP_SETTINGS_FETCH_REQUEST,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchUserMfaSettingsSuccess() {
|
||||
return {
|
||||
type: TOTP_SETTINGS_FETCH_SUCCESS,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchUserMfaSettingsFail() {
|
||||
return {
|
||||
type: TOTP_SETTINGS_FETCH_FAIL,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBackupCodes() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: BACKUP_CODES_FETCH_REQUEST });
|
||||
return api(getState).get('/api/pleroma/accounts/mfa/backup_codes').then(response => {
|
||||
dispatch({ type: BACKUP_CODES_FETCH_SUCCESS, backup_codes: response.data });
|
||||
return response;
|
||||
dispatch({ type: MFA_BACKUP_CODES_FETCH_REQUEST });
|
||||
return api(getState).get('/api/pleroma/accounts/mfa/backup_codes').then(({ data }) => {
|
||||
dispatch({ type: MFA_BACKUP_CODES_FETCH_SUCCESS, data });
|
||||
return data;
|
||||
}).catch(error => {
|
||||
dispatch({ type: BACKUP_CODES_FETCH_FAIL });
|
||||
dispatch({ type: MFA_BACKUP_CODES_FETCH_FAIL });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBackupCodesRequest() {
|
||||
return {
|
||||
type: BACKUP_CODES_FETCH_REQUEST,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBackupCodesSuccess(backup_codes, response) {
|
||||
return {
|
||||
type: BACKUP_CODES_FETCH_SUCCESS,
|
||||
backup_codes: response.data,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBackupCodesFail(error) {
|
||||
return {
|
||||
type: BACKUP_CODES_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchToptSetup() {
|
||||
export function setupMfa(method) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: TOTP_SETUP_FETCH_REQUEST });
|
||||
return api(getState).get('/api/pleroma/accounts/mfa/setup/totp').then(response => {
|
||||
dispatch({ type: TOTP_SETUP_FETCH_SUCCESS, totp_setup: response.data });
|
||||
return response;
|
||||
dispatch({ type: MFA_SETUP_REQUEST, method });
|
||||
return api(getState).get(`/api/pleroma/accounts/mfa/setup/${method}`).then(({ data }) => {
|
||||
dispatch({ type: MFA_SETUP_SUCCESS, data });
|
||||
return data;
|
||||
}).catch(error => {
|
||||
dispatch({ type: TOTP_SETUP_FETCH_FAIL });
|
||||
dispatch({ type: MFA_SETUP_FAIL });
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchToptSetupRequest() {
|
||||
return {
|
||||
type: TOTP_SETUP_FETCH_REQUEST,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchToptSetupSuccess(totp_setup, response) {
|
||||
return {
|
||||
type: TOTP_SETUP_FETCH_SUCCESS,
|
||||
totp_setup: response.data,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchToptSetupFail(error) {
|
||||
return {
|
||||
type: TOTP_SETUP_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function confirmToptSetup(code, password) {
|
||||
export function confirmMfa(method, code, password) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: CONFIRM_TOTP_REQUEST, code });
|
||||
return api(getState).post('/api/pleroma/accounts/mfa/confirm/totp', {
|
||||
code,
|
||||
password,
|
||||
}).then(response => {
|
||||
dispatch({ type: CONFIRM_TOTP_SUCCESS });
|
||||
return response;
|
||||
const params = { code, password };
|
||||
dispatch({ type: MFA_CONFIRM_REQUEST, method, code });
|
||||
return api(getState).post(`/api/pleroma/accounts/mfa/confirm/${method}`, params).then(({ data }) => {
|
||||
dispatch({ type: MFA_CONFIRM_SUCCESS, method, code });
|
||||
return data;
|
||||
}).catch(error => {
|
||||
dispatch({ type: CONFIRM_TOTP_FAIL });
|
||||
dispatch({ type: MFA_CONFIRM_FAIL, method, code, error, skipAlert: true });
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function confirmToptRequest() {
|
||||
return {
|
||||
type: CONFIRM_TOTP_REQUEST,
|
||||
};
|
||||
}
|
||||
|
||||
export function confirmToptSuccess(backup_codes, response) {
|
||||
return {
|
||||
type: CONFIRM_TOTP_SUCCESS,
|
||||
};
|
||||
}
|
||||
|
||||
export function confirmToptFail(error) {
|
||||
return {
|
||||
type: CONFIRM_TOTP_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function disableToptSetup(password) {
|
||||
export function disableMfa(method, password) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: DISABLE_TOTP_REQUEST });
|
||||
return api(getState).delete('/api/pleroma/accounts/mfa/totp', { data: { password } }).then(response => {
|
||||
dispatch({ type: DISABLE_TOTP_SUCCESS });
|
||||
return response;
|
||||
dispatch({ type: MFA_DISABLE_REQUEST, method });
|
||||
return api(getState).delete(`/api/pleroma/accounts/mfa/${method}`, { data: { password } }).then(({ data }) => {
|
||||
dispatch({ type: MFA_DISABLE_SUCCESS, method });
|
||||
return data;
|
||||
}).catch(error => {
|
||||
dispatch({ type: DISABLE_TOTP_FAIL });
|
||||
dispatch({ type: MFA_DISABLE_FAIL, method, skipAlert: true });
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function disableToptRequest() {
|
||||
return {
|
||||
type: DISABLE_TOTP_REQUEST,
|
||||
};
|
||||
}
|
||||
|
||||
export function disableToptSuccess(backup_codes, response) {
|
||||
return {
|
||||
type: DISABLE_TOTP_SUCCESS,
|
||||
};
|
||||
}
|
||||
|
||||
export function disableToptFail(error) {
|
||||
return {
|
||||
type: DISABLE_TOTP_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
import React from 'react';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import { openModal } from 'soapbox/actions/modal';
|
||||
import { deactivateUsers, deleteUsers, deleteStatus, toggleStatusSensitivity } from 'soapbox/actions/admin';
|
||||
|
||||
import { fetchAccountByUsername } from 'soapbox/actions/accounts';
|
||||
import { deactivateUsers, deleteUsers, deleteStatus, toggleStatusSensitivity } from 'soapbox/actions/admin';
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import AccountContainer from 'soapbox/containers/account_container';
|
||||
import { isLocal } from 'soapbox/utils/accounts';
|
||||
|
||||
const messages = defineMessages({
|
||||
deactivateUserHeading: { id: 'confirmations.admin.deactivate_user.heading', defaultMessage: 'Deactivate @{acct}' },
|
||||
deactivateUserPrompt: { id: 'confirmations.admin.deactivate_user.message', defaultMessage: 'You are about to deactivate @{acct}. Deactivating a user is a reversible action.' },
|
||||
deactivateUserConfirm: { id: 'confirmations.admin.deactivate_user.confirm', defaultMessage: 'Deactivate @{name}' },
|
||||
userDeactivated: { id: 'admin.users.user_deactivated_message', defaultMessage: '@{acct} was deactivated' },
|
||||
deleteUserHeading: { id: 'confirmations.admin.delete_user.heading', defaultMessage: 'Delete @{acct}' },
|
||||
deleteUserPrompt: { id: 'confirmations.admin.delete_user.message', defaultMessage: 'You are about to delete @{acct}. THIS IS A DESTRUCTIVE ACTION THAT CANNOT BE UNDONE.' },
|
||||
deleteUserConfirm: { id: 'confirmations.admin.delete_user.confirm', defaultMessage: 'Delete @{name}' },
|
||||
deleteLocalUserCheckbox: { id: 'confirmations.admin.delete_local_user.checkbox', defaultMessage: 'I understand that I am about to delete a local user.' },
|
||||
userDeleted: { id: 'admin.users.user_deleted_message', defaultMessage: '@{acct} was deleted' },
|
||||
deleteStatusHeading: { id: 'confirmations.admin.delete_status.heading', defaultMessage: 'Delete post' },
|
||||
deleteStatusPrompt: { id: 'confirmations.admin.delete_status.message', defaultMessage: 'You are about to delete a post by @{acct}. This action cannot be undone.' },
|
||||
deleteStatusConfirm: { id: 'confirmations.admin.delete_status.confirm', defaultMessage: 'Delete post' },
|
||||
rejectUserHeading: { id: 'confirmations.admin.reject_user.heading', defaultMessage: 'Reject @{acct}' },
|
||||
rejectUserPrompt: { id: 'confirmations.admin.reject_user.message', defaultMessage: 'You are about to reject @{acct} registration request. This action cannot be undone.' },
|
||||
rejectUserConfirm: { id: 'confirmations.admin.reject_user.confirm', defaultMessage: 'Reject @{name}' },
|
||||
statusDeleted: { id: 'admin.statuses.status_deleted_message', defaultMessage: 'Post by @{acct} was deleted' },
|
||||
markStatusSensitiveHeading: { id: 'confirmations.admin.mark_status_sensitive.heading', defaultMessage: 'Mark post sensitive' },
|
||||
markStatusNotSensitiveHeading: { id: 'confirmations.admin.mark_status_not_sensitive.heading', defaultMessage: 'Mark post not sensitive.' },
|
||||
markStatusSensitivePrompt: { id: 'confirmations.admin.mark_status_sensitive.message', defaultMessage: 'You are about to mark a post by @{acct} sensitive.' },
|
||||
markStatusNotSensitivePrompt: { id: 'confirmations.admin.mark_status_not_sensitive.message', defaultMessage: 'You are about to mark a post by @{acct} not sensitive.' },
|
||||
markStatusSensitiveConfirm: { id: 'confirmations.admin.mark_status_sensitive.confirm', defaultMessage: 'Mark post sensitive' },
|
||||
|
@ -33,6 +42,8 @@ export function deactivateUserModal(intl, accountId, afterConfirm = () => {}) {
|
|||
const name = state.getIn(['accounts', accountId, 'username']);
|
||||
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: require('@tabler/icons/icons/user-off.svg'),
|
||||
heading: intl.formatMessage(messages.deactivateUserHeading, { acct }),
|
||||
message: intl.formatMessage(messages.deactivateUserPrompt, { acct }),
|
||||
confirm: intl.formatMessage(messages.deactivateUserConfirm, { name }),
|
||||
onConfirm: () => {
|
||||
|
@ -70,6 +81,8 @@ export function deleteUserModal(intl, accountId, afterConfirm = () => {}) {
|
|||
const checkbox = local ? intl.formatMessage(messages.deleteLocalUserCheckbox) : false;
|
||||
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: require('@tabler/icons/icons/user-minus.svg'),
|
||||
heading: intl.formatMessage(messages.deleteUserHeading, { acct }),
|
||||
message,
|
||||
confirm,
|
||||
checkbox,
|
||||
|
@ -85,6 +98,28 @@ export function deleteUserModal(intl, accountId, afterConfirm = () => {}) {
|
|||
};
|
||||
}
|
||||
|
||||
export function rejectUserModal(intl, accountId, afterConfirm = () => {}) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState();
|
||||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
||||
const name = state.getIn(['accounts', accountId, 'username']);
|
||||
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: require('@tabler/icons/icons/user-off.svg'),
|
||||
heading: intl.formatMessage(messages.rejectUserHeading, { acct }),
|
||||
message: intl.formatMessage(messages.rejectUserPrompt, { acct }),
|
||||
confirm: intl.formatMessage(messages.rejectUserConfirm, { name }),
|
||||
onConfirm: () => {
|
||||
dispatch(deleteUsers([accountId]))
|
||||
.then(() => {
|
||||
afterConfirm();
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
export function toggleStatusSensitivityModal(intl, statusId, sensitive, afterConfirm = () => {}) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState();
|
||||
|
@ -92,6 +127,8 @@ export function toggleStatusSensitivityModal(intl, statusId, sensitive, afterCon
|
|||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
||||
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: require('@tabler/icons/icons/alert-triangle.svg'),
|
||||
heading: intl.formatMessage(sensitive === false ? messages.markStatusSensitiveHeading : messages.markStatusNotSensitiveHeading),
|
||||
message: intl.formatMessage(sensitive === false ? messages.markStatusSensitivePrompt : messages.markStatusNotSensitivePrompt, { acct }),
|
||||
confirm: intl.formatMessage(sensitive === false ? messages.markStatusSensitiveConfirm : messages.markStatusNotSensitiveConfirm),
|
||||
onConfirm: () => {
|
||||
|
@ -112,6 +149,8 @@ export function deleteStatusModal(intl, statusId, afterConfirm = () => {}) {
|
|||
const acct = state.getIn(['accounts', accountId, 'acct']);
|
||||
|
||||
dispatch(openModal('CONFIRM', {
|
||||
icon: require('@tabler/icons/icons/trash.svg'),
|
||||
heading: intl.formatMessage(messages.deleteStatusHeading),
|
||||
message: intl.formatMessage(messages.deleteStatusPrompt, { acct }),
|
||||
confirm: intl.formatMessage(messages.deleteStatusConfirm),
|
||||
onConfirm: () => {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { fetchConfig, updateConfig } from './admin';
|
||||
import { Set as ImmutableSet } from 'immutable';
|
||||
|
||||
import ConfigDB from 'soapbox/utils/config_db';
|
||||
|
||||
import { fetchConfig, updateConfig } from './admin';
|
||||
|
||||
const simplePolicyMerge = (simplePolicy, host, restrictions) => {
|
||||
return simplePolicy.map((hosts, key) => {
|
||||
const isRestricted = restrictions.get(key);
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { openModal } from './modal';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getNextLinkName } from 'soapbox/utils/quirks';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { openModal } from './modals';
|
||||
|
||||
export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST';
|
||||
export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS';
|
||||
export const MUTES_FETCH_FAIL = 'MUTES_FETCH_FAIL';
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
import api, { getLinks } from '../api';
|
||||
import {
|
||||
List as ImmutableList,
|
||||
Map as ImmutableMap,
|
||||
OrderedMap as ImmutableOrderedMap,
|
||||
} from 'immutable';
|
||||
import IntlMessageFormat from 'intl-messageformat';
|
||||
import 'intl-pluralrules';
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { parseVersion, PLEROMA } from 'soapbox/utils/features';
|
||||
import { joinPublicPath } from 'soapbox/utils/static';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
import { getFilters, regexFromFilters } from '../selectors';
|
||||
import { unescapeHTML } from '../utils/html';
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import {
|
||||
importFetchedAccount,
|
||||
|
@ -10,17 +24,6 @@ import {
|
|||
} from './importer';
|
||||
import { saveMarker } from './markers';
|
||||
import { getSettings, saveSettings } from './settings';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import {
|
||||
List as ImmutableList,
|
||||
Map as ImmutableMap,
|
||||
OrderedMap as ImmutableOrderedMap,
|
||||
} from 'immutable';
|
||||
import { unescapeHTML } from '../utils/html';
|
||||
import { getFilters, regexFromFilters } from '../selectors';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { parseVersion, PLEROMA } from 'soapbox/utils/features';
|
||||
import { joinPublicPath } from 'soapbox/utils/static';
|
||||
|
||||
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
||||
export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP';
|
||||
|
@ -115,7 +118,7 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale,
|
|||
data: {
|
||||
url: joinPublicPath('/notifications'),
|
||||
},
|
||||
});
|
||||
}).catch(console.error);
|
||||
}).catch(console.error);
|
||||
}
|
||||
} catch(e) {
|
||||
|
@ -203,16 +206,16 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
|||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
const entries = response.data.reduce((acc, item) => {
|
||||
if (item.account && item.account.id) {
|
||||
if (item.account?.id) {
|
||||
acc.accounts[item.account.id] = item.account;
|
||||
}
|
||||
|
||||
// Used by Move notification
|
||||
if (item.target && item.target.id) {
|
||||
if (item.target?.id) {
|
||||
acc.accounts[item.target.id] = item.target;
|
||||
}
|
||||
|
||||
if (item.status && item.status.id) {
|
||||
if (item.status?.id) {
|
||||
acc.statuses[item.status.id] = item.status;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import api from '../api';
|
||||
import { importFetchedStatuses } from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
|
||||
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
|
||||
export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import api from '../api';
|
||||
|
||||
import { importFetchedPoll } from './importer';
|
||||
|
||||
export const POLL_VOTE_REQUEST = 'POLL_VOTE_REQUEST';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { mapValues } from 'lodash';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
import { verifyCredentials } from './auth';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
export const PLEROMA_PRELOAD_IMPORT = 'PLEROMA_PRELOAD_IMPORT';
|
||||
export const MASTODON_PRELOAD_IMPORT = 'MASTODON_PRELOAD_IMPORT';
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { register, saveSettings } from './registerer';
|
||||
import {
|
||||
SET_BROWSER_SUPPORT,
|
||||
SET_SUBSCRIPTION,
|
||||
|
@ -5,7 +6,6 @@ import {
|
|||
SET_ALERTS,
|
||||
setAlerts,
|
||||
} from './setter';
|
||||
import { register, saveSettings } from './registerer';
|
||||
|
||||
export {
|
||||
SET_BROWSER_SUPPORT,
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { decode as decodeBase64 } from '../../utils/base64';
|
||||
import { pushNotificationsSetting } from '../../settings';
|
||||
import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
|
||||
import { createPushSubsription, updatePushSubscription } from 'soapbox/actions/push_subscriptions';
|
||||
import { getVapidKey } from 'soapbox/utils/auth';
|
||||
|
||||
import { pushNotificationsSetting } from '../../settings';
|
||||
import { decode as decodeBase64 } from '../../utils/base64';
|
||||
|
||||
import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
|
||||
|
||||
// Taken from https://www.npmjs.com/package/web-push
|
||||
const urlBase64ToUint8Array = (base64String) => {
|
||||
|
@ -13,11 +16,6 @@ const urlBase64ToUint8Array = (base64String) => {
|
|||
return decodeBase64(base64);
|
||||
};
|
||||
|
||||
const getVapidKey = getState => {
|
||||
const state = getState();
|
||||
return state.getIn(['auth', 'app', 'vapid_key']) || state.getIn(['instance', 'pleroma', 'vapid_public_key']);
|
||||
};
|
||||
|
||||
const getRegistration = () => navigator.serviceWorker.ready;
|
||||
|
||||
const getPushSubscription = (registration) =>
|
||||
|
@ -27,7 +25,7 @@ const getPushSubscription = (registration) =>
|
|||
const subscribe = (registration, getState) =>
|
||||
registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState)),
|
||||
applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState())),
|
||||
});
|
||||
|
||||
const unsubscribe = ({ registration, subscription }) =>
|
||||
|
@ -35,7 +33,8 @@ const unsubscribe = ({ registration, subscription }) =>
|
|||
|
||||
const sendSubscriptionToBackend = (subscription, me) => {
|
||||
return (dispatch, getState) => {
|
||||
const params = { subscription };
|
||||
const alerts = getState().getIn(['push_notifications', 'alerts']).toJS();
|
||||
const params = { subscription, data: { alerts } };
|
||||
|
||||
if (me) {
|
||||
const data = pushNotificationsSetting.get(me);
|
||||
|
@ -54,7 +53,7 @@ const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager'
|
|||
export function register() {
|
||||
return (dispatch, getState) => {
|
||||
const me = getState().get('me');
|
||||
const vapidKey = getVapidKey(getState);
|
||||
const vapidKey = getVapidKey(getState());
|
||||
|
||||
dispatch(setBrowserSupport(supportsPushNotifications));
|
||||
|
||||
|
@ -105,6 +104,7 @@ export function register() {
|
|||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
if (error.code === 20 && error.name === 'AbortError') {
|
||||
console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.');
|
||||
} else if (error.code === 5 && error.name === 'InvalidCharacterError') {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import api from '../api';
|
||||
import { openModal, closeModal } from './modal';
|
||||
|
||||
import { openModal, closeModal } from './modals';
|
||||
|
||||
export const REPORT_INIT = 'REPORT_INIT';
|
||||
export const REPORT_CANCEL = 'REPORT_CANCEL';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import api from '../api';
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||
|
||||
|
@ -17,9 +18,16 @@ export const SEARCH_EXPAND_SUCCESS = 'SEARCH_EXPAND_SUCCESS';
|
|||
export const SEARCH_EXPAND_FAIL = 'SEARCH_EXPAND_FAIL';
|
||||
|
||||
export function changeSearch(value) {
|
||||
return {
|
||||
type: SEARCH_CHANGE,
|
||||
value,
|
||||
return (dispatch, getState) => {
|
||||
// If backspaced all the way, clear the search
|
||||
if (value.length === 0) {
|
||||
return dispatch(clearSearch());
|
||||
} else {
|
||||
return dispatch({
|
||||
type: SEARCH_CHANGE,
|
||||
value,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -29,10 +37,12 @@ export function clearSearch() {
|
|||
};
|
||||
}
|
||||
|
||||
export function submitSearch() {
|
||||
export function submitSearch(filter) {
|
||||
return (dispatch, getState) => {
|
||||
const value = getState().getIn(['search', 'value']);
|
||||
const type = filter || getState().getIn(['search', 'filter'], 'accounts');
|
||||
|
||||
// An empty search doesn't return any results
|
||||
if (value.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -44,6 +54,7 @@ export function submitSearch() {
|
|||
q: value,
|
||||
resolve: true,
|
||||
limit: 20,
|
||||
type,
|
||||
},
|
||||
}).then(response => {
|
||||
if (response.data.accounts) {
|
||||
|
@ -54,7 +65,7 @@ export function submitSearch() {
|
|||
dispatch(importFetchedStatuses(response.data.statuses));
|
||||
}
|
||||
|
||||
dispatch(fetchSearchSuccess(response.data));
|
||||
dispatch(fetchSearchSuccess(response.data, value, type));
|
||||
dispatch(fetchRelationships(response.data.accounts.map(item => item.id)));
|
||||
}).catch(error => {
|
||||
dispatch(fetchSearchFail(error));
|
||||
|
@ -69,10 +80,12 @@ export function fetchSearchRequest(value) {
|
|||
};
|
||||
}
|
||||
|
||||
export function fetchSearchSuccess(results) {
|
||||
export function fetchSearchSuccess(results, searchTerm, searchType) {
|
||||
return {
|
||||
type: SEARCH_FETCH_SUCCESS,
|
||||
results,
|
||||
searchTerm,
|
||||
searchType,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -83,13 +96,17 @@ export function fetchSearchFail(error) {
|
|||
};
|
||||
}
|
||||
|
||||
export const setFilter = filterType => dispatch => {
|
||||
dispatch({
|
||||
type: SEARCH_FILTER_SET,
|
||||
path: ['search', 'filter'],
|
||||
value: filterType,
|
||||
});
|
||||
};
|
||||
export function setFilter(filterType) {
|
||||
return (dispatch) => {
|
||||
dispatch(submitSearch(filterType));
|
||||
|
||||
dispatch({
|
||||
type: SEARCH_FILTER_SET,
|
||||
path: ['search', 'filter'],
|
||||
value: filterType,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const expandSearch = type => (dispatch, getState) => {
|
||||
const value = getState().getIn(['search', 'value']);
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
* @see module:soapbox/actions/auth
|
||||
*/
|
||||
|
||||
import api from '../api';
|
||||
import { getLoggedInAccount } from 'soapbox/utils/auth';
|
||||
import snackbar from 'soapbox/actions/snackbar';
|
||||
import { getLoggedInAccount } from 'soapbox/utils/auth';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { AUTH_LOGGED_OUT, messages } from './auth';
|
||||
|
||||
export const FETCH_TOKENS_REQUEST = 'FETCH_TOKENS_REQUEST';
|
||||
|
@ -33,6 +35,10 @@ export const DELETE_ACCOUNT_REQUEST = 'DELETE_ACCOUNT_REQUEST';
|
|||
export const DELETE_ACCOUNT_SUCCESS = 'DELETE_ACCOUNT_SUCCESS';
|
||||
export const DELETE_ACCOUNT_FAIL = 'DELETE_ACCOUNT_FAIL';
|
||||
|
||||
export const MOVE_ACCOUNT_REQUEST = 'MOVE_ACCOUNT_REQUEST';
|
||||
export const MOVE_ACCOUNT_SUCCESS = 'MOVE_ACCOUNT_SUCCESS';
|
||||
export const MOVE_ACCOUNT_FAIL = 'MOVE_ACCOUNT_FAIL';
|
||||
|
||||
export function fetchOAuthTokens() {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: FETCH_TOKENS_REQUEST });
|
||||
|
@ -122,3 +128,19 @@ export function deleteAccount(intl, password) {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function moveAccount(targetAccount, password) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: MOVE_ACCOUNT_REQUEST });
|
||||
return api(getState).post('/api/pleroma/move_account', {
|
||||
password,
|
||||
target_account: targetAccount,
|
||||
}).then(response => {
|
||||
if (response.data.error) throw response.data.error; // This endpoint returns HTTP 200 even on failure
|
||||
dispatch({ type: MOVE_ACCOUNT_SUCCESS, response });
|
||||
}).catch(error => {
|
||||
dispatch({ type: MOVE_ACCOUNT_FAIL, error, skipAlert: true });
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import { debounce } from 'lodash';
|
||||
import { showAlertForError } from './alerts';
|
||||
import { patchMe } from 'soapbox/actions/me';
|
||||
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import uuid from '../uuid';
|
||||
import { debounce } from 'lodash';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { patchMe } from 'soapbox/actions/me';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
|
||||
import uuid from '../uuid';
|
||||
|
||||
import { showAlertForError } from './alerts';
|
||||
|
||||
export const SETTING_CHANGE = 'SETTING_CHANGE';
|
||||
export const SETTING_SAVE = 'SETTING_SAVE';
|
||||
export const SETTINGS_UPDATE = 'SETTINGS_UPDATE';
|
||||
|
||||
export const FE_NAME = 'soapbox_fe';
|
||||
|
||||
|
@ -30,7 +34,6 @@ export const defaultSettings = ImmutableMap({
|
|||
locale: navigator.language.split(/[-_]/)[0] || 'en',
|
||||
showExplanationBox: true,
|
||||
explanationBox: true,
|
||||
otpEnabled: false,
|
||||
autoloadTimelines: true,
|
||||
autoloadMore: true,
|
||||
|
||||
|
@ -97,12 +100,17 @@ export const defaultSettings = ImmutableMap({
|
|||
move: false,
|
||||
'pleroma:emoji_reaction': false,
|
||||
}),
|
||||
|
||||
birthdays: ImmutableMap({
|
||||
show: true,
|
||||
}),
|
||||
}),
|
||||
|
||||
community: ImmutableMap({
|
||||
shows: ImmutableMap({
|
||||
reblog: false,
|
||||
reply: true,
|
||||
direct: false,
|
||||
}),
|
||||
other: ImmutableMap({
|
||||
onlyMedia: false,
|
||||
|
@ -116,6 +124,7 @@ export const defaultSettings = ImmutableMap({
|
|||
shows: ImmutableMap({
|
||||
reblog: true,
|
||||
reply: true,
|
||||
direct: false,
|
||||
}),
|
||||
other: ImmutableMap({
|
||||
onlyMedia: false,
|
||||
|
@ -135,6 +144,7 @@ export const defaultSettings = ImmutableMap({
|
|||
shows: ImmutableMap({
|
||||
reblog: true,
|
||||
pinned: true,
|
||||
direct: false,
|
||||
}),
|
||||
}),
|
||||
|
||||
|
@ -162,6 +172,18 @@ export const getSettings = createSelector([
|
|||
.mergeDeep(settings);
|
||||
});
|
||||
|
||||
export function changeSettingImmediate(path, value) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
type: SETTING_CHANGE,
|
||||
path,
|
||||
value,
|
||||
});
|
||||
|
||||
dispatch(saveSettingsImmediate());
|
||||
};
|
||||
}
|
||||
|
||||
export function changeSetting(path, value) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
|
@ -174,23 +196,29 @@ export function changeSetting(path, value) {
|
|||
};
|
||||
}
|
||||
|
||||
export function saveSettingsImmediate() {
|
||||
return (dispatch, getState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
const state = getState();
|
||||
if (getSettings(state).getIn(['saved'])) return;
|
||||
|
||||
const data = state.get('settings').delete('saved').toJS();
|
||||
|
||||
dispatch(patchMe({
|
||||
pleroma_settings_store: {
|
||||
[FE_NAME]: data,
|
||||
},
|
||||
})).then(response => {
|
||||
dispatch({ type: SETTING_SAVE });
|
||||
}).catch(error => {
|
||||
dispatch(showAlertForError(error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const debouncedSave = debounce((dispatch, getState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
const state = getState();
|
||||
if (getSettings(state).getIn(['saved'])) return;
|
||||
|
||||
const data = state.get('settings').delete('saved').toJS();
|
||||
|
||||
dispatch(patchMe({
|
||||
pleroma_settings_store: {
|
||||
[FE_NAME]: data,
|
||||
},
|
||||
})).then(response => {
|
||||
dispatch({ type: SETTING_SAVE });
|
||||
}).catch(error => {
|
||||
dispatch(showAlertForError(error));
|
||||
});
|
||||
dispatch(saveSettingsImmediate());
|
||||
}, 5000, { trailing: true });
|
||||
|
||||
export function saveSettings() {
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
import { ALERT_SHOW } from './alerts';
|
||||
|
||||
export const show = (severity, message) => ({
|
||||
export const show = (severity, message, actionLabel, actionLink) => ({
|
||||
type: ALERT_SHOW,
|
||||
message,
|
||||
actionLabel,
|
||||
actionLink,
|
||||
severity,
|
||||
});
|
||||
|
||||
export function info(message) {
|
||||
return show('info', message);
|
||||
export function info(message, actionLabel, actionLink) {
|
||||
return show('info', message, actionLabel, actionLink);
|
||||
}
|
||||
|
||||
export function success(message) {
|
||||
return show('success', message);
|
||||
export function success(message, actionLabel, actionLink) {
|
||||
return show('success', message, actionLabel, actionLink);
|
||||
}
|
||||
|
||||
export function error(message) {
|
||||
return show('error', message);
|
||||
export function error(message, actionLabel, actionLink) {
|
||||
return show('error', message, actionLabel, actionLink);
|
||||
}
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
import api, { staticClient } from '../api';
|
||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { getHost } from 'soapbox/actions/instance';
|
||||
import KVStore from 'soapbox/storage/kv_store';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import api, { staticClient } from '../api';
|
||||
|
||||
export const SOAPBOX_CONFIG_REQUEST_SUCCESS = 'SOAPBOX_CONFIG_REQUEST_SUCCESS';
|
||||
export const SOAPBOX_CONFIG_REQUEST_FAIL = 'SOAPBOX_CONFIG_REQUEST_FAIL';
|
||||
|
||||
export const SOAPBOX_CONFIG_REMEMBER_REQUEST = 'SOAPBOX_CONFIG_REMEMBER_REQUEST';
|
||||
export const SOAPBOX_CONFIG_REMEMBER_SUCCESS = 'SOAPBOX_CONFIG_REMEMBER_SUCCESS';
|
||||
export const SOAPBOX_CONFIG_REMEMBER_FAIL = 'SOAPBOX_CONFIG_REMEMBER_FAIL';
|
||||
|
||||
const allowedEmoji = ImmutableList([
|
||||
'👍',
|
||||
'❤',
|
||||
|
@ -61,46 +69,71 @@ export const getSoapboxConfig = createSelector([
|
|||
return makeDefaultConfig(features).merge(soapbox);
|
||||
});
|
||||
|
||||
export function fetchSoapboxConfig() {
|
||||
export function rememberSoapboxConfig(host) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: SOAPBOX_CONFIG_REMEMBER_REQUEST, host });
|
||||
return KVStore.getItemOrError(`soapbox_config:${host}`).then(soapboxConfig => {
|
||||
dispatch({ type: SOAPBOX_CONFIG_REMEMBER_SUCCESS, host, soapboxConfig });
|
||||
return soapboxConfig;
|
||||
}).catch(error => {
|
||||
dispatch({ type: SOAPBOX_CONFIG_REMEMBER_FAIL, host, error, skipAlert: true });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSoapboxConfig(host) {
|
||||
return (dispatch, getState) => {
|
||||
api(getState).get('/api/pleroma/frontend_configurations').then(response => {
|
||||
if (response.data.soapbox_fe) {
|
||||
dispatch(importSoapboxConfig(response.data.soapbox_fe));
|
||||
dispatch(importSoapboxConfig(response.data.soapbox_fe, host));
|
||||
} else {
|
||||
dispatch(fetchSoapboxJson());
|
||||
dispatch(fetchSoapboxJson(host));
|
||||
}
|
||||
}).catch(error => {
|
||||
dispatch(fetchSoapboxJson());
|
||||
dispatch(fetchSoapboxJson(host));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSoapboxJson() {
|
||||
// Tries to remember the config from browser storage before fetching it
|
||||
export function loadSoapboxConfig() {
|
||||
return (dispatch, getState) => {
|
||||
const host = getHost(getState());
|
||||
|
||||
return dispatch(rememberSoapboxConfig(host)).finally(() => {
|
||||
return dispatch(fetchSoapboxConfig(host));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSoapboxJson(host) {
|
||||
return (dispatch, getState) => {
|
||||
staticClient.get('/instance/soapbox.json').then(({ data }) => {
|
||||
if (!isObject(data)) throw 'soapbox.json failed';
|
||||
dispatch(importSoapboxConfig(data));
|
||||
dispatch(importSoapboxConfig(data, host));
|
||||
}).catch(error => {
|
||||
dispatch(soapboxConfigFail(error));
|
||||
dispatch(soapboxConfigFail(error, host));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function importSoapboxConfig(soapboxConfig) {
|
||||
export function importSoapboxConfig(soapboxConfig, host) {
|
||||
if (!soapboxConfig.brandColor) {
|
||||
soapboxConfig.brandColor = '#0482d8';
|
||||
}
|
||||
return {
|
||||
type: SOAPBOX_CONFIG_REQUEST_SUCCESS,
|
||||
soapboxConfig,
|
||||
host,
|
||||
};
|
||||
}
|
||||
|
||||
export function soapboxConfigFail(error) {
|
||||
export function soapboxConfigFail(error, host) {
|
||||
return {
|
||||
type: SOAPBOX_CONFIG_REQUEST_FAIL,
|
||||
error,
|
||||
skipAlert: true,
|
||||
host,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import api from '../api';
|
||||
import { deleteFromTimelines } from './timelines';
|
||||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||
import { openModal } from './modal';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { shouldHaveCard } from 'soapbox/utils/status';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||
import { openModal } from './modals';
|
||||
import { deleteFromTimelines } from './timelines';
|
||||
|
||||
export const STATUS_CREATE_REQUEST = 'STATUS_CREATE_REQUEST';
|
||||
export const STATUS_CREATE_SUCCESS = 'STATUS_CREATE_SUCCESS';
|
||||
|
@ -44,8 +48,31 @@ export function createStatus(params, idempotencyKey) {
|
|||
return api(getState).post('/api/v1/statuses', params, {
|
||||
headers: { 'Idempotency-Key': idempotencyKey },
|
||||
}).then(({ data: status }) => {
|
||||
// The backend might still be processing the rich media attachment
|
||||
if (!status.card && shouldHaveCard(status)) {
|
||||
status.expectsCard = true;
|
||||
}
|
||||
|
||||
dispatch(importFetchedStatus(status, idempotencyKey));
|
||||
dispatch({ type: STATUS_CREATE_SUCCESS, status, params, idempotencyKey });
|
||||
|
||||
// Poll the backend for the updated card
|
||||
if (status.expectsCard) {
|
||||
const delay = 1000;
|
||||
|
||||
const poll = (retries = 5) => {
|
||||
api(getState).get(`/api/v1/statuses/${status.id}`).then(response => {
|
||||
if (response.data?.card) {
|
||||
dispatch(importFetchedStatus(response.data));
|
||||
} else if (retries > 0 && response.status === 200) {
|
||||
setTimeout(() => poll(retries - 1), delay);
|
||||
}
|
||||
}).catch(console.error);
|
||||
};
|
||||
|
||||
setTimeout(() => poll(), delay);
|
||||
}
|
||||
|
||||
return status;
|
||||
}).catch(error => {
|
||||
dispatch({ type: STATUS_CREATE_FAIL, error, params, idempotencyKey });
|
||||
|
@ -71,10 +98,17 @@ export function fetchStatus(id) {
|
|||
}
|
||||
|
||||
export function redraft(status, raw_text) {
|
||||
return {
|
||||
type: REDRAFT,
|
||||
status,
|
||||
raw_text,
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const instance = state.get('instance');
|
||||
const { explicitAddressing } = getFeatures(instance);
|
||||
|
||||
dispatch({
|
||||
type: REDRAFT,
|
||||
status,
|
||||
raw_text,
|
||||
explicitAddressing,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -109,13 +143,21 @@ export function fetchContext(id) {
|
|||
dispatch({ type: CONTEXT_FETCH_REQUEST, id });
|
||||
|
||||
return api(getState).get(`/api/v1/statuses/${id}/context`).then(({ data: context }) => {
|
||||
const { ancestors, descendants } = context;
|
||||
const statuses = ancestors.concat(descendants);
|
||||
dispatch(importFetchedStatuses(statuses));
|
||||
dispatch({ type: CONTEXT_FETCH_SUCCESS, id, ancestors, descendants });
|
||||
if (Array.isArray(context)) {
|
||||
// Mitra: returns a list of statuses
|
||||
dispatch(importFetchedStatuses(context));
|
||||
} else if (typeof context === 'object') {
|
||||
// Standard Mastodon API returns a map with `ancestors` and `descendants`
|
||||
const { ancestors, descendants } = context;
|
||||
const statuses = ancestors.concat(descendants);
|
||||
dispatch(importFetchedStatuses(statuses));
|
||||
dispatch({ type: CONTEXT_FETCH_SUCCESS, id, ancestors, descendants });
|
||||
} else {
|
||||
throw context;
|
||||
}
|
||||
return context;
|
||||
}).catch(error => {
|
||||
if (error.response && error.response.status === 404) {
|
||||
if (error.response?.status === 404) {
|
||||
dispatch(deleteFromTimelines(id));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import messages from 'soapbox/locales/messages';
|
||||
|
||||
import { connectStream } from '../stream';
|
||||
|
||||
import { updateConversations } from './conversations';
|
||||
import { fetchFilters } from './filters';
|
||||
import { updateNotificationsQueue, expandNotifications } from './notifications';
|
||||
import {
|
||||
deleteFromTimelines,
|
||||
expandHomeTimeline,
|
||||
|
@ -6,11 +13,6 @@ import {
|
|||
disconnectTimeline,
|
||||
processTimelineUpdate,
|
||||
} from './timelines';
|
||||
import { updateNotificationsQueue, expandNotifications } from './notifications';
|
||||
import { updateConversations } from './conversations';
|
||||
import { fetchFilters } from './filters';
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import messages from 'soapbox/locales/messages';
|
||||
|
||||
export const STREAMING_CHAT_UPDATE = 'STREAMING_CHAT_UPDATE';
|
||||
export const STREAMING_FOLLOW_RELATIONSHIPS_UPDATE = 'STREAMING_FOLLOW_RELATIONSHIPS_UPDATE';
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import api from '../api';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST';
|
||||
export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS';
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||
import api, { getLinks } from '../api';
|
||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
|
||||
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import { shouldFilter } from 'soapbox/utils/timelines';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||
|
||||
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
|
||||
export const TIMELINE_DELETE = 'TIMELINE_DELETE';
|
||||
export const TIMELINE_CLEAR = 'TIMELINE_CLEAR';
|
||||
|
@ -23,7 +26,7 @@ export const MAX_QUEUED_ITEMS = 40;
|
|||
export function processTimelineUpdate(timeline, status, accept) {
|
||||
return (dispatch, getState) => {
|
||||
const me = getState().get('me');
|
||||
const ownStatus = status.account && status.account.id === me;
|
||||
const ownStatus = status.account?.id === me;
|
||||
const hasPendingStatuses = !getState().get('pending_statuses').isEmpty();
|
||||
|
||||
const columnSettings = getSettings(getState()).get(timeline, ImmutableMap());
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
|
||||
import axios from 'axios';
|
||||
import LinkHeader from 'http-link-header';
|
||||
import { getAccessToken, getAppToken, parseBaseURL } from 'soapbox/utils/auth';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { BACKEND_URL, FE_SUBDIRECTORY } from 'soapbox/build_config';
|
||||
import { getAccessToken, getAppToken, parseBaseURL } from 'soapbox/utils/auth';
|
||||
import { isURL } from 'soapbox/utils/auth';
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,9 +4,10 @@ import 'intl';
|
|||
import 'intl/locale-data/jsonp/en';
|
||||
import 'es6-symbol/implement';
|
||||
import includes from 'array-includes';
|
||||
import isNaN from 'is-nan';
|
||||
import assign from 'object-assign';
|
||||
import values from 'object.values';
|
||||
import isNaN from 'is-nan';
|
||||
|
||||
import { decode as decodeBase64 } from './utils/base64';
|
||||
|
||||
if (!Array.prototype.includes) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
export default function InlineSVG({ src }) {
|
||||
return <svg id={src} />;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import AutosuggestEmoji from '../autosuggest_emoji';
|
||||
|
||||
describe('<AutosuggestEmoji />', () => {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import React from 'react';
|
||||
import { fromJS } from 'immutable';
|
||||
import React from 'react';
|
||||
|
||||
import { createComponent } from 'soapbox/test_helpers';
|
||||
|
||||
import Avatar from '../avatar';
|
||||
|
||||
describe('<Avatar />', () => {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import React from 'react';
|
||||
import { fromJS } from 'immutable';
|
||||
import React from 'react';
|
||||
|
||||
import { createComponent } from 'soapbox/test_helpers';
|
||||
|
||||
import AvatarOverlay from '../avatar_overlay';
|
||||
|
||||
describe('<AvatarOverlay', () => {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import Badge from '../badge';
|
||||
|
||||
describe('<Badge />', () => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import Button from '../button';
|
||||
|
||||
describe('<Button />', () => {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import Column from '../column';
|
||||
|
||||
describe('<Column />', () => {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import ColumnBackButton from '../column_back_button';
|
||||
|
||||
import { createComponent } from 'soapbox/test_helpers';
|
||||
|
||||
import ColumnBackButton from '../column_back_button';
|
||||
|
||||
describe('<ColumnBackButton />', () => {
|
||||
it('renders correctly', () => {
|
||||
const component = createComponent(<ColumnBackButton />);
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import React from 'react';
|
||||
import { fromJS } from 'immutable';
|
||||
import DisplayName from '../display_name';
|
||||
import React from 'react';
|
||||
|
||||
import { createComponent } from 'soapbox/test_helpers';
|
||||
|
||||
import DisplayName from '../display_name';
|
||||
|
||||
describe('<DisplayName />', () => {
|
||||
it('renders display name + account name', () => {
|
||||
const account = fromJS({
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import React from 'react';
|
||||
|
||||
import { createComponent } from 'soapbox/test_helpers';
|
||||
|
||||
import EmojiSelector from '../emoji_selector';
|
||||
|
||||
describe('<EmojiSelector />', () => {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import React from 'react';
|
||||
import TimelineQueueButtonHeader from '../timeline_queue_button_header';
|
||||
import { createComponent } from 'soapbox/test_helpers';
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
import { createComponent } from 'soapbox/test_helpers';
|
||||
|
||||
import TimelineQueueButtonHeader from '../timeline_queue_button_header';
|
||||
|
||||
const messages = defineMessages({
|
||||
queue: { id: 'status_list.queue_label', defaultMessage: 'Click to see {count} new {count, plural, one {post} other {posts}}' },
|
||||
});
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Fragment } from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import emojify from 'soapbox/features/emoji/emoji';
|
||||
import ActionButton from 'soapbox/features/ui/components/action_button';
|
||||
|
||||
import Avatar from './avatar';
|
||||
import DisplayName from './display_name';
|
||||
import Permalink from './permalink';
|
||||
import Icon from './icon';
|
||||
import IconButton from './icon_button';
|
||||
import ActionButton from 'soapbox/features/ui/components/action_button';
|
||||
import Permalink from './permalink';
|
||||
import RelativeTimestamp from './relative_timestamp';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import classNames from 'classnames';
|
||||
import emojify from 'soapbox/features/emoji/emoji';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import AutosuggestAccountInput from 'soapbox/components/autosuggest_account_input';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import AutosuggestAccountInput from 'soapbox/components/autosuggest_account_input';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'account_search.placeholder', defaultMessage: 'Search for an account' },
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import Icon from 'soapbox/components/icon';
|
||||
|
||||
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { MediaGallery } from 'soapbox/features/ui/util/async-components';
|
||||
import { openModal } from 'soapbox/actions/modal';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import Bundle from 'soapbox/features/ui/components/bundle';
|
||||
import { MediaGallery } from 'soapbox/features/ui/util/async-components';
|
||||
|
||||
export default @connect()
|
||||
class AttachmentThumbs extends ImmutablePureComponent {
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import React from 'react';
|
||||
import AutosuggestInput from './autosuggest_input';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CancelToken } from 'axios';
|
||||
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
import { throttle } from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
|
||||
import { accountSearch } from 'soapbox/actions/accounts';
|
||||
import { throttle } from 'lodash';
|
||||
|
||||
import AutosuggestInput from './autosuggest_input';
|
||||
|
||||
const noOp = () => {};
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light';
|
||||
import React from 'react';
|
||||
|
||||
import { joinPublicPath } from 'soapbox/utils/static';
|
||||
|
||||
import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light';
|
||||
|
||||
export default class AutosuggestEmoji extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import React from 'react';
|
||||
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
|
||||
import AutosuggestEmoji from './autosuggest_emoji';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import { isRtl } from '../rtl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import classNames from 'classnames';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import Icon from 'soapbox/components/icon';
|
||||
|
||||
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
|
||||
import { isRtl } from '../rtl';
|
||||
|
||||
import AutosuggestEmoji from './autosuggest_emoji';
|
||||
|
||||
const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => {
|
||||
let word;
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import React from 'react';
|
||||
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
|
||||
import AutosuggestEmoji from './autosuggest_emoji';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { isRtl } from '../rtl';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Textarea from 'react-textarea-autosize';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
|
||||
import { isRtl } from '../rtl';
|
||||
|
||||
import AutosuggestEmoji from './autosuggest_emoji';
|
||||
|
||||
const textAtCursorMatchesToken = (str, caretPosition) => {
|
||||
let word;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import StillImage from 'soapbox/components/still_image';
|
||||
|
||||
export default class Avatar extends React.PureComponent {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import StillImage from 'soapbox/components/still_image';
|
||||
|
||||
export default class AvatarComposite extends React.PureComponent {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import StillImage from 'soapbox/components/still_image';
|
||||
|
||||
export default class AvatarOverlay extends React.PureComponent {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const Badge = (props) => (
|
||||
<span className={'badge badge--' + props.slug}>{props.title}</span>
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import DatePicker from 'react-datepicker';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
|
||||
import IconButton from 'soapbox/components/icon_button';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
const messages = defineMessages({
|
||||
birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' },
|
||||
previousMonth: { id: 'datepicker.previous_month', defaultMessage: 'Previous month' },
|
||||
nextMonth: { id: 'datepicker.next_month', defaultMessage: 'Next month' },
|
||||
previousYear: { id: 'datepicker.previous_year', defaultMessage: 'Previous year' },
|
||||
nextYear: { id: 'datepicker.next_year', defaultMessage: 'Next year' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const features = getFeatures(state.get('instance'));
|
||||
|
||||
return {
|
||||
supportsBirthdays: features.birthdays,
|
||||
minAge: state.getIn(['instance', 'pleroma', 'metadata', 'birthday_min_age']),
|
||||
};
|
||||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class BirthdayInput extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
hint: PropTypes.node,
|
||||
required: PropTypes.bool,
|
||||
supportsBirthdays: PropTypes.bool,
|
||||
minAge: PropTypes.number,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.instanceOf(Date),
|
||||
};
|
||||
|
||||
renderHeader = ({
|
||||
decreaseMonth,
|
||||
increaseMonth,
|
||||
prevMonthButtonDisabled,
|
||||
nextMonthButtonDisabled,
|
||||
decreaseYear,
|
||||
increaseYear,
|
||||
prevYearButtonDisabled,
|
||||
nextYearButtonDisabled,
|
||||
date,
|
||||
}) => {
|
||||
const { intl } = this.props;
|
||||
|
||||
return (
|
||||
<div className='datepicker__header'>
|
||||
<div className='datepicker__months'>
|
||||
<IconButton
|
||||
className='datepicker__button'
|
||||
src={require('@tabler/icons/icons/chevron-left.svg')}
|
||||
onClick={decreaseMonth}
|
||||
disabled={prevMonthButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.previousMonth)}
|
||||
title={intl.formatMessage(messages.previousMonth)}
|
||||
/>
|
||||
{intl.formatDate(date, { month: 'long' })}
|
||||
<IconButton
|
||||
className='datepicker__button'
|
||||
src={require('@tabler/icons/icons/chevron-right.svg')}
|
||||
onClick={increaseMonth}
|
||||
disabled={nextMonthButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.nextMonth)}
|
||||
title={intl.formatMessage(messages.nextMonth)}
|
||||
/>
|
||||
</div>
|
||||
<div className='datepicker__years'>
|
||||
<IconButton
|
||||
className='datepicker__button'
|
||||
src={require('@tabler/icons/icons/chevron-left.svg')}
|
||||
onClick={decreaseYear}
|
||||
disabled={prevYearButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.previousYear)}
|
||||
title={intl.formatMessage(messages.previousYear)}
|
||||
/>
|
||||
{intl.formatDate(date, { year: 'numeric' })}
|
||||
<IconButton
|
||||
className='datepicker__button'
|
||||
src={require('@tabler/icons/icons/chevron-right.svg')}
|
||||
onClick={increaseYear}
|
||||
disabled={nextYearButtonDisabled}
|
||||
aria-label={intl.formatMessage(messages.nextYear)}
|
||||
title={intl.formatMessage(messages.nextYear)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl, value, onChange, supportsBirthdays, hint, required, minAge } = this.props;
|
||||
|
||||
if (!supportsBirthdays) return null;
|
||||
|
||||
let maxDate = new Date();
|
||||
maxDate = new Date(maxDate.getTime() - minAge * 1000 * 60 * 60 * 24 + maxDate.getTimezoneOffset() * 1000 * 60);
|
||||
|
||||
return (
|
||||
<div className='datepicker'>
|
||||
{hint && (
|
||||
<div className='datepicker__hint'>
|
||||
{hint}
|
||||
</div>
|
||||
)}
|
||||
<div className='datepicker__input'>
|
||||
<DatePicker
|
||||
selected={value}
|
||||
wrapperClassName='react-datepicker-wrapper'
|
||||
onChange={onChange}
|
||||
placeholderText={intl.formatMessage(messages.birthdayPlaceholder)}
|
||||
minDate={new Date('1900-01-01')}
|
||||
maxDate={maxDate}
|
||||
required={required}
|
||||
renderCustomHeader={this.renderHeader}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { fetchBirthdayReminders } from 'soapbox/actions/accounts';
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const me = state.get('me');
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const birthdays = state.getIn(['user_lists', 'birthday_reminders', me]);
|
||||
|
||||
if (birthdays?.size > 0) {
|
||||
return {
|
||||
birthdays,
|
||||
account: getAccount(state, birthdays.first()),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
birthdays,
|
||||
};
|
||||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class BirthdayReminders extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
birthdays: ImmutablePropTypes.orderedSet,
|
||||
intl: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
onMoveDown: PropTypes.func,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
const date = new Date();
|
||||
|
||||
const day = date.getDate();
|
||||
const month = date.getMonth() + 1;
|
||||
|
||||
dispatch(fetchBirthdayReminders(day, month));
|
||||
}
|
||||
|
||||
getHandlers() {
|
||||
return {
|
||||
open: this.handleOpenBirthdaysModal,
|
||||
moveDown: this.props.onMoveDown,
|
||||
};
|
||||
}
|
||||
|
||||
handleOpenBirthdaysModal = () => {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
dispatch(openModal('BIRTHDAYS'));
|
||||
}
|
||||
|
||||
renderMessage() {
|
||||
const { birthdays, account } = this.props;
|
||||
|
||||
const link = (
|
||||
<bdi>
|
||||
<Link
|
||||
className='notification__display-name'
|
||||
title={account.get('acct')}
|
||||
to={`/@${account.get('acct')}`}
|
||||
dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }}
|
||||
/>
|
||||
</bdi>
|
||||
);
|
||||
|
||||
if (birthdays.size === 1) {
|
||||
return <FormattedMessage id='notification.birthday' defaultMessage='{name} has birthday today' values={{ name: link }} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='notification.birthday_plural'
|
||||
defaultMessage='{name} and {more} have birthday today'
|
||||
values={{
|
||||
name: link,
|
||||
more: (
|
||||
<span type='button' role='presentation' onClick={this.handleOpenBirthdaysModal}>
|
||||
<FormattedMessage
|
||||
id='notification.birthday.more'
|
||||
defaultMessage='{count} more {count, plural, one {friend} other {friends}}'
|
||||
values={{ count: birthdays.size - 1 }}
|
||||
/>
|
||||
</span>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderMessageForScreenReader = () => {
|
||||
const { intl, birthdays, account } = this.props;
|
||||
|
||||
if (birthdays.size === 1) {
|
||||
return intl.formatMessage({ id: 'notification.birthday', defaultMessage: '{name} has birthday today' }, { name: account.get('display_name') });
|
||||
}
|
||||
|
||||
return intl.formatMessage(
|
||||
{
|
||||
id: 'notification.birthday_plural',
|
||||
defaultMessage: '{name} and {more} have birthday today',
|
||||
},
|
||||
{
|
||||
name: account.get('display_name'),
|
||||
more: intl.formatMessage(
|
||||
{
|
||||
id: 'notification.birthday.more',
|
||||
defaultMessage: '{count} more {count, plural, one {friend} other {friends}}',
|
||||
},
|
||||
{ count: birthdays.size - 1 },
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { birthdays } = this.props;
|
||||
|
||||
if (!birthdays || birthdays.size === 0) return null;
|
||||
|
||||
return (
|
||||
<HotKeys handlers={this.getHandlers()}>
|
||||
<div className='notification notification-birthday focusable' tabIndex='0' title={this.renderMessageForScreenReader()}>
|
||||
<div className='notification__message'>
|
||||
<div className='notification__icon-wrapper'>
|
||||
<Icon src={require('@tabler/icons/icons/ballon.svg')} />
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{this.renderMessage()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</HotKeys>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
// @ts-check
|
||||
|
||||
import { decode } from 'blurhash';
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* @typedef BlurhashPropsBase
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import Icon from './icon';
|
||||
|
||||
export default class Button extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
type: PropTypes.string,
|
||||
text: PropTypes.node,
|
||||
onClick: PropTypes.func,
|
||||
to: PropTypes.string,
|
||||
|
@ -53,6 +55,7 @@ export default class Button extends React.PureComponent {
|
|||
|
||||
const btn = (
|
||||
<button
|
||||
type={this.props.type}
|
||||
className={className}
|
||||
disabled={this.props.disabled}
|
||||
onClick={this.handleClick}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
export default class Column extends React.PureComponent {
|
||||
|
||||
|
@ -11,6 +11,10 @@ export default class Column extends React.PureComponent {
|
|||
label: PropTypes.string,
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, label, children, transparent, ...rest } = this.props;
|
||||
|
||||
|
@ -20,6 +24,7 @@ export default class Column extends React.PureComponent {
|
|||
aria-label={label}
|
||||
className={classNames('column', className, { 'column--transparent': transparent })}
|
||||
{...rest}
|
||||
ref={this.setRef}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Icon from 'soapbox/components/icon';
|
||||
|
||||
export default class ColumnBackButton extends React.PureComponent {
|
||||
|
@ -16,7 +17,7 @@ export default class ColumnBackButton extends React.PureComponent {
|
|||
handleClick = () => {
|
||||
const { to } = this.props;
|
||||
|
||||
if (window.history && window.history.length === 1) {
|
||||
if (window.history?.length === 1) {
|
||||
this.context.router.history.push(to ? to : '/');
|
||||
} else {
|
||||
this.context.router.history.goBack();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
// import classNames from 'classnames';
|
||||
// import { injectIntl, defineMessages } from 'react-intl';
|
||||
// import Icon from 'soapbox/components/icon';
|
||||
|
@ -33,7 +34,7 @@ export default class ColumnHeader extends React.PureComponent {
|
|||
};
|
||||
|
||||
historyBack = () => {
|
||||
if (window.history && window.history.length === 1) {
|
||||
if (window.history?.length === 1) {
|
||||
this.context.router.history.push('/');
|
||||
} else {
|
||||
this.context.router.history.goBack();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue