Merge remote-tracking branch 'soapbox/develop' into modals-stack

merge-requests/1017/head
marcin mikołajczak 3 years ago
commit 767c3dad7a

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,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,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&#39;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,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);
});
});

@ -13,7 +13,9 @@ import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/
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';
@ -32,11 +34,11 @@ const fetchExternalInstance = baseURL => {
});
};
export function createAppAndRedirect(host) {
function createExternalApp(instance, baseURL) {
return (dispatch, getState) => {
const baseURL = parseBaseURL(host) || parseBaseURL(`https://${host}`);
// Mitra: skip creating the auth app
if (getQuirks(instance).noApps) return new Promise(f => f({}));
return fetchExternalInstance(baseURL).then(instance => {
const { scopes } = getFeatures(instance);
const params = {
@ -46,7 +48,15 @@ export function createAppAndRedirect(host) {
scopes,
};
return dispatch(createApp(params, baseURL)).then(app => {
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({
@ -62,6 +72,48 @@ export function createAppAndRedirect(host) {
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 features = getFeatures(instance);
const quirks = getQuirks(instance);
if (features.ethereumLogin && quirks.noOAuthForm) {
return dispatch(externalEthereumLogin(instance, baseURL));
} else {
return dispatch(externalAuthorize(instance, baseURL));
}
});
};
}

@ -15,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;
@ -41,6 +48,10 @@ export function normalizeAccount(account) {
export function normalizeStatus(status, normalOldStatus, expandSpoilers) {
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 };

@ -61,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 });
});
};

@ -143,10 +143,18 @@ export function fetchContext(id) {
dispatch({ type: CONTEXT_FETCH_REQUEST, id });
return api(getState).get(`/api/v1/statuses/${id}/context`).then(({ data: context }) => {
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) {

@ -342,6 +342,10 @@ class StatusActionBar extends ImmutablePureComponent {
// });
}
if (!me) {
return menu;
}
if (features.bookmarks) {
menu.push({
text: intl.formatMessage(status.get('bookmarked') ? messages.unbookmark : messages.bookmark),
@ -350,10 +354,6 @@ class StatusActionBar extends ImmutablePureComponent {
});
}
if (!me) {
return menu;
}
menu.push(null);
if (ownAccount || withDismiss) {

@ -17,10 +17,13 @@ export default class SvgIcon extends React.PureComponent {
};
render() {
const { src, className } = this.props;
const { src, className, ...other } = this.props;
return (
<div className={classNames('svg-icon', className)}>
<div
className={classNames('svg-icon', className)}
{...other}
>
<InlineSVG src={src} />
</div>
);

@ -56,7 +56,9 @@ exports[`<LoginForm /> renders for Mastodon 1`] = `
style={Object {}}
>
<div
aria-hidden="true"
className="svg-icon"
fixedWidth={true}
>
<svg
id={
@ -150,7 +152,9 @@ exports[`<LoginForm /> renders for Pleroma 1`] = `
style={Object {}}
>
<div
aria-hidden="true"
className="svg-icon"
fixedWidth={true}
>
<svg
id={

@ -59,7 +59,9 @@ exports[`<LoginPage /> renders correctly on load 1`] = `
style={Object {}}
>
<div
aria-hidden="true"
className="svg-icon"
fixedWidth={true}
>
<svg
id={

@ -15,11 +15,10 @@ const messages = defineMessages({
const mapStateToProps = state => {
const instance = state.get('instance');
const features = getFeatures(instance);
return {
baseURL: getBaseURL(state),
hasResetPasswordAPI: features.resetPasswordAPI,
features: getFeatures(instance),
};
};
@ -28,7 +27,7 @@ export default @connect(mapStateToProps)
class LoginForm extends ImmutablePureComponent {
render() {
const { intl, isLoading, handleSubmit, baseURL, hasResetPasswordAPI } = this.props;
const { intl, isLoading, handleSubmit, baseURL, features } = this.props;
return (
<form className='simple_form new_user' method='post' onSubmit={handleSubmit}>
@ -57,12 +56,8 @@ class LoginForm extends ImmutablePureComponent {
autoCapitalize='off'
required
/>
{/* <div className='input password user_password'>
<input
/>
</div> */}
<p className='hint subtle-hint'>
{hasResetPasswordAPI ? (
{features.resetPasswordAPI ? (
<Link to='/auth/reset_password'>
<FormattedMessage id='login.reset_password_hint' defaultMessage='Trouble logging in?' />
</Link>

@ -3,7 +3,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { injectIntl, FormattedMessage, defineMessages } from 'react-intl';
import { connect } from 'react-redux';
import { createAppAndRedirect, loginWithCode } from 'soapbox/actions/external_auth';
import { externalLogin, loginWithCode } from 'soapbox/actions/external_auth';
import LoadingIndicator from 'soapbox/components/loading_indicator';
import { SimpleForm, FieldsGroup, TextInput } from 'soapbox/features/forms';
@ -31,7 +31,7 @@ class ExternalLoginForm extends ImmutablePureComponent {
this.setState({ isLoading: true });
dispatch(createAppAndRedirect(host))
dispatch(externalLogin(host))
.then(() => this.setState({ isLoading: false }))
.catch(() => this.setState({ isLoading: false }));
}

@ -68,8 +68,10 @@ class IconPickerMenu extends React.PureComponent {
if (!c) return;
// Nice and dirty hack to display the icons
c.querySelectorAll('button.emoji-mart-emoji > span').forEach(elem => {
elem.innerHTML = `<i class="fa fa-${elem.parentNode.getAttribute('title')}"></i>`;
c.querySelectorAll('button.emoji-mart-emoji > img').forEach(elem => {
const newIcon = document.createElement('span');
newIcon.innerHTML = `<i class="fa fa-${elem.parentNode.getAttribute('title')} fa-hack"></i>`;
elem.parentNode.replaceChild(newIcon, elem);
});
}

@ -345,6 +345,7 @@ class ActionBar extends React.PureComponent {
// });
}
if (me) {
if (features.bookmarks) {
menu.push({
text: intl.formatMessage(status.get('bookmarked') ? messages.unbookmark : messages.bookmark),
@ -353,7 +354,6 @@ class ActionBar extends React.PureComponent {
});
}
if (me) {
menu.push(null);
if (ownAccount) {

@ -25,6 +25,7 @@ const messages = defineMessages({
requested_small: { id: 'account.requested_small', defaultMessage: 'Awaiting approval' },
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
blocked: { id: 'account.blocked', defaultMessage: 'Blocked' },
});
const mapStateToProps = state => {
@ -132,8 +133,9 @@ class ActionButton extends ImmutablePureComponent {
return <Button className='logo-button' text={small ? intl.formatMessage(messages.requested_small) : intl.formatMessage(messages.requested)} onClick={this.handleFollow} />;
} else if (!account.getIn(['relationship', 'blocking'])) {
// Follow & Unfollow
const blocked_by = account.getIn(['relationship', 'blocked_by']);
return (<Button
disabled={account.getIn(['relationship', 'blocked_by'])}
disabled={blocked_by}
className={classNames('button--follow', {
'button--destructive': account.getIn(['relationship', 'following']),
})}
@ -143,8 +145,8 @@ class ActionButton extends ImmutablePureComponent {
intl.formatMessage(messages.unfollow)
) : (
<>
{intl.formatMessage(messages.follow)}
<Icon src={require('@tabler/icons/icons/plus.svg')} />
{ intl.formatMessage(blocked_by ? messages.blocked : messages.follow)}
<Icon src={blocked_by ? require('@tabler/icons/icons/ban.svg') : require('@tabler/icons/icons/plus.svg')} />
</>
)}
</Button>);

@ -670,14 +670,12 @@ class UI extends React.PureComponent {
}
render() {
const { streamingUrl, features, soapbox } = this.props;
const { features, soapbox } = this.props;
const { draggingOver, mobile } = this.state;
const { intl, children, location, dropdownMenuIsOpen, me } = this.props;
// Wait for login to succeed or fail
if (me === null) return null;
// If login didn't fail, wait for streaming to become available
if (me !== false && !streamingUrl) return null;
const handlers = me ? {
help: this.handleHotkeyToggleHelp,

File diff suppressed because it is too large Load Diff

@ -4,12 +4,12 @@
"accordion.expand": "Rozwiń",
"account.add_or_remove_from_list": "Dodaj lub usuń z list",
"account.badges.bot": "Bot",
"account.birthday": "Urodzony(-a) {date}",
"account.birthday_today": "Ma dziś urodziny!",
"account.block": "Blokuj @{name}",
"account.block_domain": "Blokuj wszystko z {domain}",
"account.blocked": "Zablokowany(-a)",
"account.chat": "Napisz do @{name}",
"account.column_settings.description": "Te ustawienia stosowane są do osi czasu wszystkich kont.",
"account.column_settings.title": "Ustawienia osi czasu konta",
"account.deactivated": "Dezaktywowany(-a)",
"account.deactivated_description": "To konto zostało zdezaktywowane.",
"account.direct": "Wyślij wiadomość bezpośrednią do @{name}",
@ -45,8 +45,8 @@
"account.share": "Udostępnij profil @{name}",
"account.show_reblogs": "Pokazuj podbicia od @{name}",
"account.subscribe": "Subskrybuj wpisy @{name}",
"account.subscribed": "Subscribed",
"account.unblock": "Zasubskrybowano",
"account.subscribed": "Subskrybujesz",
"account.unblock": "Odblokuj @{name}",
"account.unblock_domain": "Odblokuj domenę {domain}",
"account.unendorse": "Przestań polecać",
"account.unfollow": "Przestań śledzić",
@ -54,7 +54,6 @@
"account.unsubscribe": "Przestań subskrybować wpisy @{name}",
"account_gallery.none": "Brak zawartości multimedialnej do wyświetlenia.",
"account_search.placeholder": "Szukaj konta",
"account_timeline.column_settings.show_pinned": "Pokazuj przypięte wpisy",
"admin.awaiting_approval.approved_message": "Przyjęto {acct}!",
"admin.awaiting_approval.empty_message": "Nikt nie oczekuje przyjęcia. Gdy zarejestruje się nowy użytkownik, możesz zatwierdzić go tutaj.",
"admin.awaiting_approval.rejected_message": "Odrzucono {acct}!",
@ -148,7 +147,6 @@
"bundle_modal_error.close": "Zamknij",
"bundle_modal_error.message": "Coś poszło nie tak podczas ładowania tego składnika.",
"bundle_modal_error.retry": "Spróbuj ponownie",
"chat_box.actions.close": "Zamknij czat",
"chat_box.actions.send": "Wyślij",
"chat_box.input.placeholder": "Wyślij wiadomość…",
"chat_panels.main_window.empty": "Nie znaleziono rozmów. Aby zacząć rozmowę, odwiedź profil użytkownika.",
@ -176,6 +174,7 @@
"column.aliases.subheading_aliases": "Istniejące aliasy",
"column.app_create": "Utwórz aplikację",
"column.backups": "Kopie zapasowe",
"column.birthdays": "Urodziny",
"column.blocks": "Zablokowani użytkownicy",
"column.bookmarks": "Zakładki",
"column.chats": "Rozmowy",
@ -234,11 +233,11 @@
"column.scheduled_statuses": "Zaplanowane wpisy",
"column.search": "Szukaj",
"column.security": "Bezpieczeństwo",
"column.settings_store": "Settings store",
"column.soapbox_config": "Konfiguracja Soapbox",
"column_back_button.label": "Wróć",
"column_forbidden.body": "Nie masz uprawnień, aby odwiedzić tę stronę.",
"column_forbidden.title": "Niedozwolone",
"column_header.hide_settings": "Ukryj ustawienia",
"column_header.show_settings": "Pokaż ustawienia",
"community.column_settings.media_only": "Tylko zawartość multimedialna",
"community.column_settings.title": "Ustawienia lokalnej osi czasu",
@ -272,40 +271,54 @@
"compose_form.spoiler_placeholder": "Wprowadź swoje ostrzeżenie o zawartości",
"confirmation_modal.cancel": "Anuluj",
"confirmations.admin.deactivate_user.confirm": "Dezaktywuj @{name}",
"confirmations.admin.deactivate_user.heading": "Dezaktywuj @{acct}",
"confirmations.admin.deactivate_user.message": "Zamierzasz zdezaktywować @{acct}. Dezaktywacja konta może zostać cofnięta.",
"confirmations.admin.delete_local_user.checkbox": "Wiem, że właśnie usuwam lokalnego użytkownika.",
"confirmations.admin.delete_status.confirm": "Usuń wpis",
"confirmations.admin.delete_status.heading": "Usuń wpis",
"confirmations.admin.delete_status.message": "Zamierzasz usunąć wpis użytkownika @{acct}. To działanie nie może zostać cofnięte.",
"confirmations.admin.delete_user.confirm": "Usuń @{name}",
"confirmations.admin.delete_user.heading": "Usuń @{acct}",
"confirmations.admin.delete_user.message": "Zamierzasz usunąć @{acct}. TO DZIAŁANIE NIE MOŻE ZOSTAĆ COFNIĘTE.",
"confirmations.admin.mark_status_not_sensitive.confirm": "Oznacz wpis jako niewrażliwy",
"confirmations.admin.mark_status_not_sensitive.heading": "Oznacz wpis jako niewrażliwy.",
"confirmations.admin.mark_status_not_sensitive.message": "Zamierzasz oznaczyć wpis {acct} jako niewrażliwy.",
"confirmations.admin.mark_status_sensitive.confirm": "Oznacz wpis jako wrażliwy",
"confirmations.admin.mark_status_sensitive.heading": "Oznacz wpis jako wrażliwy",
"confirmations.admin.mark_status_sensitive.message": "Zamierzasz oznaczyć wpis {acct} jako wrażliwy.",
"confirmations.admin.reject_user.confirm": "Odrzuć @{name}",
"confirmations.admin.reject_user.heading": "Odrzuć @{acct}",
"confirmations.admin.reject_user.message": "Zamierzasz odrzucić prośbę o rejestrację @{acct}. To działanie nie może zostać cofnięte.",
"confirmations.block.block_and_report": "Zablokuj i zgłoś",
"confirmations.block.confirm": "Zablokuj",
"confirmations.block.heading": "Zablokuj @{name}",
"confirmations.block.message": "Czy na pewno chcesz zablokować {name}?",
"confirmations.delete.confirm": "Usuń",
"confirmations.delete.heading": "Usuń wpis",
"confirmations.delete.message": "Czy na pewno chcesz usunąć ten wpis?",
"confirmations.delete_list.confirm": "Usuń",
"confirmations.delete_list.heading": "Usuń listę",
"confirmations.delete_list.message": "Czy na pewno chcesz bezpowrotnie usunąć tą listę?",
"confirmations.domain_block.confirm": "Ukryj wszysyko z domeny",
"confirmations.domain_block.heading": "Zablokuj {domain}",
"confirmations.domain_block.message": "Czy na pewno chcesz zablokować całą domenę {domain}? Zwykle lepszym rozwiązaniem jest blokada lub wyciszenie kilku użytkowników.",
"confirmations.mute.confirm": "Wycisz",
"confirmations.mute.heading": "Wycisz @{name}",
"confirmations.mute.message": "Czy na pewno chcesz wyciszyć {name}?",
"confirmations.redraft.confirm": "Usuń i przeredaguj",
"confirmations.redraft.heading": "Usuń i przeredaguj",
"confirmations.redraft.message": "Czy na pewno chcesz usunąć i przeredagować ten wpis? Polubienia i podbicia zostaną utracone, a odpowiedzi do oryginalnego wpisu zostaną osierocone.",
"confirmations.register.needs_approval": "Twoje konto musi zostać ręcznie zatwierdzone przez administratora. Zachowaj cierpliwość, a my sprawdzimy szczegóły Twojej rejestracji.",
"confirmations.register.needs_approval.header": "Wymagane zatwierdzenie",
"confirmations.register.needs_confirmation": "Sprawdź swoją skrzynkę na {email}, aby znaleźć instrukcje potwierdzania. Musisz zweryfikować swój adres e-mail, aby kontynuować.",
"confirmations.register.needs_confirmation.header": "Wymagane potwierdzenie",
"confirmations.reply.confirm": "Odpowiedz",
"confirmations.reply.message": "W ten sposób utracisz wpis który obecnie tworzysz. Czy na pewno chcesz to zrobić?",
"confirmations.scheduled_status_delete.confirm": "Anuluj",
"confirmations.scheduled_status_delete.heading": "Anuluj zaplanowany wpis",
"confirmations.scheduled_status_delete.message": "Czy na pewno chcesz anulować ten zaplanowany wpis?",
"confirmations.unfollow.confirm": "Przestań śledzić",
"confirmations.unfollow.heading": "Przestań śledzić {name}",
"confirmations.unfollow.message": "Czy na pewno zamierzasz przestać śledzić {name}?",
"crypto_donate.explanation_box.message": "{siteTitle} przyjmuje darowizny w kryptowalutach. Możesz wysłać darowiznę na jeden z poniższych adresów. Dziękujemy za Wasze wsparcie!",
"crypto_donate.explanation_box.title": "Przekaż darowiznę w kryptowalutach",
@ -313,8 +326,22 @@
"crypto_donate_panel.heading": "Przekaż kryptowalutę",
"crypto_donate_panel.intro.message": "{siteTitle} przyjmuje darowizny w kryptowalutach, aby utrzymać naszą usługę. Dziękujemy za Wasze wsparcie!",
"datepicker.hint": "Zaplanowano publikację na…",
"datepicker.next_month": "Następny miesiąc",
"datepicker.next_year": "Następny rok",
"datepicker.previous_month": "Poprzedni miesiąc",
"datepicker.previous_year": "Poprzedni rok",
"developers.challenge.answer_label": "Odpowiedź",
"developers.challenge.answer_placeholder": "Twoja odpowiedź",
"developers.challenge.fail": "Nieprawidłowa odpowiedź",
"developers.challenge.message": "Jaki jest wynik wywołania {function}?",
"developers.challenge.submit": "Zostań programistą",
"developers.challenge.success": "Jesteś teraz programistą",
"developers.leave": "Nie jesteś już programistą",
"developers.navigation.app_create_label": "Utwórz aplikację",
"developers.navigation.intentional_error_label": "Wywołaj błąd",
"developers.navigation.leave_developers_label": "Opuść programistów",
"developers.navigation.settings_store_label": "Settings store",
"developers.settings_store.hint": "Możesz tu bezpośrednio edytować swoje ustawienia. UWAŻAJ! Edytowanie tej sekcji może uszkodzić Twoje konto, co może zostać naprawione tylko przez API.",
"direct.search_placeholder": "Wyślij wiadomość do…",
"directory.federated": "Z całego znanego Fediwersum",
"directory.local": "Tylko z {domain}",
@ -334,6 +361,8 @@
"edit_profile.fields.avatar_label": "Awatar",
"edit_profile.fields.bio_label": "Opis",
"edit_profile.fields.bio_placeholder": "Powiedz nam coś o sobie.",
"edit_profile.fields.birthday_label": "Urodziny",
"edit_profile.fields.birthday_placeholder": "Twoje urodziny",
"edit_profile.fields.bot_label": "To jest konto bota",
"edit_profile.fields.discoverable_label": "Pozwól na odkrywanie konta",
"edit_profile.fields.display_name_label": "Nazwa wyświetlana",
@ -344,16 +373,18 @@
"edit_profile.fields.meta_fields.content_placeholder": "Treść",
"edit_profile.fields.meta_fields.label_placeholder": "Podpis",
"edit_profile.fields.meta_fields_label": "Metadane profilu",
"edit_profile.fields.show_birthday_label": "Pokazuj moje urodziny",
"edit_profile.fields.stranger_notifications_label": "Blokuj powiadomienia od nieznajomych",
"edit_profile.fields.verified_display_name": "Zweryfikowani użytkownicy nie mogą zmieniać nazwy wyświetlanej",
"edit_profile.hints.accepts_email_list": "Otrzymuj wiadomości i nowości marketingowe.",
"edit_profile.hints.avatar": "PNG, GIF lub JPG. Maksymalnie 2 MB. Zostanie zmniejszony do 400x400px",
"edit_profile.hints.avatar": "PNG, GIF lub JPG. Zostanie zmniejszony do {size}",
"edit_profile.hints.bot": "To konto podejmuje głównie zautomatyzowane działania i może nie być nadzorowane",
"edit_profile.hints.discoverable": "Wyświetlaj konto w katalogu profilów i pozwalaj na indeksowanie przez zewnętrzne usługi",
"edit_profile.hints.header": "PNG, GIF lub JPG. Maksymalnie 2 MB. Zostanie zmniejszony do 1500x500px",
"edit_profile.hints.header": "PNG, GIF lub JPG. Zostanie zmniejszony do {size}",
"edit_profile.hints.hide_network": "To, kogo obserwujesz i kto Cię obserwuje nie będzie wyświetlane na Twoim profilu",
"edit_profile.hints.locked": "Wymaga ręcznego zatwierdzania obserwacji",
"edit_profile.hints.meta_fields": "Możesz mieć maksymalnie {count, plural, one {# element} few {# elemeny} many {# elementów} other {# elementy}} wyświetlane w formie tabeli na swoim profilu",
"edit_profile.hints.show_birthday": "Twoja data urodzenia będzie widoczna na Twoim profilu.",
"edit_profile.hints.stranger_notifications": "Wyświetlaj tylko powiadomienia od osób, które obserwujesz",
"edit_profile.meta_fields.add": "Dodaj element",
"edit_profile.save": "Zapisz",
@ -390,10 +421,10 @@
"empty_column.filters": "Nie wyciszyłeś(-aś) jeszcze żadnego słowa.",
"empty_column.follow_recommendations": "Wygląda na to, że nie można wygenerować dla Ciebie sugestii kont do obserwacji. Możesz spróbować użyć wyszukiwania aby odnaleźć ciekawe profile, lub przejrzeć trendujące hashtagi.",
"empty_column.follow_requests": "Nie masz żadnych próśb o możliwość śledzenia. Kiedy ktoś utworzy ją, pojawi się tutaj.",
"empty_column.group": "There is nothing in this group yet. When members of this group make new posts, they will appear here.",
"empty_column.group": "Nie ma żadnych wpisów w tej grupie. Gdy członkowie tej grupy utworzą wpisy, pojawią się one tutaj.",
"empty_column.hashtag": "Nie ma wpisów oznaczonych tym hashtagiem. Możesz napisać pierwszy(-a)!",
"empty_column.home": "Nie śledzisz nikogo. Odwiedź globalną oś czasu lub użyj wyszukiwarki, aby znaleźć interesujące Cię profile.",
"empty_column.home.local_tab": "zakładka {site_title}",
"empty_column.home": "Nie śledzisz nikogo. Odwiedź {public}, aby znaleźć innych użytkowników.",
"empty_column.home.local_tab": "zakładkę {site_title}",
"empty_column.list": "Nie ma nic na tej liście. Kiedy członkowie listy dodadzą nowe wpisy, pojawia się one tutaj.",
"empty_column.lists": "Nie masz żadnych list. Kiedy utworzysz jedną, pojawi się tutaj.",
"empty_column.mutes": "Nie wyciszyłeś(-aś) jeszcze żadnego użytkownika.",
@ -449,7 +480,6 @@
"forms.hide_password": "Ukryj hasło",
"forms.show_password": "Pokaż hasło",
"getting_started.open_source_notice": "{code_name} jest oprogramowaniem o otwartym źródle. Możesz pomóc w rozwoju lub zgłaszać błędy na GitLabie tutaj: {code_link} (v{code_version}).",
"group.detail.archived_group": "Zarchiwizowana grupa",
"group.members.empty": "Ta grupa nie ma żadnych członków.",
"group.removed_accounts.empty": "Ta grupa nie ma żadnych usuniętych kont.",
"groups.card.join": "Dołącz",
@ -458,21 +488,13 @@
"groups.card.roles.member": "Jesteś członkiem",
"groups.card.view": "Zobacz",
"groups.create": "Utwórz grupę",
"groups.detail.role_admin": "Jesteś administratorem",
"groups.edit": "Edytuj",
"groups.form.coverImage": "Wyślij obraz baneru (nieobowiązkowe)",
"groups.form.coverImageChange": "Wybrano obraz baneru",
"groups.form.create": "Utwórz grupę",
"groups.form.description": "Opis",
"groups.form.title": "Tytuł",
"groups.form.update": "Aktualizuj grupę",
"groups.join": "Dołącz do grupy",
"groups.leave": "Opuść grupę",
"groups.removed_accounts": "Usunięte konta",
"groups.sidebar-panel.item.no_recent_activity": "Brak ostatniej aktywności",
"groups.sidebar-panel.item.view": "nowe wpisy",
"groups.sidebar-panel.show_all": "Pokaż wszystkie",
"groups.sidebar-panel.title": "Grupy do których należysz",
"groups.tab_admin": "Zarządzaj",
"groups.tab_featured": "Wyróżnione",
"groups.tab_member": "Członek",
@ -487,14 +509,10 @@
"home.column_settings.show_reblogs": "Pokazuj podbicia",
"home.column_settings.show_replies": "Pokazuj odpowiedzi",
"home.column_settings.title": "Ustawienia strony głównej",
"home_column.lists": "Listy",
"home_column_header.all": "Wszystkie",
"home_column_header.fediverse": "Fediwersum",
"home_column_header.home": "Strona główna",
"icon_button.icons": "Ikony",
"icon_button.label": "Wybierz ikonę",
"icon_button.not_found": "Brak ikon!! (╯°□°)╯︵ ┻━┻",
"import_data.actions.import": "Import",
"import_data.actions.import": "Importuj",
"import_data.actions.import_blocks": "Importuj blokady",
"import_data.actions.import_follows": "Importuj obserwacje",
"import_data.actions.import_mutes": "Importuj wyciszenia",
@ -510,19 +528,6 @@
"intervals.full.days": "{number, plural, one {# dzień} few {# dni} many {# dni} other {# dni}}",
"intervals.full.hours": "{number, plural, one {# godzina} few {# godziny} many {# godzin} other {# godzin}}",
"intervals.full.minutes": "{number, plural, one {# minuta} few {# minuty} many {# minut} other {# minut}}",
"introduction.federation.action": "Next",
"introduction.federation.home.headline": "Home",
"introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
"introduction.interactions.action": "Finish tutorial!",
"introduction.interactions.favourite.headline": "Favorite",
"introduction.interactions.favourite.text": "You can save a post for later, and let the author know that you liked it, by favoriting it.",
"introduction.interactions.reblog.headline": "Repost",
"introduction.interactions.reblog.text": "You can share other people's posts with your followers by reposting them.",
"introduction.interactions.reply.headline": "Reply",
"introduction.interactions.reply.text": "You can reply to other people's and your own posts, which will chain them together in a conversation.",
"introduction.welcome.action": "Let's go!",
"introduction.welcome.headline": "First steps",
"introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
"keyboard_shortcuts.back": "aby cofnąć się",
"keyboard_shortcuts.blocked": "aby przejść do listy zablokowanych użytkowników",
"keyboard_shortcuts.boost": "aby podbić wpis",
@ -556,8 +561,6 @@
"lightbox.previous": "Poprzednie",
"lightbox.view_context": "Pokaż kontekst",
"list.click_to_add": "Naciśnij tutaj, aby dodać ludzi",
"list.label": "Wybierz listę…",
"list.select": "Wybierz listę",
"list_adder.header_title": "Dodaj lub usuń z list",
"lists.account.add": "Dodaj do listy",
"lists.account.remove": "Usunąć z listy",
@ -583,12 +586,15 @@
"media_gallery.toggle_visible": "Przełącz widoczność",
"media_panel.empty_message": "Nie znaleziono mediów.",
"media_panel.title": "Media",
"mfa.confirm.success_message": "Potwierdzono MFA",
"mfa.disable.success_message": "Wyłączono MFA",
"mfa.mfa_disable_enter_password": "Wprowadź obecne hasło, aby wyłączyć uwierzytelnianie dwuetapowe:",
"mfa.mfa_setup_enter_password": "Wprowadź obecne hasło, aby potwierdzić swoją tożsamość:",
"mfa.mfa_setup.code_hint": "Wprowadź kod z aplikacji do uwierzytelniania dwuskładnikowego.",
"mfa.mfa_setup.code_placeholder": "Kod",
"mfa.mfa_setup.password_hint": "Wprowadź obecne hasło, aby potwierdzić swoją tożsamość.",
"mfa.mfa_setup.password_placeholder": "Hasło",
"mfa.mfa_setup_scan_description": "Korzystając z aplikacji do uwierzytelniania dwuetapowego, zeskanuj ten kod QR lub wprowadź klucz tekstowy:",
"mfa.mfa_setup_scan_key": "Klucz:",
"mfa.mfa_setup_scan_title": "Skanuj",
"mfa.mfa_setup_verify_description": "Aby aktywować uwierzytelnianie dwuetapowe, wprowadź kod ze swojej aplikacji do uwierzytelniania dwuetapowego:",
"mfa.mfa_setup_verify_title": "Weryfikuj",
"mfa.otp_enabled_description": "Masz włączone uwierzytelnianie dwuetapowe przez OTP.",
"mfa.otp_enabled_title": "Włączono OTP",
@ -615,9 +621,9 @@
"navigation_bar.account_aliases": "Aliasy kont",
"navigation_bar.admin_settings": "Ustawienia administracyjne",
"navigation_bar.blocks": "Zablokowani użytkownicy",
"navigation_bar.bookmarks": "Zakładki",
"navigation_bar.compose": "Utwórz nowy wpis",
"navigation_bar.compose_direct": "Wiadomość bezpośrednia",
"navigation_bar.compose_quote": "Cytuj wpis",
"navigation_bar.compose_reply": "Odpowiedz na wpis",
"navigation_bar.domain_blocks": "Ukryte domeny",
"navigation_bar.export_data": "Eksportuj dane",
@ -629,15 +635,16 @@
"navigation_bar.info": "Szczegółowe informacje",
"navigation_bar.invites": "Zaproszenia",
"navigation_bar.keyboard_shortcuts": "Skróty klawiszowe",
"navigation_bar.lists": "Lists",
"navigation_bar.logout": "Wyloguj",
"navigation_bar.messages": "Messages",
"navigation_bar.mutes": "Wyciszeni użytkownicy",
"navigation_bar.pins": "Przypięte wpisy",
"navigation_bar.preferences": "Preferencje",
"navigation_bar.profile_directory": "Katalog profilów",
"navigation_bar.security": "Bezpieczeństwo",
"navigation_bar.soapbox_config": "Konfiguracja Soapbox",
"notification.birthday": "{name} ma dziś urodziny",
"notification.birthday.more": "{count} {count, plural, one {znajomy} other {więcej znajomych}}",
"notification.birthday_plural": "{name} i {more} mają dziś urodziny",
"notification.chat_mention": "{name} wysłał(a) Ci wiadomośść",
"notification.favourite": "{name} dodał(a) Twój wpis do ulubionych",
"notification.follow": "{name} zaczął(-ęła) Cię śledzić",
@ -649,7 +656,10 @@
"notification.reblog": "{name} podbił(a) Twój wpis",
"notifications.clear": "Wyczyść powiadomienia",
"notifications.clear_confirmation": "Czy na pewno chcesz bezpowrotnie usunąć wszystkie powiadomienia?",
"notifications.clear_heading": "Wyczyść powiadomienia",
"notifications.column_settings.alert": "Powiadomienia na pulpicie",
"notifications.column_settings.birthdays.category": "Urodziny",
"notifications.column_settings.birthdays.show": "Pokazuj przypomnienia o urodzinach",
"notifications.column_settings.emoji_react": "Reakcje emoji:",
"notifications.column_settings.favourite": "Dodanie do ulubionych:",
"notifications.column_settings.filter_bar.advanced": "Wyświetl wszystkie kategorie",
@ -697,7 +707,6 @@
"preferences.fields.content_type_label": "Format wpisów",
"preferences.fields.delete_modal_label": "Pokazuj prośbę o potwierdzenie przed usunięciem wpisu",
"preferences.fields.demetricator_label": "Użyj Demetricatora",
"preferences.fields.developer_label": "Narzędzia dla programistów",
"preferences.fields.display_media.default": "Ukrywaj media oznaczone jako wrażliwe",
"preferences.fields.display_media.hide_all": "Ukrywaj wszystkie media",
"preferences.fields.display_media.show_all": "Pokazuj wszystkie media",
@ -750,7 +759,6 @@
"registration.fields.password_placeholder": "Hasło",
"registration.fields.username_hint": "Możesz używać tylko liter, cyfr i podkreślników.",
"registration.fields.username_placeholder": "Nazwa użytkownika",
"registration.lead": "Z kontem na {instance}, możesz obserwować ludzi z dowolnego serwera w całym Fediwersum.",
"registration.newsletter": "Zasubskrybuj newsletter.",
"registration.password_mismatch": "Hasła nie pasują do siebie.",
"registration.reason": "Dlaczego chcesz dołączyć?",
@ -764,12 +772,12 @@
"relative_time.minutes": "{number} min.",
"relative_time.seconds": "{number} s.",
"remote_instance.edit_federation": "Edytuj federację",
"remote_instance.federation_panel.heading": "Federation Restrictions",
"remote_instance.federation_panel.heading": "Ograniczenia federacji",
"remote_instance.federation_panel.no_restrictions_message": "{siteTitle} nie nakłada ograniczeń na {host}.",
"remote_instance.federation_panel.restricted_message": "{siteTitle} blokuje wszystkie aktywności z {host}.",
"remote_instance.federation_panel.some_restrictions_message": "{siteTitle} nakłada pewne ograniczenia na {host}.",
"remote_instance.pin_host": "Przypnij {instance}",
"remote_instance.unpin_host": "Odepnij {instance}",
"remote_instance.pin_host": "Przypnij {host}",
"remote_instance.unpin_host": "Odepnij {host}",
"remote_interaction.account_placeholder": "Wprowadź nazwę@domenę użytkownika, z którego chcesz wykonać działanie",
"remote_interaction.divider": "lub",
"remote_interaction.favourite": "Przejdź do polubienia",
@ -808,7 +816,6 @@
"search_results.accounts": "Ludzie",
"search_results.hashtags": "Hashtagi",
"search_results.statuses": "Wpisy",
"search_results.top": "Góra",
"security.codes.fail": "Nie udało się uzyskać zapasowych kodów",
"security.confirm.fail": "Nieprawidłowy kod lub hasło. Spróbuj ponownie.",
"security.delete_account.fail": "Nie udało się usunąć konta.",
@ -839,6 +846,7 @@
"security.update_password.success": "Pomyślnie zmieniono hasło.",
"signup_panel.subtitle": "Zarejestruj się, aby przyłączyć się do dyskusji.",
"signup_panel.title": "Nowi na {site_title}?",
"snackbar.view": "Wyświetl",
"soapbox_config.authenticated_profile_hint": "Użytkownicy muszą być zalogowani, aby zobaczyć odpowiedzi i media na profilach użytkowników.",
"soapbox_config.authenticated_profile_label": "Profile wymagają uwierzytelniania",
"soapbox_config.copyright_footer.meta_fields.label_placeholder": "Stopka praw autorskich",
@ -898,6 +906,7 @@
"status.open": "Rozwiń ten wpis",
"status.pin": "Przypnij do profilu",
"status.pinned": "Przypięty wpis",
"status.quote": "Cytuj wpis",
"status.reactions.cry": "Przykro mi",
"status.reactions.empty": "Nikt nie zareagował na ten wpis. Gdy ktoś to zrobi, pojawi się tutaj.",
"status.reactions.heart": "Super",
@ -923,7 +932,6 @@
"status.show_less_all": "Zwiń wszystkie",
"status.show_more": "Rozwiń",
"status.show_more_all": "Rozwiń wszystkie",
"status.show_thread": "Pokaż wątek",
"status.title": "Wpis",
"status.title_direct": "Wiadomość bezpośrednia",
"status.unbookmark": "Usuń z zakładek",
@ -931,6 +939,7 @@
"status.unmute_conversation": "Cofnij wyciszenie konwersacji",
"status.unpin": "Odepnij z profilu",
"status_list.queue_label": "Naciśnij aby zobaczyć {count} {count, plural, one {nowy wpis} few {nowe wpisy} many {nowych wpisów} other {nowe wpisy}}",
"statuses.quote_tombstone": "Wpis jest niedostępny.",
"statuses.tombstone": "Jeden lub więcej z wpisów jest już niedostępny.",
"suggestions.dismiss": "Odrzuć sugestię",
"tabs_bar.all": "Wszystkie",

@ -39,6 +39,49 @@ describe('statuses reducer', () => {
expect(state.getIn(['AFmFMSpITT9xcOJKcK', 'quote'])).toEqual('AFmFLcd6XYVdjWCrOS');
});
it('normalizes Mitra attachments', () => {
const status = require('soapbox/__fixtures__/mitra-status-with-attachments.json');
const state = reducer(undefined, { type: STATUS_IMPORT, status: normalizeStatus(status) });
const expected = fromJS([{
id: '017eeb0e-e5df-30a4-77a7-a929145cb836',
type: 'image',
url: 'https://mitra.social/media/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png',
preview_url: 'https://mitra.social/media/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png',
remote_url: 'https://mitra.social/media/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png',
}, {
id: '017eeb0e-e5e4-2a48-2889-afdebf368a54',
type: 'unknown',
url: 'https://mitra.social/media/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac',
preview_url: 'https://mitra.social/media/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac',
remote_url: 'https://mitra.social/media/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac',
}, {
id: '017eeb0e-e5e5-79fd-6054-8b6869b1db49',
type: 'unknown',
url: 'https://mitra.social/media/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.oga',
preview_url: 'https://mitra.social/media/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.oga',
remote_url: 'https://mitra.social/media/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.oga',
}, {
id: '017eeb0e-e5e6-c416-a444-21e560c47839',
type: 'unknown',
url: 'https://mitra.social/media/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0',
preview_url: 'https://mitra.social/media/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0',
remote_url: 'https://mitra.social/media/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0',
}]);
expect(state.getIn(['017eeb0e-e5e7-98fe-6b2b-ad02349251fb', 'media_attachments'])).toEqual(expected);
});
it('leaves Pleroma attachments alone', () => {
const status = require('soapbox/__fixtures__/pleroma-status-with-attachments.json');
const action = { type: STATUS_IMPORT, status: normalizeStatus(status) };
const state = reducer(undefined, action);
const expected = fromJS(status.media_attachments);
expect(state.getIn(['AGNkA21auFR5lnEAHw', 'media_attachments'])).toEqual(expected);
});
});
describe('STATUS_CREATE_REQUEST', () => {

@ -50,7 +50,7 @@ const initialState = ImmutableMap({
// Build Mastodon configuration from Pleroma instance
const pleromaToMastodonConfig = instance => {
return {
return ImmutableMap({
statuses: ImmutableMap({
max_characters: instance.get('max_toot_chars'),
}),
@ -60,7 +60,7 @@ const pleromaToMastodonConfig = instance => {
min_expiration: instance.getIn(['poll_limits', 'min_expiration']),
max_expiration: instance.getIn(['poll_limits', 'max_expiration']),
}),
};
});
};
// Use new value only if old value is undefined

@ -1,4 +1,4 @@
import { Map as ImmutableMap, fromJS } from 'immutable';
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
import { simulateEmojiReact, simulateUnEmojiReact } from 'soapbox/utils/emoji_reacts';
@ -26,6 +26,30 @@ import {
} from '../actions/statuses';
import { TIMELINE_DELETE } from '../actions/timelines';
// Ensure attachments have required fields
// https://docs.joinmastodon.org/entities/attachment/
const normalizeAttachment = attachment => {
const url = [
attachment.get('url'),
attachment.get('preview_url'),
attachment.get('remote_url'),
].find(url => url) || '';
const base = ImmutableMap({
url,
preview_url: url,
remote_url: url,
});
return attachment.mergeWith((o, n) => o || n, base);
};
const normalizeAttachments = status => {
return status.update('media_attachments', ImmutableList(), attachments => {
return attachments.map(normalizeAttachment);
});
};
// Fix order of mentions
const fixMentions = status => {
const mentions = status.get('mentions');
@ -60,14 +84,15 @@ const fixQuote = (state, status) => {
}
};
const fixStatus = (state, status) => {
const normalizeStatus = (state, status) => {
return status.withMutations(status => {
fixMentions(status);
fixQuote(state, status);
normalizeAttachments(status);
});
};
const importStatus = (state, status) => state.set(status.id, fixStatus(state, fromJS(status)));
const importStatus = (state, status) => state.set(status.id, normalizeStatus(state, fromJS(status)));
const importStatuses = (state, statuses) =>
state.withMutations(mutable => statuses.forEach(status => importStatus(mutable, status)));

@ -0,0 +1,26 @@
export const ethereum = () => window.ethereum;
export const hasEthereum = () => Boolean(ethereum());
// Requests an Ethereum wallet from the browser
// Returns a Promise containing the Ethereum wallet address (string).
export const getWallet = () => {
return ethereum().request({ method: 'eth_requestAccounts' })
.then(wallets => wallets[0]);
};
// Asks the browser to sign a message with Ethereum.
// Returns a Promise containing the signature (string).
export const signMessage = (wallet, message) => {
return ethereum().request({ method: 'personal_sign', params: [message, wallet] });
};
// Combines the above functions.
// Returns an object with the `wallet` and `signature`
export const getWalletAndSign = message => {
return getWallet().then(wallet => {
return signMessage(wallet, message).then(signature => {
return { wallet, signature };
});
});
};

@ -9,12 +9,13 @@ const any = arr => arr.some(Boolean);
// For uglification
export const MASTODON = 'Mastodon';
export const PLEROMA = 'Pleroma';
export const MITRA = 'Mitra';
export const getFeatures = createSelector([instance => instance], instance => {
const v = parseVersion(instance.get('version'));
const features = instance.getIn(['pleroma', 'metadata', 'features'], ImmutableList());
const federation = instance.getIn(['pleroma', 'metadata', 'federation'], ImmutableMap());
export const getFeatures = createSelector([
instance => parseVersion(instance.get('version')),
instance => instance.getIn(['pleroma', 'metadata', 'features'], ImmutableList()),
instance => instance.getIn(['pleroma', 'metadata', 'federation'], ImmutableMap()),
], (v, features, federation) => {
return {
bookmarks: any([
v.software === MASTODON && gte(v.compatVersion, '3.1.0'),
@ -81,17 +82,32 @@ export const getFeatures = createSelector([
remoteInteractionsAPI: v.software === PLEROMA && gte(v.version, '2.4.50'),
explicitAddressing: v.software === PLEROMA && gte(v.version, '1.0.0'),
accountEndorsements: v.software === PLEROMA && gte(v.version, '2.4.50'),
quotePosts: v.software === PLEROMA && gte(v.version, '2.4.50'),
quotePosts: any([
v.software === PLEROMA && gte(v.version, '2.4.50'),
instance.get('feature_quote') === true,
]),
birthdays: v.software === PLEROMA && gte(v.version, '2.4.50'),
ethereumLogin: v.software === MITRA,
};
});
export const parseVersion = version => {
const regex = /^([\w\.]*)(?: \(compatible; ([\w]*) (.*)\))?$/;
const match = regex.exec(version);
if (match) {
return {
software: match[2] || MASTODON,
version: match[3] || match[1],
compatVersion: match[1],
};
} else {
// If we can't parse the version, this is a new and exotic backend.
// Fall back to minimal featureset.
return {
software: null,
version: '0.0.0',
compatVersion: '0.0.0',
};
}
};

@ -1,12 +1,17 @@
import { parseVersion } from './features';
import { createSelector } from 'reselect';
import { parseVersion, PLEROMA, MITRA } from './features';
// For solving bugs between API implementations
export const getQuirks = instance => {
const v = parseVersion(instance.get('version'));
export const getQuirks = createSelector([
instance => parseVersion(instance.get('version')),
], (v) => {
return {
invertedPagination: v.software === 'Pleroma',
};
invertedPagination: v.software === PLEROMA,
noApps: v.software === MITRA,
noOAuthForm: v.software === MITRA,
};
});
export const getNextLinkName = getState =>
getQuirks(getState().get('instance')).invertedPagination ? 'prev' : 'next';

@ -344,4 +344,8 @@
height: 22px;
text-align: center;
}
.fa-hack {
margin: 0 auto;
}
}

Loading…
Cancel
Save