From a4b74c70dbdac7f9f19f417ef9f216b1f886789e Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 21 Feb 2021 22:51:08 +0000
Subject: [PATCH 0001/1416] Note
---
httpsig.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/httpsig.py b/httpsig.py
index 2b0c9eb1b..f61d0c7d2 100644
--- a/httpsig.py
+++ b/httpsig.py
@@ -8,6 +8,9 @@ __email__ = "bob@freedombone.net"
__status__ = "Production"
# see https://tools.ietf.org/html/draft-cavage-http-signatures-06
+#
+# This might change in future
+# see https://tools.ietf.org/html/draft-ietf-httpbis-message-signatures-01
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import load_pem_private_key
From 4edc3af8f760c6efbbdfb72e1592433879c1a1ff Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 22 Feb 2021 10:09:56 +0000
Subject: [PATCH 0002/1416] Invert logic
---
daemon.py | 2 +-
tests.py | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/daemon.py b/daemon.py
index 8f1dfd3aa..2891c2649 100644
--- a/daemon.py
+++ b/daemon.py
@@ -13805,7 +13805,7 @@ class PubServer(BaseHTTPRequestHandler):
self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 21)
- if not self.headers.get('signature'):
+ if self.headers.get('signature'):
if 'keyId=' not in self.headers['signature']:
if self.server.debug:
print('DEBUG: POST to inbox has no keyId in ' +
diff --git a/tests.py b/tests.py
index 5a4bd233e..964971ba0 100644
--- a/tests.py
+++ b/tests.py
@@ -3116,6 +3116,9 @@ def testValidHashTag():
def runAllTests():
print('Running tests...')
+ testHttpsig()
+ return
+
testFunctions()
testValidHashTag()
testPrepareHtmlPostNickname()
From 4e2487aa27f9f12e70829f989d1d1ba89c2aa675 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 22 Feb 2021 11:13:27 +0000
Subject: [PATCH 0003/1416] Support for newer http signature specification
---
daemon.py | 19 +++++++++++++++++--
httpsig.py | 41 +++++++++++++++++++++++++++++++++++++----
2 files changed, 54 insertions(+), 6 deletions(-)
diff --git a/daemon.py b/daemon.py
index 2891c2649..d2029b346 100644
--- a/daemon.py
+++ b/daemon.py
@@ -300,6 +300,19 @@ def saveDomainQrcode(baseDir: str, httpPrefix: str,
class PubServer(BaseHTTPRequestHandler):
protocol_version = 'HTTP/1.1'
+ def _getheaderSignatureInput(self):
+ """There are different versions of http signatures with
+ different header styles
+ """
+ if self.headers.get('Signature-Input'):
+ # https://tools.ietf.org/html/
+ # draft-ietf-httpbis-message-signatures-01
+ return self.headers['Signature-Input']
+ elif self.headers.get('signature'):
+ # Ye olde Masto http sig
+ return self.headers['signature']
+ return None
+
def _pathIsImage(self, path: str) -> bool:
if path.endswith('.png') or \
path.endswith('.jpg') or \
@@ -13805,8 +13818,10 @@ class PubServer(BaseHTTPRequestHandler):
self._benchmarkPOSTtimings(POSTstartTime, POSTtimings, 21)
- if self.headers.get('signature'):
- if 'keyId=' not in self.headers['signature']:
+ headerSignature = self._getheaderSignatureInput()
+
+ if headerSignature:
+ if 'keyId=' not in headerSignature:
if self.server.debug:
print('DEBUG: POST to inbox has no keyId in ' +
'header signature parameter')
diff --git a/httpsig.py b/httpsig.py
index f61d0c7d2..e99766bad 100644
--- a/httpsig.py
+++ b/httpsig.py
@@ -184,21 +184,42 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
pubkey = load_pem_public_key(publicKeyPem.encode('utf-8'),
backend=default_backend())
# Build a dictionary of the signature values
- signatureHeader = headers['signature']
+ if headers.get('Signature-Input'):
+ signatureHeader = headers['Signature-Input']
+ fieldSep1 = ';'
+ fieldSep2 = ','
+ else:
+ signatureHeader = headers['signature']
+ fieldSep1 = ','
+ fieldSep2 = ' '
+
+ # split the signature input into separate fields
signatureDict = {
k: v[1:-1]
- for k, v in [i.split('=', 1) for i in signatureHeader.split(',')]
+ for k, v in [i.split('=', 1) for i in signatureHeader.split(fieldSep1)]
}
# Unpack the signed headers and set values based on current headers and
# body (if a digest was included)
signedHeaderList = []
- for signedHeader in signatureDict['headers'].split(' '):
+ for signedHeader in signatureDict['headers'].split(fieldSep2):
+ signedHeader = signedHeader.strip()
if debug:
print('DEBUG: verifyPostHeaders signedHeader=' + signedHeader)
if signedHeader == '(request-target)':
+ # original Mastodon http signature
appendStr = f'(request-target): {method.lower()} {path}'
signedHeaderList.append(appendStr)
+ elif '*request-target' in signedHeader:
+ # https://tools.ietf.org/html/
+ # draft-ietf-httpbis-message-signatures-01
+ appendStr = f'*request-target: {method.lower()} {path}'
+ # remove sig1=(
+ if '=(' in appendStr:
+ appendStr = appendStr.split('=(')[1]
+ if ')' in appendStr:
+ appendStr = appendStr.split(')')[0]
+ signedHeaderList.append(appendStr)
elif signedHeader == 'digest':
if messageBodyDigest:
bodyDigest = messageBodyDigest
@@ -253,7 +274,19 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
headerDigest = getSHA256(signedHeaderText.encode('ascii'))
# Get the signature, verify with public key, return result
- signature = base64.b64decode(signatureDict['signature'])
+ signature = None
+ if headers.get('Signature-Input') and headers.get('Signature'):
+ # https://tools.ietf.org/html/
+ # draft-ietf-httpbis-message-signatures-01
+ headersSig = headers['Signature']
+ # remove sig1=:
+ if '=:' in headersSig:
+ headersSig = headersSig.split('=:')[1]
+ headersSig = headersSig[:len(headersSig)-1]
+ signature = base64.b64decode(headersSig)
+ else:
+ # Original Mastodon signature
+ signature = base64.b64decode(signatureDict['signature'])
try:
pubkey.verify(
From 56e9130287d3f108778ca14f0fc605ca6019660e Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 22 Feb 2021 14:03:24 +0000
Subject: [PATCH 0004/1416] Unit test for verifying new http signature type
---
httpsig.py | 50 ++++++++++++--------
tests.py | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 160 insertions(+), 21 deletions(-)
diff --git a/httpsig.py b/httpsig.py
index e99766bad..d15d94654 100644
--- a/httpsig.py
+++ b/httpsig.py
@@ -163,7 +163,8 @@ def _verifyRecentSignature(signedDateStr: str) -> bool:
def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
path: str, GETmethod: bool,
messageBodyDigest: str,
- messageBodyJsonStr: str, debug: bool) -> bool:
+ messageBodyJsonStr: str, debug: bool,
+ noRecencyCheck=False) -> bool:
"""Returns true or false depending on if the key that we plugged in here
validates against the headers, method, and path.
publicKeyPem - the public key from an rsa key pair
@@ -186,23 +187,36 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
# Build a dictionary of the signature values
if headers.get('Signature-Input'):
signatureHeader = headers['Signature-Input']
- fieldSep1 = ';'
fieldSep2 = ','
+ # split the signature input into separate fields
+ signatureDict = {
+ k.strip(): v.strip()
+ for k, v in [i.split('=', 1) for i in signatureHeader.split(';')]
+ }
+ requestTargetKey = None
+ requestTargetStr = None
+ for k, v in signatureDict.items():
+ if v.startswith('('):
+ requestTargetKey = k
+ requestTargetStr = v[1:-1]
+ break
+ if not requestTargetKey:
+ return False
+ signatureDict[requestTargetKey] = requestTargetStr
else:
+ requestTargetKey = 'headers'
signatureHeader = headers['signature']
- fieldSep1 = ','
fieldSep2 = ' '
-
- # split the signature input into separate fields
- signatureDict = {
- k: v[1:-1]
- for k, v in [i.split('=', 1) for i in signatureHeader.split(fieldSep1)]
- }
+ # split the signature input into separate fields
+ signatureDict = {
+ k: v[1:-1]
+ for k, v in [i.split('=', 1) for i in signatureHeader.split(',')]
+ }
# Unpack the signed headers and set values based on current headers and
# body (if a digest was included)
signedHeaderList = []
- for signedHeader in signatureDict['headers'].split(fieldSep2):
+ for signedHeader in signatureDict[requestTargetKey].split(fieldSep2):
signedHeader = signedHeader.strip()
if debug:
print('DEBUG: verifyPostHeaders signedHeader=' + signedHeader)
@@ -214,11 +228,11 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
# https://tools.ietf.org/html/
# draft-ietf-httpbis-message-signatures-01
appendStr = f'*request-target: {method.lower()} {path}'
- # remove sig1=(
- if '=(' in appendStr:
- appendStr = appendStr.split('=(')[1]
- if ')' in appendStr:
- appendStr = appendStr.split(')')[0]
+ # remove ()
+ # if appendStr.startswith('('):
+ # appendStr = appendStr.split('(')[1]
+ # if ')' in appendStr:
+ # appendStr = appendStr.split(')')[0]
signedHeaderList.append(appendStr)
elif signedHeader == 'digest':
if messageBodyDigest:
@@ -245,7 +259,7 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
' not found in ' + str(headers))
else:
if headers.get(signedHeader):
- if signedHeader == 'date':
+ if signedHeader == 'date' and not noRecencyCheck:
if not _verifyRecentSignature(headers[signedHeader]):
if debug:
print('DEBUG: ' +
@@ -280,8 +294,8 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
# draft-ietf-httpbis-message-signatures-01
headersSig = headers['Signature']
# remove sig1=:
- if '=:' in headersSig:
- headersSig = headersSig.split('=:')[1]
+ if requestTargetKey + '=:' in headersSig:
+ headersSig = headersSig.split(requestTargetKey + '=:')[1]
headersSig = headersSig[:len(headersSig)-1]
signature = base64.b64decode(headersSig)
else:
diff --git a/tests.py b/tests.py
index 964971ba0..180dfc661 100644
--- a/tests.py
+++ b/tests.py
@@ -106,6 +106,133 @@ thrBob = None
thrEve = None
+def testHttpSigNew():
+ print('testHttpSigNew')
+ messageBodyJson = {"hello": "world"}
+ messageBodyJsonStr = json.dumps(messageBodyJson)
+ publicKeyPem = \
+ '-----BEGIN RSA PUBLIC KEY-----\n' + \
+ 'MIIBCgKCAQEAhAKYdtoeoy8zcAcR874L8' + \
+ 'cnZxKzAGwd7v36APp7Pv6Q2jdsPBRrw\n' + \
+ 'WEBnez6d0UDKDwGbc6nxfEXAy5mbhgajz' + \
+ 'rw3MOEt8uA5txSKobBpKDeBLOsdJKFq\n' + \
+ 'MGmXCQvEG7YemcxDTRPxAleIAgYYRjTSd' + \
+ '/QBwVW9OwNFhekro3RtlinV0a75jfZg\n' + \
+ 'kne/YiktSvLG34lw2zqXBDTC5NHROUqGT' + \
+ 'lML4PlNZS5Ri2U4aCNx2rUPRcKIlE0P\n' + \
+ 'uKxI4T+HIaFpv8+rdV6eUgOrB2xeI1dSF' + \
+ 'Fn/nnv5OoZJEIB+VmuKn3DCUcCZSFlQ\n' + \
+ 'PSXSfBDiUGhwOw76WuSSsf1D4b/vLoJ10wIDAQAB\n' + \
+ '-----END RSA PUBLIC KEY-----\n'
+
+ # privKey = \
+ # '-----BEGIN RSA PRIVATE KEY-----\n' + \
+ # 'MIIEqAIBAAKCAQEAhAKYdtoeoy8zcAcR8' + \
+ # '74L8cnZxKzAGwd7v36APp7Pv6Q2jdsP\n' + \
+ # 'BRrwWEBnez6d0UDKDwGbc6nxfEXAy5mbh' + \
+ # 'gajzrw3MOEt8uA5txSKobBpKDeBLOsd\n' + \
+ # 'JKFqMGmXCQvEG7YemcxDTRPxAleIAgYYR' + \
+ # 'jTSd/QBwVW9OwNFhekro3RtlinV0a75\n' + \
+ # 'jfZgkne/YiktSvLG34lw2zqXBDTC5NHRO' + \
+ # 'UqGTlML4PlNZS5Ri2U4aCNx2rUPRcKI\n' + \
+ # 'lE0PuKxI4T+HIaFpv8+rdV6eUgOrB2xeI' + \
+ # '1dSFFn/nnv5OoZJEIB+VmuKn3DCUcCZ\n' + \
+ # 'SFlQPSXSfBDiUGhwOw76WuSSsf1D4b/vL' + \
+ # 'oJ10wIDAQABAoIBAG/JZuSWdoVHbi56\n' + \
+ # 'vjgCgkjg3lkO1KrO3nrdm6nrgA9P9qaPj' + \
+ # 'xuKoWaKO1cBQlE1pSWp/cKncYgD5WxE\n' + \
+ # 'CpAnRUXG2pG4zdkzCYzAh1i+c34L6oZoH' + \
+ # 'sirK6oNcEnHveydfzJL5934egm6p8DW\n' + \
+ # '+m1RQ70yUt4uRc0YSor+q1LGJvGQHReF0' + \
+ # 'WmJBZHrhz5e63Pq7lE0gIwuBqL8SMaA\n' + \
+ # 'yRXtK+JGxZpImTq+NHvEWWCu09SCq0r83' + \
+ # '8ceQI55SvzmTkwqtC+8AT2zFviMZkKR\n' + \
+ # 'Qo6SPsrqItxZWRty2izawTF0Bf5S2VAx7' + \
+ # 'O+6t3wBsQ1sLptoSgX3QblELY5asI0J\n' + \
+ # 'YFz7LJECgYkAsqeUJmqXE3LP8tYoIjMIA' + \
+ # 'KiTm9o6psPlc8CrLI9CH0UbuaA2JCOM\n' + \
+ # 'cCNq8SyYbTqgnWlB9ZfcAm/cFpA8tYci9' + \
+ # 'm5vYK8HNxQr+8FS3Qo8N9RJ8d0U5Csw\n' + \
+ # 'DzMYfRghAfUGwmlWj5hp1pQzAuhwbOXFt' + \
+ # 'xKHVsMPhz1IBtF9Y8jvgqgYHLbmyiu1\n' + \
+ # 'mwJ5AL0pYF0G7x81prlARURwHo0Yf52kE' + \
+ # 'w1dxpx+JXER7hQRWQki5/NsUEtv+8RT\n' + \
+ # 'qn2m6qte5DXLyn83b1qRscSdnCCwKtKWU' + \
+ # 'ug5q2ZbwVOCJCtmRwmnP131lWRYfj67\n' + \
+ # 'B/xJ1ZA6X3GEf4sNReNAtaucPEelgR2ns' + \
+ # 'N0gKQKBiGoqHWbK1qYvBxX2X3kbPDkv\n' + \
+ # '9C+celgZd2PW7aGYLCHq7nPbmfDV0yHcW' + \
+ # 'jOhXZ8jRMjmANVR/eLQ2EfsRLdW69bn\n' + \
+ # 'f3ZD7JS1fwGnO3exGmHO3HZG+6AvberKY' + \
+ # 'VYNHahNFEw5TsAcQWDLRpkGybBcxqZo\n' + \
+ # '81YCqlqidwfeO5YtlO7etx1xLyqa2NsCe' + \
+ # 'G9A86UjG+aeNnXEIDk1PDK+EuiThIUa\n' + \
+ # '/2IxKzJKWl1BKr2d4xAfR0ZnEYuRrbeDQ' + \
+ # 'YgTImOlfW6/GuYIxKYgEKCFHFqJATAG\n' + \
+ # 'IxHrq1PDOiSwXd2GmVVYyEmhZnbcp8Cxa' + \
+ # 'EMQoevxAta0ssMK3w6UsDtvUvYvF22m\n' + \
+ # 'qQKBiD5GwESzsFPy3Ga0MvZpn3D6EJQLg' + \
+ # 'snrtUPZx+z2Ep2x0xc5orneB5fGyF1P\n' + \
+ # 'WtP+fG5Q6Dpdz3LRfm+KwBCWFKQjg7uTx' + \
+ # 'cjerhBWEYPmEMKYwTJF5PBG9/ddvHLQ\n' + \
+ # 'EQeNC8fHGg4UXU8mhHnSBt3EA10qQJfRD' + \
+ # 's15M38eG2cYwB1PZpDHScDnDA0=\n' + \
+ # '-----END RSA PRIVATE KEY-----'
+ sigInput = \
+ 'sig1=(date); alg=rsa-sha256; keyId="test-key-b"'
+ sig = \
+ 'sig1=:HtXycCl97RBVkZi66ADKnC9c5eSSlb57GnQ4KFqNZplOpNfxqk62' + \
+ 'JzZ484jXgLvoOTRaKfR4hwyxlcyb+BWkVasApQovBSdit9Ml/YmN2IvJDPncrlhPD' + \
+ 'VDv36Z9/DiSO+RNHD7iLXugdXo1+MGRimW1RmYdenl/ITeb7rjfLZ4b9VNnLFtVWw' + \
+ 'rjhAiwIqeLjodVImzVc5srrk19HMZNuUejK6I3/MyN3+3U8tIRW4LWzx6ZgGZUaEE' + \
+ 'P0aBlBkt7Fj0Tt5/P5HNW/Sa/m8smxbOHnwzAJDa10PyjzdIbywlnWIIWtZKPPsoV' + \
+ 'oKVopUWEU3TNhpWmaVhFrUL/O6SN3w==:'
+ # "hs2019", using RSASSA-PSS [RFC8017] and SHA-512 [RFC6234]
+ # sigInput = \
+ # 'sig1=(*request-target, *created, host, date, ' + \
+ # 'cache-control, x-empty-header, x-example); keyId="test-key-a"; ' + \
+ # 'alg=hs2019; created=1402170695; expires=1402170995'
+ # sig = \
+ # 'sig1=:K2qGT5srn2OGbOIDzQ6kYT+ruaycnDAAUpKv+ePFfD0RAxn/1BUe' + \
+ # 'Zx/Kdrq32DrfakQ6bPsvB9aqZqognNT6be4olHROIkeV879RrsrObury8L9SCEibe' + \
+ # 'oHyqU/yCjphSmEdd7WD+zrchK57quskKwRefy2iEC5S2uAH0EPyOZKWlvbKmKu5q4' + \
+ # 'CaB8X/I5/+HLZLGvDiezqi6/7p2Gngf5hwZ0lSdy39vyNMaaAT0tKo6nuVw0S1MVg' + \
+ # '1Q7MpWYZs0soHjttq0uLIA3DIbQfLiIvK6/l0BdWTU7+2uQj7lBkQAsFZHoA96ZZg' + \
+ # 'FquQrXRlmYOh+Hx5D9fJkXcXe5tmAg==:'
+ boxpath = '/foo'
+ # headers = {
+ # "*request-target": "get " + boxpath,
+ # "*created": "1402170695",
+ # "host": "example.org",
+ # "date": "Tue, 07 Jun 2014 20:51:35 GMT",
+ # "cache-control": "max-age=60, must-revalidate",
+ # "x-emptyheader": "",
+ # "x-example": "Example header with some whitespace.",
+ # "x-dictionary": "b=2",
+ # "x-dictionary": "a=1",
+ # "x-list": "(a, b, c)",
+ # "Signature-Input": sigInput,
+ # "Signature": sig
+ # }
+ headers = {
+ "*created": "1402170695",
+ "*request-target": "post /foo?param=value&pet=dog",
+ "host": "example.com",
+ "date": "Tue, 07 Jun 2014 20:51:35 GMT",
+ "content-type": "application/json",
+ "digest": "SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=",
+ "content-length": "18",
+ "Signature-Input": sigInput,
+ "Signature": sig
+ }
+ httpPrefix = 'https'
+ debug = False
+ assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
+ boxpath, False, None,
+ messageBodyJsonStr, debug,
+ True)
+
+
def _testHttpsigBase(withDigest):
print('testHttpsig(' + str(withDigest) + ')')
@@ -3116,9 +3243,6 @@ def testValidHashTag():
def runAllTests():
print('Running tests...')
- testHttpsig()
- return
-
testFunctions()
testValidHashTag()
testPrepareHtmlPostNickname()
@@ -3156,6 +3280,7 @@ def runAllTests():
testAddEmoji()
testActorParsing()
testHttpsig()
+ testHttpSigNew()
testCache()
testThreads()
testCreatePerson()
From 3d1c4405844a5e70dbe67a4e1511242c21bf70c6 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 22 Feb 2021 18:20:33 +0000
Subject: [PATCH 0005/1416] Support for new style of http signatures
---
httpsig.py | 84 +++++++++++++++++++++++++++++
tests.py | 152 +++++++++++++++++++++++++++++++++--------------------
2 files changed, 180 insertions(+), 56 deletions(-)
diff --git a/httpsig.py b/httpsig.py
index d15d94654..bb2997f03 100644
--- a/httpsig.py
+++ b/httpsig.py
@@ -18,6 +18,7 @@ from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import utils as hazutils
+import calendar
import base64
from time import gmtime, strftime
import datetime
@@ -99,6 +100,89 @@ def signPostHeaders(dateStr: str, privateKeyPem: str,
return signatureHeader
+def signPostHeadersNew(dateStr: str, privateKeyPem: str,
+ nickname: str,
+ domain: str, port: int,
+ toDomain: str, toPort: int,
+ path: str,
+ httpPrefix: str,
+ messageBodyJsonStr: str,
+ algorithm: str) -> (str, str):
+ """Returns a raw signature strings that can be plugged into a header
+ as "Signature-Input" and "Signature"
+ used to verify the authenticity of an HTTP transmission.
+ See https://tools.ietf.org/html/draft-ietf-httpbis-message-signatures-01
+ """
+ domain = getFullDomain(domain, port)
+
+ toDomain = getFullDomain(toDomain, toPort)
+
+ timeFormat = "%a, %d %b %Y %H:%M:%S %Z"
+ if not dateStr:
+ currTime = gmtime()
+ secondsSinceEpoch = int(calendar.timegm(currTime))
+ dateStr = strftime(timeFormat, currTime)
+ else:
+ currTime = datetime.datetime.strptime(dateStr, timeFormat)
+ secondsSinceEpoch = int(currTime.timestamp())
+ keyID = httpPrefix + '://' + domain + '/users/' + nickname + '#main-key'
+ if not messageBodyJsonStr:
+ headers = {
+ '*request-target': f'post {path}',
+ '*created': str(secondsSinceEpoch),
+ 'host': toDomain,
+ 'date': dateStr,
+ 'content-type': 'application/json'
+ }
+ else:
+ bodyDigest = messageContentDigest(messageBodyJsonStr)
+ contentLength = len(messageBodyJsonStr)
+ headers = {
+ '*request-target': f'post {path}',
+ '*created': str(secondsSinceEpoch),
+ 'host': toDomain,
+ 'date': dateStr,
+ 'digest': f'SHA-256={bodyDigest}',
+ 'content-type': 'application/activity+json',
+ 'content-length': str(contentLength)
+ }
+ key = load_pem_private_key(privateKeyPem.encode('utf-8'),
+ None, backend=default_backend())
+ # build a digest for signing
+ signedHeaderKeys = headers.keys()
+ signedHeaderText = ''
+ for headerKey in signedHeaderKeys:
+ signedHeaderText += f'{headerKey}: {headers[headerKey]}\n'
+ signedHeaderText = signedHeaderText.strip()
+ headerDigest = getSHA256(signedHeaderText.encode('ascii'))
+
+ # Sign the digest. Potentially other signing algorithms can be added here.
+ signature = ''
+ if algorithm == 'rsa-sha256':
+ rawSignature = key.sign(headerDigest,
+ padding.PKCS1v15(),
+ hazutils.Prehashed(hashes.SHA256()))
+ signature = base64.b64encode(rawSignature).decode('ascii')
+
+ sigKey = 'sig1'
+ # Put it into a valid HTTP signature format
+ signatureInputDict = {
+ 'keyId': keyID,
+ }
+ signatureIndexHeader = '; '.join(
+ [f'{k}="{v}"' for k, v in signatureInputDict.items()])
+ signatureIndexHeader += '; alg=hs2019'
+ signatureIndexHeader += '; created=' + str(secondsSinceEpoch)
+ signatureIndexHeader += \
+ '; ' + sigKey + '=(' + ', '.join(signedHeaderKeys) + ')'
+ signatureDict = {
+ sigKey: signature
+ }
+ signatureHeader = '; '.join(
+ [f'{k}=:{v}:' for k, v in signatureDict.items()])
+ return signatureIndexHeader, signatureHeader
+
+
def createSignedHeader(privateKeyPem: str, nickname: str,
domain: str, port: int,
toDomain: str, toPort: int,
diff --git a/tests.py b/tests.py
index 180dfc661..0256d0d95 100644
--- a/tests.py
+++ b/tests.py
@@ -13,6 +13,7 @@ import json
from time import gmtime, strftime
from pprint import pprint
from httpsig import signPostHeaders
+from httpsig import signPostHeadersNew
from httpsig import verifyPostHeaders
from httpsig import messageContentDigest
from cache import storePersonInCache
@@ -125,59 +126,59 @@ def testHttpSigNew():
'PSXSfBDiUGhwOw76WuSSsf1D4b/vLoJ10wIDAQAB\n' + \
'-----END RSA PUBLIC KEY-----\n'
- # privKey = \
- # '-----BEGIN RSA PRIVATE KEY-----\n' + \
- # 'MIIEqAIBAAKCAQEAhAKYdtoeoy8zcAcR8' + \
- # '74L8cnZxKzAGwd7v36APp7Pv6Q2jdsP\n' + \
- # 'BRrwWEBnez6d0UDKDwGbc6nxfEXAy5mbh' + \
- # 'gajzrw3MOEt8uA5txSKobBpKDeBLOsd\n' + \
- # 'JKFqMGmXCQvEG7YemcxDTRPxAleIAgYYR' + \
- # 'jTSd/QBwVW9OwNFhekro3RtlinV0a75\n' + \
- # 'jfZgkne/YiktSvLG34lw2zqXBDTC5NHRO' + \
- # 'UqGTlML4PlNZS5Ri2U4aCNx2rUPRcKI\n' + \
- # 'lE0PuKxI4T+HIaFpv8+rdV6eUgOrB2xeI' + \
- # '1dSFFn/nnv5OoZJEIB+VmuKn3DCUcCZ\n' + \
- # 'SFlQPSXSfBDiUGhwOw76WuSSsf1D4b/vL' + \
- # 'oJ10wIDAQABAoIBAG/JZuSWdoVHbi56\n' + \
- # 'vjgCgkjg3lkO1KrO3nrdm6nrgA9P9qaPj' + \
- # 'xuKoWaKO1cBQlE1pSWp/cKncYgD5WxE\n' + \
- # 'CpAnRUXG2pG4zdkzCYzAh1i+c34L6oZoH' + \
- # 'sirK6oNcEnHveydfzJL5934egm6p8DW\n' + \
- # '+m1RQ70yUt4uRc0YSor+q1LGJvGQHReF0' + \
- # 'WmJBZHrhz5e63Pq7lE0gIwuBqL8SMaA\n' + \
- # 'yRXtK+JGxZpImTq+NHvEWWCu09SCq0r83' + \
- # '8ceQI55SvzmTkwqtC+8AT2zFviMZkKR\n' + \
- # 'Qo6SPsrqItxZWRty2izawTF0Bf5S2VAx7' + \
- # 'O+6t3wBsQ1sLptoSgX3QblELY5asI0J\n' + \
- # 'YFz7LJECgYkAsqeUJmqXE3LP8tYoIjMIA' + \
- # 'KiTm9o6psPlc8CrLI9CH0UbuaA2JCOM\n' + \
- # 'cCNq8SyYbTqgnWlB9ZfcAm/cFpA8tYci9' + \
- # 'm5vYK8HNxQr+8FS3Qo8N9RJ8d0U5Csw\n' + \
- # 'DzMYfRghAfUGwmlWj5hp1pQzAuhwbOXFt' + \
- # 'xKHVsMPhz1IBtF9Y8jvgqgYHLbmyiu1\n' + \
- # 'mwJ5AL0pYF0G7x81prlARURwHo0Yf52kE' + \
- # 'w1dxpx+JXER7hQRWQki5/NsUEtv+8RT\n' + \
- # 'qn2m6qte5DXLyn83b1qRscSdnCCwKtKWU' + \
- # 'ug5q2ZbwVOCJCtmRwmnP131lWRYfj67\n' + \
- # 'B/xJ1ZA6X3GEf4sNReNAtaucPEelgR2ns' + \
- # 'N0gKQKBiGoqHWbK1qYvBxX2X3kbPDkv\n' + \
- # '9C+celgZd2PW7aGYLCHq7nPbmfDV0yHcW' + \
- # 'jOhXZ8jRMjmANVR/eLQ2EfsRLdW69bn\n' + \
- # 'f3ZD7JS1fwGnO3exGmHO3HZG+6AvberKY' + \
- # 'VYNHahNFEw5TsAcQWDLRpkGybBcxqZo\n' + \
- # '81YCqlqidwfeO5YtlO7etx1xLyqa2NsCe' + \
- # 'G9A86UjG+aeNnXEIDk1PDK+EuiThIUa\n' + \
- # '/2IxKzJKWl1BKr2d4xAfR0ZnEYuRrbeDQ' + \
- # 'YgTImOlfW6/GuYIxKYgEKCFHFqJATAG\n' + \
- # 'IxHrq1PDOiSwXd2GmVVYyEmhZnbcp8Cxa' + \
- # 'EMQoevxAta0ssMK3w6UsDtvUvYvF22m\n' + \
- # 'qQKBiD5GwESzsFPy3Ga0MvZpn3D6EJQLg' + \
- # 'snrtUPZx+z2Ep2x0xc5orneB5fGyF1P\n' + \
- # 'WtP+fG5Q6Dpdz3LRfm+KwBCWFKQjg7uTx' + \
- # 'cjerhBWEYPmEMKYwTJF5PBG9/ddvHLQ\n' + \
- # 'EQeNC8fHGg4UXU8mhHnSBt3EA10qQJfRD' + \
- # 's15M38eG2cYwB1PZpDHScDnDA0=\n' + \
- # '-----END RSA PRIVATE KEY-----'
+ privateKeyPem = \
+ '-----BEGIN RSA PRIVATE KEY-----\n' + \
+ 'MIIEqAIBAAKCAQEAhAKYdtoeoy8zcAcR8' + \
+ '74L8cnZxKzAGwd7v36APp7Pv6Q2jdsP\n' + \
+ 'BRrwWEBnez6d0UDKDwGbc6nxfEXAy5mbh' + \
+ 'gajzrw3MOEt8uA5txSKobBpKDeBLOsd\n' + \
+ 'JKFqMGmXCQvEG7YemcxDTRPxAleIAgYYR' + \
+ 'jTSd/QBwVW9OwNFhekro3RtlinV0a75\n' + \
+ 'jfZgkne/YiktSvLG34lw2zqXBDTC5NHRO' + \
+ 'UqGTlML4PlNZS5Ri2U4aCNx2rUPRcKI\n' + \
+ 'lE0PuKxI4T+HIaFpv8+rdV6eUgOrB2xeI' + \
+ '1dSFFn/nnv5OoZJEIB+VmuKn3DCUcCZ\n' + \
+ 'SFlQPSXSfBDiUGhwOw76WuSSsf1D4b/vL' + \
+ 'oJ10wIDAQABAoIBAG/JZuSWdoVHbi56\n' + \
+ 'vjgCgkjg3lkO1KrO3nrdm6nrgA9P9qaPj' + \
+ 'xuKoWaKO1cBQlE1pSWp/cKncYgD5WxE\n' + \
+ 'CpAnRUXG2pG4zdkzCYzAh1i+c34L6oZoH' + \
+ 'sirK6oNcEnHveydfzJL5934egm6p8DW\n' + \
+ '+m1RQ70yUt4uRc0YSor+q1LGJvGQHReF0' + \
+ 'WmJBZHrhz5e63Pq7lE0gIwuBqL8SMaA\n' + \
+ 'yRXtK+JGxZpImTq+NHvEWWCu09SCq0r83' + \
+ '8ceQI55SvzmTkwqtC+8AT2zFviMZkKR\n' + \
+ 'Qo6SPsrqItxZWRty2izawTF0Bf5S2VAx7' + \
+ 'O+6t3wBsQ1sLptoSgX3QblELY5asI0J\n' + \
+ 'YFz7LJECgYkAsqeUJmqXE3LP8tYoIjMIA' + \
+ 'KiTm9o6psPlc8CrLI9CH0UbuaA2JCOM\n' + \
+ 'cCNq8SyYbTqgnWlB9ZfcAm/cFpA8tYci9' + \
+ 'm5vYK8HNxQr+8FS3Qo8N9RJ8d0U5Csw\n' + \
+ 'DzMYfRghAfUGwmlWj5hp1pQzAuhwbOXFt' + \
+ 'xKHVsMPhz1IBtF9Y8jvgqgYHLbmyiu1\n' + \
+ 'mwJ5AL0pYF0G7x81prlARURwHo0Yf52kE' + \
+ 'w1dxpx+JXER7hQRWQki5/NsUEtv+8RT\n' + \
+ 'qn2m6qte5DXLyn83b1qRscSdnCCwKtKWU' + \
+ 'ug5q2ZbwVOCJCtmRwmnP131lWRYfj67\n' + \
+ 'B/xJ1ZA6X3GEf4sNReNAtaucPEelgR2ns' + \
+ 'N0gKQKBiGoqHWbK1qYvBxX2X3kbPDkv\n' + \
+ '9C+celgZd2PW7aGYLCHq7nPbmfDV0yHcW' + \
+ 'jOhXZ8jRMjmANVR/eLQ2EfsRLdW69bn\n' + \
+ 'f3ZD7JS1fwGnO3exGmHO3HZG+6AvberKY' + \
+ 'VYNHahNFEw5TsAcQWDLRpkGybBcxqZo\n' + \
+ '81YCqlqidwfeO5YtlO7etx1xLyqa2NsCe' + \
+ 'G9A86UjG+aeNnXEIDk1PDK+EuiThIUa\n' + \
+ '/2IxKzJKWl1BKr2d4xAfR0ZnEYuRrbeDQ' + \
+ 'YgTImOlfW6/GuYIxKYgEKCFHFqJATAG\n' + \
+ 'IxHrq1PDOiSwXd2GmVVYyEmhZnbcp8Cxa' + \
+ 'EMQoevxAta0ssMK3w6UsDtvUvYvF22m\n' + \
+ 'qQKBiD5GwESzsFPy3Ga0MvZpn3D6EJQLg' + \
+ 'snrtUPZx+z2Ep2x0xc5orneB5fGyF1P\n' + \
+ 'WtP+fG5Q6Dpdz3LRfm+KwBCWFKQjg7uTx' + \
+ 'cjerhBWEYPmEMKYwTJF5PBG9/ddvHLQ\n' + \
+ 'EQeNC8fHGg4UXU8mhHnSBt3EA10qQJfRD' + \
+ 's15M38eG2cYwB1PZpDHScDnDA0=\n' + \
+ '-----END RSA PRIVATE KEY-----'
sigInput = \
'sig1=(date); alg=rsa-sha256; keyId="test-key-b"'
sig = \
@@ -199,7 +200,8 @@ def testHttpSigNew():
# 'CaB8X/I5/+HLZLGvDiezqi6/7p2Gngf5hwZ0lSdy39vyNMaaAT0tKo6nuVw0S1MVg' + \
# '1Q7MpWYZs0soHjttq0uLIA3DIbQfLiIvK6/l0BdWTU7+2uQj7lBkQAsFZHoA96ZZg' + \
# 'FquQrXRlmYOh+Hx5D9fJkXcXe5tmAg==:'
- boxpath = '/foo'
+ nickname = 'foo'
+ boxpath = '/' + nickname
# headers = {
# "*request-target": "get " + boxpath,
# "*created": "1402170695",
@@ -214,11 +216,14 @@ def testHttpSigNew():
# "Signature-Input": sigInput,
# "Signature": sig
# }
+ dateStr = "Tue, 07 Jun 2014 20:51:35 GMT"
+ domain = "example.com"
+ port = 443
headers = {
"*created": "1402170695",
"*request-target": "post /foo?param=value&pet=dog",
- "host": "example.com",
- "date": "Tue, 07 Jun 2014 20:51:35 GMT",
+ "host": domain,
+ "date": dateStr,
"content-type": "application/json",
"digest": "SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=",
"content-length": "18",
@@ -231,6 +236,41 @@ def testHttpSigNew():
boxpath, False, None,
messageBodyJsonStr, debug,
True)
+ # make a deliberate mistake
+ headers['Signature'] = headers['Signature'].replace('V', 'B')
+ assert not verifyPostHeaders(httpPrefix, publicKeyPem, headers,
+ boxpath, False, None,
+ messageBodyJsonStr, debug,
+ True)
+ # test signing
+ bodyDigest = messageContentDigest(messageBodyJsonStr)
+ contentLength = len(messageBodyJsonStr)
+ headers = {
+ "host": domain,
+ "date": dateStr,
+ "digest": f'SHA-256={bodyDigest}',
+ "content-type": "application/json",
+ "content-length": str(contentLength)
+ }
+ signatureIndexHeader, signatureHeader = \
+ signPostHeadersNew(dateStr, privateKeyPem, nickname,
+ domain, port,
+ domain, port,
+ boxpath, httpPrefix, messageBodyJsonStr,
+ 'rsa-sha256')
+ assert signatureIndexHeader == \
+ 'keyId="https://example.com/users/foo#main-key"; ' + \
+ 'alg=hs2019; created=1402170695; ' + \
+ 'sig1=(*request-target, *created, host, date, ' + \
+ 'digest, content-type, content-length)'
+ assert signatureHeader == \
+ 'sig1=:LQU1PcJILSp1Q30GWINusfftYYKfTtam7InSu2c+ZzfGC' + \
+ 'bTSevRgifZFuG2asFi8ubG/uUVHiBwIxxIz1u/JyWC3lYIFgjQF' + \
+ 'RFM6As2b/ytnMA0LQhNebvk05iUNsz5izSoNTp5h9J7+roWkl6l' + \
+ '8d5EA7vPMTQTJZnyU1cXBlvP1MtuVAKR6MbB3Aa/iZ4XOeaNK5E' + \
+ '1VuPfNFrdnizIELE3nGVoVqNNImgMY3DWhtF3vvezrcT0J2vNGZ' + \
+ 'cvhBfgn/xeAsNxz67SIHMgiXvLL6TFqEI1en9dl9A3ihB6ZO6+W' + \
+ 'gUoW7OobZNlPxAUkQCc2A6oVjCYOdpKdrMAXQp2TQQ==:'
def _testHttpsigBase(withDigest):
From 0b7d96f48c9035ad7b5f39eabaa6e6042825730a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 22 Feb 2021 18:27:04 +0000
Subject: [PATCH 0006/1416] Tidying
---
tests.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tests.py b/tests.py
index 0256d0d95..02fe2b604 100644
--- a/tests.py
+++ b/tests.py
@@ -217,10 +217,11 @@ def testHttpSigNew():
# "Signature": sig
# }
dateStr = "Tue, 07 Jun 2014 20:51:35 GMT"
+ secondsSinceEpoch = 1402170695
domain = "example.com"
port = 443
headers = {
- "*created": "1402170695",
+ "*created": str(secondsSinceEpoch),
"*request-target": "post /foo?param=value&pet=dog",
"host": domain,
"date": dateStr,
@@ -260,7 +261,7 @@ def testHttpSigNew():
'rsa-sha256')
assert signatureIndexHeader == \
'keyId="https://example.com/users/foo#main-key"; ' + \
- 'alg=hs2019; created=1402170695; ' + \
+ 'alg=hs2019; created=' + str(secondsSinceEpoch) + '; ' + \
'sig1=(*request-target, *created, host, date, ' + \
'digest, content-type, content-length)'
assert signatureHeader == \
From e03b2e0fd8da8be2fadbd5554db2b1caade4cbaf Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 14:01:22 +0000
Subject: [PATCH 0007/1416] Set a flag to clear the browser cache when the
theme is changed
---
theme.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/theme.py b/theme.py
index 9a27ec6e6..dbf78cf27 100644
--- a/theme.py
+++ b/theme.py
@@ -619,6 +619,15 @@ def setNewsAvatar(baseDir: str, name: str,
nickname + '@' + domain + '/avatar.png')
+def _setClearCacheFlag(baseDir: str) -> None:
+ """Sets a flag which can be used by an external system
+ (eg. a script in a cron job) to clear the browser cache
+ """
+ flagFilename = baseDir + '/accounts/.clear_cache'
+ with open(flagFilename, 'w+') as flagFile:
+ flagFile.write('\n')
+
+
def setTheme(baseDir: str, name: str, domain: str,
allowLocalNetworkAccess: bool) -> bool:
"""Sets the theme with the given name as the current theme
@@ -674,4 +683,5 @@ def setTheme(baseDir: str, name: str, domain: str,
disableGrayscale(baseDir)
_setThemeInConfig(baseDir, name)
+ _setClearCacheFlag(baseDir)
return result
From 0dbd048a1516bcdf07a1a3200f879d781609f220 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 17:29:22 +0000
Subject: [PATCH 0008/1416] Check authorization on person options
---
daemon.py | 11 +-
webapp_person_options.py | 229 ++++++++++++++++++++-------------------
2 files changed, 125 insertions(+), 115 deletions(-)
diff --git a/daemon.py b/daemon.py
index d2029b346..b147c100d 100644
--- a/daemon.py
+++ b/daemon.py
@@ -2819,7 +2819,7 @@ class PubServer(BaseHTTPRequestHandler):
domain, domainFull,
GETstartTime, GETtimings,
onionDomain, i2pDomain,
- cookie, debug)
+ cookie, debug, authorized)
return
else:
showPublishedDateOnly = self.server.showPublishedDateOnly
@@ -5486,7 +5486,8 @@ class PubServer(BaseHTTPRequestHandler):
domain: str, domainFull: str,
GETstartTime, GETtimings: {},
onionDomain: str, i2pDomain: str,
- cookie: str, debug: bool) -> None:
+ cookie: str, debug: bool,
+ authorized: bool) -> None:
"""Show person options screen
"""
backToPath = ''
@@ -5576,7 +5577,8 @@ class PubServer(BaseHTTPRequestHandler):
lockedAccount,
movedTo, alsoKnownAs,
self.server.textModeBanner,
- self.server.newsInstance).encode('utf-8')
+ self.server.newsInstance,
+ authorized).encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
cookie, callingDomain)
@@ -10495,7 +10497,8 @@ class PubServer(BaseHTTPRequestHandler):
GETstartTime, GETtimings,
self.server.onionDomain,
self.server.i2pDomain,
- cookie, self.server.debug)
+ cookie, self.server.debug,
+ authorized)
return
self._benchmarkGETtimings(GETstartTime, GETtimings,
diff --git a/webapp_person_options.py b/webapp_person_options.py
index 75dd21045..5c903ce9b 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -53,7 +53,8 @@ def htmlPersonOptions(defaultTimeline: str,
movedTo: str,
alsoKnownAs: [],
textModeBanner: str,
- newsInstance: bool) -> str:
+ newsInstance: bool,
+ authorized: bool) -> str:
"""Show options for a person: view/follow/block/report
"""
optionsDomain, optionsPort = getDomainFromActor(optionsActor)
@@ -225,88 +226,91 @@ def htmlPersonOptions(defaultTimeline: str,
optionsActor + '">\n'
optionsStr += ' \n'
- if optionsNickname:
- handle = optionsNickname + '@' + optionsDomainFull
- petname = getPetName(baseDir, nickname, domain, handle)
- optionsStr += \
- ' ' + translate['Petname'] + ': \n' + \
- ' \n' \
- ' ' + \
- translate['Submit'] + ' \n'
+ if authorized:
+ if optionsNickname:
+ handle = optionsNickname + '@' + optionsDomainFull
+ petname = getPetName(baseDir, nickname, domain, handle)
+ optionsStr += \
+ ' ' + translate['Petname'] + ': \n' + \
+ ' \n' \
+ ' ' + \
+ translate['Submit'] + ' \n'
- # checkbox for receiving calendar events
- if isFollowingActor(baseDir, nickname, domain, optionsActor):
- checkboxStr = \
- ' ' + \
- translate['Receive calendar events from this account'] + \
- '\n ' + \
- translate['Submit'] + ' \n'
- if not receivingCalendarEvents(baseDir, nickname, domain,
- optionsNickname, optionsDomainFull):
- checkboxStr = checkboxStr.replace(' checked>', '>')
- optionsStr += checkboxStr
+ # checkbox for receiving calendar events
+ if isFollowingActor(baseDir, nickname, domain, optionsActor):
+ checkboxStr = \
+ ' ' + \
+ translate['Receive calendar events from this account'] + \
+ '\n ' + \
+ translate['Submit'] + ' \n'
+ if not receivingCalendarEvents(baseDir, nickname, domain,
+ optionsNickname,
+ optionsDomainFull):
+ checkboxStr = checkboxStr.replace(' checked>', '>')
+ optionsStr += checkboxStr
- # checkbox for permission to post to newswire
- newswirePostsPermitted = False
- if optionsDomainFull == domainFull:
- adminNickname = getConfigParam(baseDir, 'admin')
- if (nickname == adminNickname or
- (isModerator(baseDir, nickname) and
- not isModerator(baseDir, optionsNickname))):
- newswireBlockedFilename = \
+ # checkbox for permission to post to newswire
+ newswirePostsPermitted = False
+ if optionsDomainFull == domainFull:
+ adminNickname = getConfigParam(baseDir, 'admin')
+ if (nickname == adminNickname or
+ (isModerator(baseDir, nickname) and
+ not isModerator(baseDir, optionsNickname))):
+ newswireBlockedFilename = \
+ baseDir + '/accounts/' + \
+ optionsNickname + '@' + optionsDomain + '/.nonewswire'
+ checkboxStr = \
+ ' ' + \
+ translate['Allow news posts'] + \
+ '\n ' + \
+ translate['Submit'] + ' \n'
+ if os.path.isfile(newswireBlockedFilename):
+ checkboxStr = checkboxStr.replace(' checked>', '>')
+ else:
+ newswirePostsPermitted = True
+ optionsStr += checkboxStr
+
+ # whether blogs created by this account are moderated on the newswire
+ if newswirePostsPermitted:
+ moderatedFilename = \
baseDir + '/accounts/' + \
- optionsNickname + '@' + optionsDomain + '/.nonewswire'
+ optionsNickname + '@' + optionsDomain + '/.newswiremoderated'
checkboxStr = \
' ' + \
- translate['Allow news posts'] + \
+ 'class="profilecheckbox" name="modNewsPosts" checked> ' + \
+ translate['News posts are moderated'] + \
'\n ' + \
+ 'name="submitModNewsPosts">' + \
translate['Submit'] + ' \n'
- if os.path.isfile(newswireBlockedFilename):
- checkboxStr = checkboxStr.replace(' checked>', '>')
- else:
- newswirePostsPermitted = True
- optionsStr += checkboxStr
-
- # whether blogs created by this account are moderated on the newswire
- if newswirePostsPermitted:
- moderatedFilename = \
- baseDir + '/accounts/' + \
- optionsNickname + '@' + optionsDomain + '/.newswiremoderated'
- checkboxStr = \
- ' ' + \
- translate['News posts are moderated'] + \
- '\n ' + \
- translate['Submit'] + ' \n'
- if not os.path.isfile(moderatedFilename):
- checkboxStr = checkboxStr.replace(' checked>', '>')
- optionsStr += checkboxStr
-
- # checkbox for permission to post to featured articles
- if newsInstance and optionsDomainFull == domainFull:
- adminNickname = getConfigParam(baseDir, 'admin')
- if (nickname == adminNickname or
- (isModerator(baseDir, nickname) and
- not isModerator(baseDir, optionsNickname))):
- checkboxStr = \
- ' ' + \
- translate['Featured writer'] + \
- '\n ' + \
- translate['Submit'] + ' \n'
- if not isFeaturedWriter(baseDir, optionsNickname,
- optionsDomain):
+ if not os.path.isfile(moderatedFilename):
checkboxStr = checkboxStr.replace(' checked>', '>')
optionsStr += checkboxStr
+ # checkbox for permission to post to featured articles
+ if newsInstance and optionsDomainFull == domainFull:
+ adminNickname = getConfigParam(baseDir, 'admin')
+ if (nickname == adminNickname or
+ (isModerator(baseDir, nickname) and
+ not isModerator(baseDir, optionsNickname))):
+ checkboxStr = \
+ ' ' + \
+ translate['Featured writer'] + \
+ '\n ' + \
+ translate['Submit'] + ' \n'
+ if not isFeaturedWriter(baseDir, optionsNickname,
+ optionsDomain):
+ checkboxStr = checkboxStr.replace(' checked>', '>')
+ optionsStr += checkboxStr
+
optionsStr += optionsLinkStr
backPath = '/'
if nickname:
@@ -317,49 +321,52 @@ def htmlPersonOptions(defaultTimeline: str,
' ' + translate['Go Back'] + \
' \n'
- optionsStr += \
- ' ' + \
- translate['View'] + ' \n'
+ if authorized:
+ optionsStr += \
+ ' ' + \
+ translate['View'] + ' \n'
optionsStr += donateStr
- optionsStr += \
- ' ' + translate[followStr] + ' \n'
- optionsStr += \
- ' ' + translate[blockStr] + ' \n'
- optionsStr += \
- ' ' + \
- translate['DM'] + ' \n'
- optionsStr += \
- ' ' + translate[snoozeButtonStr] + ' \n'
- optionsStr += \
- ' ' + \
- translate['Report'] + ' \n'
-
- if isModerator(baseDir, nickname):
+ if authorized:
+ optionsStr += \
+ ' ' + translate[followStr] + ' \n'
+ optionsStr += \
+ ' ' + translate[blockStr] + ' \n'
+ optionsStr += \
+ ' ' + \
+ translate['DM'] + ' \n'
+ optionsStr += \
+ ' ' + translate[snoozeButtonStr] + \
+ ' \n'
optionsStr += \
' ' + \
- translate['Info'] + ' \n'
+ 'name="submitReport">' + translate['Report'] + '\n'
- personNotes = ''
- personNotesFilename = \
- baseDir + '/accounts/' + nickname + '@' + domain + \
- '/notes/' + handle + '.txt'
- if os.path.isfile(personNotesFilename):
- with open(personNotesFilename, 'r') as fp:
- personNotes = fp.read()
+ if isModerator(baseDir, nickname):
+ optionsStr += \
+ ' ' + \
+ translate['Info'] + ' \n'
- optionsStr += \
- ' ' + translate['Notes'] + ': \n'
- optionsStr += ' ' + \
- translate['Submit'] + ' \n'
- optionsStr += \
- ' \n'
+ personNotes = ''
+ personNotesFilename = \
+ baseDir + '/accounts/' + nickname + '@' + domain + \
+ '/notes/' + handle + '.txt'
+ if os.path.isfile(personNotesFilename):
+ with open(personNotesFilename, 'r') as fp:
+ personNotes = fp.read()
+
+ optionsStr += \
+ ' ' + translate['Notes'] + ': \n'
+ optionsStr += ' ' + \
+ translate['Submit'] + ' \n'
+ optionsStr += \
+ ' \n'
optionsStr += ' \n'
optionsStr += '\n'
From 8124a7cdc6fdab55bf996f1c817331258f2bb451 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 17:35:26 +0000
Subject: [PATCH 0009/1416] Check that notes belong to the viewer
---
webapp_person_options.py | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/webapp_person_options.py b/webapp_person_options.py
index 5c903ce9b..6459f2d45 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -351,12 +351,13 @@ def htmlPersonOptions(defaultTimeline: str,
translate['Info'] + '\n'
personNotes = ''
- personNotesFilename = \
- baseDir + '/accounts/' + nickname + '@' + domain + \
- '/notes/' + handle + '.txt'
- if os.path.isfile(personNotesFilename):
- with open(personNotesFilename, 'r') as fp:
- personNotes = fp.read()
+ if originPathStr.startswith('/' + nickname + '/'):
+ personNotesFilename = \
+ baseDir + '/accounts/' + nickname + '@' + domain + \
+ '/notes/' + handle + '.txt'
+ if os.path.isfile(personNotesFilename):
+ with open(personNotesFilename, 'r') as fp:
+ personNotes = fp.read()
optionsStr += \
' ' + translate['Notes'] + ': \n'
From 8e343f2ca0240b7dd74ef3773a541fc013105483 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 17:40:22 +0000
Subject: [PATCH 0010/1416] Users
---
webapp_person_options.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/webapp_person_options.py b/webapp_person_options.py
index 6459f2d45..c7f18490a 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -351,7 +351,7 @@ def htmlPersonOptions(defaultTimeline: str,
translate['Info'] + '\n'
personNotes = ''
- if originPathStr.startswith('/' + nickname + '/'):
+ if originPathStr.startswith('/users/' + nickname + '/'):
personNotesFilename = \
baseDir + '/accounts/' + nickname + '@' + domain + \
'/notes/' + handle + '.txt'
From 8635d68e3e1c571f6f0e7158d5ec23089fb54a3a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 17:42:11 +0000
Subject: [PATCH 0011/1416] Debug
---
webapp_person_options.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/webapp_person_options.py b/webapp_person_options.py
index c7f18490a..3ee334b49 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -351,6 +351,7 @@ def htmlPersonOptions(defaultTimeline: str,
translate['Info'] + '\n'
personNotes = ''
+ print('originPathStr=' + originPathStr)
if originPathStr.startswith('/users/' + nickname + '/'):
personNotesFilename = \
baseDir + '/accounts/' + nickname + '@' + domain + \
From 2d861657957306787259cbba28dec42032f875fb Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 17:45:53 +0000
Subject: [PATCH 0012/1416] Origin check
---
webapp_person_options.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/webapp_person_options.py b/webapp_person_options.py
index 3ee334b49..5f824b3bc 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -351,8 +351,7 @@ def htmlPersonOptions(defaultTimeline: str,
translate['Info'] + '\n'
personNotes = ''
- print('originPathStr=' + originPathStr)
- if originPathStr.startswith('/users/' + nickname + '/'):
+ if originPathStr == '/users/' + nickname:
personNotesFilename = \
baseDir + '/accounts/' + nickname + '@' + domain + \
'/notes/' + handle + '.txt'
From 9145ac0801e226a3fec3ce54bb61e262904adc54 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 17:51:48 +0000
Subject: [PATCH 0013/1416] More checks on visibility of items on person
options
---
webapp_person_options.py | 152 ++++++++++++++++++++-------------------
1 file changed, 78 insertions(+), 74 deletions(-)
diff --git a/webapp_person_options.py b/webapp_person_options.py
index 5f824b3bc..176d75bdc 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -227,90 +227,94 @@ def htmlPersonOptions(defaultTimeline: str,
optionsStr += ' \n'
if authorized:
- if optionsNickname:
- handle = optionsNickname + '@' + optionsDomainFull
- petname = getPetName(baseDir, nickname, domain, handle)
- optionsStr += \
- ' ' + translate['Petname'] + ': \n' + \
- ' \n' \
- ' ' + \
- translate['Submit'] + ' \n'
+ if originPathStr == '/users/' + nickname:
+ if optionsNickname:
+ handle = optionsNickname + '@' + optionsDomainFull
+ petname = getPetName(baseDir, nickname, domain, handle)
+ optionsStr += \
+ ' ' + translate['Petname'] + ': \n' + \
+ ' \n' \
+ ' ' + \
+ translate['Submit'] + ' \n'
- # checkbox for receiving calendar events
- if isFollowingActor(baseDir, nickname, domain, optionsActor):
- checkboxStr = \
- ' ' + \
- translate['Receive calendar events from this account'] + \
- '\n ' + \
- translate['Submit'] + ' \n'
- if not receivingCalendarEvents(baseDir, nickname, domain,
- optionsNickname,
- optionsDomainFull):
- checkboxStr = checkboxStr.replace(' checked>', '>')
- optionsStr += checkboxStr
+ # checkbox for receiving calendar events
+ if isFollowingActor(baseDir, nickname, domain, optionsActor):
+ checkboxStr = \
+ ' ' + \
+ translate['Receive calendar events from this account'] + \
+ '\n ' + \
+ translate['Submit'] + ' \n'
+ if not receivingCalendarEvents(baseDir, nickname, domain,
+ optionsNickname,
+ optionsDomainFull):
+ checkboxStr = checkboxStr.replace(' checked>', '>')
+ optionsStr += checkboxStr
- # checkbox for permission to post to newswire
- newswirePostsPermitted = False
- if optionsDomainFull == domainFull:
- adminNickname = getConfigParam(baseDir, 'admin')
- if (nickname == adminNickname or
- (isModerator(baseDir, nickname) and
- not isModerator(baseDir, optionsNickname))):
- newswireBlockedFilename = \
+ # checkbox for permission to post to newswire
+ newswirePostsPermitted = False
+ if optionsDomainFull == domainFull:
+ adminNickname = getConfigParam(baseDir, 'admin')
+ if (nickname == adminNickname or
+ (isModerator(baseDir, nickname) and
+ not isModerator(baseDir, optionsNickname))):
+ newswireBlockedFilename = \
+ baseDir + '/accounts/' + \
+ optionsNickname + '@' + optionsDomain + '/.nonewswire'
+ checkboxStr = \
+ ' ' + \
+ translate['Allow news posts'] + \
+ '\n ' + \
+ translate['Submit'] + ' \n'
+ if os.path.isfile(newswireBlockedFilename):
+ checkboxStr = checkboxStr.replace(' checked>', '>')
+ else:
+ newswirePostsPermitted = True
+ optionsStr += checkboxStr
+
+ # whether blogs created by this account are moderated on
+ # the newswire
+ if newswirePostsPermitted:
+ moderatedFilename = \
baseDir + '/accounts/' + \
- optionsNickname + '@' + optionsDomain + '/.nonewswire'
+ optionsNickname + '@' + \
+ optionsDomain + '/.newswiremoderated'
checkboxStr = \
' ' + \
- translate['Allow news posts'] + \
+ 'class="profilecheckbox" name="modNewsPosts" checked> ' + \
+ translate['News posts are moderated'] + \
'\n ' + \
+ 'name="submitModNewsPosts">' + \
translate['Submit'] + ' \n'
- if os.path.isfile(newswireBlockedFilename):
- checkboxStr = checkboxStr.replace(' checked>', '>')
- else:
- newswirePostsPermitted = True
- optionsStr += checkboxStr
-
- # whether blogs created by this account are moderated on the newswire
- if newswirePostsPermitted:
- moderatedFilename = \
- baseDir + '/accounts/' + \
- optionsNickname + '@' + optionsDomain + '/.newswiremoderated'
- checkboxStr = \
- ' ' + \
- translate['News posts are moderated'] + \
- '\n ' + \
- translate['Submit'] + ' \n'
- if not os.path.isfile(moderatedFilename):
- checkboxStr = checkboxStr.replace(' checked>', '>')
- optionsStr += checkboxStr
-
- # checkbox for permission to post to featured articles
- if newsInstance and optionsDomainFull == domainFull:
- adminNickname = getConfigParam(baseDir, 'admin')
- if (nickname == adminNickname or
- (isModerator(baseDir, nickname) and
- not isModerator(baseDir, optionsNickname))):
- checkboxStr = \
- ' ' + \
- translate['Featured writer'] + \
- '\n ' + \
- translate['Submit'] + ' \n'
- if not isFeaturedWriter(baseDir, optionsNickname,
- optionsDomain):
+ if not os.path.isfile(moderatedFilename):
checkboxStr = checkboxStr.replace(' checked>', '>')
optionsStr += checkboxStr
+ # checkbox for permission to post to featured articles
+ if newsInstance and optionsDomainFull == domainFull:
+ adminNickname = getConfigParam(baseDir, 'admin')
+ if (nickname == adminNickname or
+ (isModerator(baseDir, nickname) and
+ not isModerator(baseDir, optionsNickname))):
+ checkboxStr = \
+ ' ' + \
+ translate['Featured writer'] + \
+ '\n ' + \
+ translate['Submit'] + ' \n'
+ if not isFeaturedWriter(baseDir, optionsNickname,
+ optionsDomain):
+ checkboxStr = checkboxStr.replace(' checked>', '>')
+ optionsStr += checkboxStr
+
optionsStr += optionsLinkStr
backPath = '/'
if nickname:
From 4e6d9d2d4561ea8864ce0cbf31f1fbefc9bc2aba Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 17:58:52 +0000
Subject: [PATCH 0014/1416] Change behavior of back button if not logged in
---
webapp_person_options.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/webapp_person_options.py b/webapp_person_options.py
index 176d75bdc..91f1c14bd 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -321,10 +321,16 @@ def htmlPersonOptions(defaultTimeline: str,
backPath = '/users/' + nickname + '/' + defaultTimeline
if 'moderation' in backToPath:
backPath = '/users/' + nickname + '/moderation'
- optionsStr += \
- ' ' + translate['Go Back'] + \
- ' \n'
+ if authorized:
+ optionsStr += \
+ ' ' + translate['Go Back'] + \
+ ' \n'
+ else:
+ optionsStr += \
+ ' ' + translate['Go Back'] + \
+ ' \n'
if authorized:
optionsStr += \
' ' + \
From 10218086d5bc510957923f341577857e8fd964ac Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 17:59:56 +0000
Subject: [PATCH 0015/1416] Check path
---
webapp_person_options.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/webapp_person_options.py b/webapp_person_options.py
index 91f1c14bd..8afeac28c 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -321,7 +321,7 @@ def htmlPersonOptions(defaultTimeline: str,
backPath = '/users/' + nickname + '/' + defaultTimeline
if 'moderation' in backToPath:
backPath = '/users/' + nickname + '/moderation'
- if authorized:
+ if authorized and originPathStr == '/users/' + nickname:
optionsStr += \
' ' + translate['Go Back'] + \
From 3067689faf3138fa3c9bc9a3bdc54c5482f2688a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 22:29:14 +0000
Subject: [PATCH 0016/1416] Change Outbox to Sent
---
translations/ar.json | 2 +-
translations/ca.json | 2 +-
translations/cy.json | 2 +-
translations/de.json | 2 +-
translations/en.json | 2 +-
translations/es.json | 2 +-
translations/fr.json | 2 +-
translations/ga.json | 2 +-
translations/hi.json | 2 +-
translations/it.json | 2 +-
translations/ja.json | 2 +-
translations/pt.json | 4 ++--
translations/ru.json | 2 +-
translations/zh.json | 2 +-
14 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/translations/ar.json b/translations/ar.json
index ecd8cced3..b6526f443 100644
--- a/translations/ar.json
+++ b/translations/ar.json
@@ -65,7 +65,7 @@
"Create a new DM": "إنشاء DM جديد",
"Switch to profile view": "التبديل إلى عرض الملف الشخصي",
"Inbox": "صندوق الوارد",
- "Outbox": "صندوق الحفظ",
+ "Outbox": "أرسلت",
"Search and follow": "بحث ومتابعة",
"Refresh": "تحديث",
"Nickname or URL. Block using *@domain or nickname@domain": "الاسم المستعار أو عنوان URL. حظر استخدام *@domain أو اسم النطاق@domain",
diff --git a/translations/ca.json b/translations/ca.json
index fd87456c5..6be0c0cf7 100644
--- a/translations/ca.json
+++ b/translations/ca.json
@@ -65,7 +65,7 @@
"Create a new DM": "Crea un nou missatge directe",
"Switch to profile view": "Canvia a la vista del perfil",
"Inbox": "entrada",
- "Outbox": "sortida",
+ "Outbox": "Enviat",
"Search and follow": "Cerca i segueix",
"Refresh": "Actualització",
"Nickname or URL. Block using *@domain or nickname@domain": "Nickname o URL. Bloquegeu amb el domini *@ o el sobrenom@",
diff --git a/translations/cy.json b/translations/cy.json
index c14bab40a..5aa2ba351 100644
--- a/translations/cy.json
+++ b/translations/cy.json
@@ -65,7 +65,7 @@
"Create a new DM": "Creu Neges Uniongyrchol newydd",
"Switch to profile view": "Newid i olwg proffil",
"Inbox": "Mewnflwch",
- "Outbox": "Allan",
+ "Outbox": "Anfonwyd",
"Search and follow": "Chwilio a dilyn",
"Refresh": "Adnewyddu",
"Nickname or URL. Block using *@domain or nickname@domain": "Llysenw neu URL. Blociwch gan ddefnyddio *@domain neu lysenw@domain",
diff --git a/translations/de.json b/translations/de.json
index b1336dc61..3a9db5c27 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -65,7 +65,7 @@
"Create a new DM": "Neue Direktnachricht",
"Switch to profile view": "Zur Profilansicht wechseln",
"Inbox": "Eingang",
- "Outbox": "Ausgang",
+ "Outbox": "Geschickt",
"Search and follow": "Suchen und folgen",
"Refresh": "Aktualisieren",
"Nickname or URL. Block using *@domain or nickname@domain": "Benutzername oder URL. *@Domäne oder Benutzer@Domäne sperren",
diff --git a/translations/en.json b/translations/en.json
index f98ac234d..964abc04c 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -65,7 +65,7 @@
"Create a new DM": "Create a new DM",
"Switch to profile view": "Profile view",
"Inbox": "Inbox",
- "Outbox": "Outbox",
+ "Outbox": "Sent",
"Search and follow": "Search/follow",
"Refresh": "Refresh",
"Nickname or URL. Block using *@domain or nickname@domain": "Nickname or URL. Block using *@domain or nickname@domain",
diff --git a/translations/es.json b/translations/es.json
index 83869d7f2..5ec514803 100644
--- a/translations/es.json
+++ b/translations/es.json
@@ -65,7 +65,7 @@
"Create a new DM": "Crear un nuevo mensaje directo",
"Switch to profile view": "Cambiar a la vista de perfil",
"Inbox": "Entrada",
- "Outbox": "Salida",
+ "Outbox": "Enviada",
"Search and follow": "Busca y sigue",
"Refresh": "Refrescar",
"Nickname or URL. Block using *@domain or nickname@domain": "Apodo o URL. Bloquear usando *@dominio o apodo@dominio",
diff --git a/translations/fr.json b/translations/fr.json
index c579130b3..e36bb2b47 100644
--- a/translations/fr.json
+++ b/translations/fr.json
@@ -65,7 +65,7 @@
"Create a new DM": "Créer un nouveau message direct",
"Switch to profile view": "Passer en vue de profil",
"Inbox": "Réception",
- "Outbox": "Envoi",
+ "Outbox": "Expédié",
"Search and follow": "Rechercher et suivre",
"Refresh": "Rafraîchir",
"Nickname or URL. Block using *@domain or nickname@domain": "Surnom ou URL. Bloquer en utilisant *@domain ou pseudo@domain",
diff --git a/translations/ga.json b/translations/ga.json
index a225f7303..fc712d2f4 100644
--- a/translations/ga.json
+++ b/translations/ga.json
@@ -65,7 +65,7 @@
"Create a new DM": "Cruthaigh Teachtaireacht Dhíreach nua",
"Switch to profile view": "Athraigh an amharcphróifíl",
"Inbox": "Isteach",
- "Outbox": "Outbox",
+ "Outbox": "Seolta",
"Search and follow": "Cuardaigh agus leanúint",
"Refresh": "Athnuachan",
"Nickname or URL. Block using *@domain or nickname@domain": "Leasainm nó URL. Bloc ag baint úsáide as *@fearainn nó leasainm@fearainn",
diff --git a/translations/hi.json b/translations/hi.json
index e500e6f66..ce79d4ed7 100644
--- a/translations/hi.json
+++ b/translations/hi.json
@@ -65,7 +65,7 @@
"Create a new DM": "नया डीएम बनाएं",
"Switch to profile view": "प्रोफ़ाइल दृश्य पर स्विच करें",
"Inbox": "इनबॉक्स",
- "Outbox": "आउटबॉक्स",
+ "Outbox": "भेज दिया",
"Search and follow": "खोज और अनुसरण करें",
"Refresh": "ताज़ा करना",
"Nickname or URL. Block using *@domain or nickname@domain": "उपनाम या URL। *@डोमेन या उपनाम@डोमेन का उपयोग करके ब्लॉक करें",
diff --git a/translations/it.json b/translations/it.json
index b626f6d8a..1cc2f85aa 100644
--- a/translations/it.json
+++ b/translations/it.json
@@ -65,7 +65,7 @@
"Create a new DM": "Crea un nuovo messaggio diretto",
"Switch to profile view": "Passa alla vista profilo",
"Inbox": "Arrivo",
- "Outbox": "In uscita",
+ "Outbox": "Inviata",
"Search and follow": "Cerca e segui",
"Refresh": "Ricaricare",
"Nickname or URL. Block using *@domain or nickname@domain": "Soprannome o URL. Blocca usando *@domain o nickname@domain",
diff --git a/translations/ja.json b/translations/ja.json
index 03a83f83b..c5aafcaff 100644
--- a/translations/ja.json
+++ b/translations/ja.json
@@ -65,7 +65,7 @@
"Create a new DM": "新しいDMを作成する",
"Switch to profile view": "縦断ビューに切り替え",
"Inbox": "受信トレイ",
- "Outbox": "送信トレイ",
+ "Outbox": "送信済み",
"Search and follow": "検索してフォローする",
"Refresh": "リフレッシュ",
"Nickname or URL. Block using *@domain or nickname@domain": "ニックネームまたはURL。 * @ domainまたはnickname @ domainを使用してブロックする",
diff --git a/translations/pt.json b/translations/pt.json
index 83d726b1b..9c5caa4fb 100644
--- a/translations/pt.json
+++ b/translations/pt.json
@@ -64,8 +64,8 @@
"Create a new post": "Crie uma nova postagem",
"Create a new DM": "Crie uma nova mensagem direta",
"Switch to profile view": "Mudar para a vista de perfil",
- "Inbox": "Caixa de entrada",
- "Outbox": "Caixa de fora",
+ "Inbox": "Entrada",
+ "Outbox": "Enviado",
"Search and follow": "Pesquise e siga",
"Refresh": "Atualizar",
"Nickname or URL. Block using *@domain or nickname@domain": "Apelido ou URL. Bloquear usando *@domain ou apelido@domain",
diff --git a/translations/ru.json b/translations/ru.json
index 93e5e2d6b..e4e6d9e5b 100644
--- a/translations/ru.json
+++ b/translations/ru.json
@@ -65,7 +65,7 @@
"Create a new DM": "Создать новое прямое сообщение",
"Switch to profile view": "Переключиться на вид профиля",
"Inbox": "входящие",
- "Outbox": "Исходящие",
+ "Outbox": "Отправлено",
"Search and follow": "Искать и следовать",
"Refresh": "обновление",
"Nickname or URL. Block using *@domain or nickname@domain": "Псевдоним или URL. Блокировка с использованием *@domain или псевдоним@domain",
diff --git a/translations/zh.json b/translations/zh.json
index eb981683b..72ed58f40 100644
--- a/translations/zh.json
+++ b/translations/zh.json
@@ -65,7 +65,7 @@
"Create a new DM": "建立新的直接讯息",
"Switch to profile view": "切换到个人资料视图",
"Inbox": "收件箱",
- "Outbox": "发件箱",
+ "Outbox": "发送",
"Search and follow": "搜索并关注",
"Refresh": "刷新",
"Nickname or URL. Block using *@domain or nickname@domain": "昵称或网址。 使用*@domain或昵称@domain阻止",
From 94b666d8030cdef6064539d0f883dda95229c153 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 23 Feb 2021 22:36:23 +0000
Subject: [PATCH 0017/1416] Outbox becomes sent
---
translations/ar.json | 2 +-
translations/ca.json | 2 +-
translations/cy.json | 2 +-
translations/de.json | 2 +-
translations/en.json | 2 +-
translations/es.json | 2 +-
translations/fr.json | 2 +-
translations/ga.json | 2 +-
translations/hi.json | 2 +-
translations/it.json | 2 +-
translations/ja.json | 2 +-
translations/oc.json | 2 +-
translations/pt.json | 2 +-
translations/ru.json | 2 +-
translations/zh.json | 2 +-
webapp_headerbuttons.py | 2 +-
webapp_timeline.py | 2 +-
17 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/translations/ar.json b/translations/ar.json
index b6526f443..bec3a0389 100644
--- a/translations/ar.json
+++ b/translations/ar.json
@@ -65,7 +65,7 @@
"Create a new DM": "إنشاء DM جديد",
"Switch to profile view": "التبديل إلى عرض الملف الشخصي",
"Inbox": "صندوق الوارد",
- "Outbox": "أرسلت",
+ "Sent": "أرسلت",
"Search and follow": "بحث ومتابعة",
"Refresh": "تحديث",
"Nickname or URL. Block using *@domain or nickname@domain": "الاسم المستعار أو عنوان URL. حظر استخدام *@domain أو اسم النطاق@domain",
diff --git a/translations/ca.json b/translations/ca.json
index 6be0c0cf7..ae3607114 100644
--- a/translations/ca.json
+++ b/translations/ca.json
@@ -65,7 +65,7 @@
"Create a new DM": "Crea un nou missatge directe",
"Switch to profile view": "Canvia a la vista del perfil",
"Inbox": "entrada",
- "Outbox": "Enviat",
+ "Sent": "Enviat",
"Search and follow": "Cerca i segueix",
"Refresh": "Actualització",
"Nickname or URL. Block using *@domain or nickname@domain": "Nickname o URL. Bloquegeu amb el domini *@ o el sobrenom@",
diff --git a/translations/cy.json b/translations/cy.json
index 5aa2ba351..0ab618d79 100644
--- a/translations/cy.json
+++ b/translations/cy.json
@@ -65,7 +65,7 @@
"Create a new DM": "Creu Neges Uniongyrchol newydd",
"Switch to profile view": "Newid i olwg proffil",
"Inbox": "Mewnflwch",
- "Outbox": "Anfonwyd",
+ "Sent": "Anfonwyd",
"Search and follow": "Chwilio a dilyn",
"Refresh": "Adnewyddu",
"Nickname or URL. Block using *@domain or nickname@domain": "Llysenw neu URL. Blociwch gan ddefnyddio *@domain neu lysenw@domain",
diff --git a/translations/de.json b/translations/de.json
index 3a9db5c27..a5f963c83 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -65,7 +65,7 @@
"Create a new DM": "Neue Direktnachricht",
"Switch to profile view": "Zur Profilansicht wechseln",
"Inbox": "Eingang",
- "Outbox": "Geschickt",
+ "Sent": "Geschickt",
"Search and follow": "Suchen und folgen",
"Refresh": "Aktualisieren",
"Nickname or URL. Block using *@domain or nickname@domain": "Benutzername oder URL. *@Domäne oder Benutzer@Domäne sperren",
diff --git a/translations/en.json b/translations/en.json
index 964abc04c..4d2af2ec5 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -65,7 +65,7 @@
"Create a new DM": "Create a new DM",
"Switch to profile view": "Profile view",
"Inbox": "Inbox",
- "Outbox": "Sent",
+ "Sent": "Sent",
"Search and follow": "Search/follow",
"Refresh": "Refresh",
"Nickname or URL. Block using *@domain or nickname@domain": "Nickname or URL. Block using *@domain or nickname@domain",
diff --git a/translations/es.json b/translations/es.json
index 5ec514803..095363f66 100644
--- a/translations/es.json
+++ b/translations/es.json
@@ -65,7 +65,7 @@
"Create a new DM": "Crear un nuevo mensaje directo",
"Switch to profile view": "Cambiar a la vista de perfil",
"Inbox": "Entrada",
- "Outbox": "Enviada",
+ "Sent": "Enviada",
"Search and follow": "Busca y sigue",
"Refresh": "Refrescar",
"Nickname or URL. Block using *@domain or nickname@domain": "Apodo o URL. Bloquear usando *@dominio o apodo@dominio",
diff --git a/translations/fr.json b/translations/fr.json
index e36bb2b47..835b52d5f 100644
--- a/translations/fr.json
+++ b/translations/fr.json
@@ -65,7 +65,7 @@
"Create a new DM": "Créer un nouveau message direct",
"Switch to profile view": "Passer en vue de profil",
"Inbox": "Réception",
- "Outbox": "Expédié",
+ "Sent": "Expédié",
"Search and follow": "Rechercher et suivre",
"Refresh": "Rafraîchir",
"Nickname or URL. Block using *@domain or nickname@domain": "Surnom ou URL. Bloquer en utilisant *@domain ou pseudo@domain",
diff --git a/translations/ga.json b/translations/ga.json
index fc712d2f4..b04c8b874 100644
--- a/translations/ga.json
+++ b/translations/ga.json
@@ -65,7 +65,7 @@
"Create a new DM": "Cruthaigh Teachtaireacht Dhíreach nua",
"Switch to profile view": "Athraigh an amharcphróifíl",
"Inbox": "Isteach",
- "Outbox": "Seolta",
+ "Sent": "Seolta",
"Search and follow": "Cuardaigh agus leanúint",
"Refresh": "Athnuachan",
"Nickname or URL. Block using *@domain or nickname@domain": "Leasainm nó URL. Bloc ag baint úsáide as *@fearainn nó leasainm@fearainn",
diff --git a/translations/hi.json b/translations/hi.json
index ce79d4ed7..a3a81ab27 100644
--- a/translations/hi.json
+++ b/translations/hi.json
@@ -65,7 +65,7 @@
"Create a new DM": "नया डीएम बनाएं",
"Switch to profile view": "प्रोफ़ाइल दृश्य पर स्विच करें",
"Inbox": "इनबॉक्स",
- "Outbox": "भेज दिया",
+ "Sent": "भेज दिया",
"Search and follow": "खोज और अनुसरण करें",
"Refresh": "ताज़ा करना",
"Nickname or URL. Block using *@domain or nickname@domain": "उपनाम या URL। *@डोमेन या उपनाम@डोमेन का उपयोग करके ब्लॉक करें",
diff --git a/translations/it.json b/translations/it.json
index 1cc2f85aa..13a001e35 100644
--- a/translations/it.json
+++ b/translations/it.json
@@ -65,7 +65,7 @@
"Create a new DM": "Crea un nuovo messaggio diretto",
"Switch to profile view": "Passa alla vista profilo",
"Inbox": "Arrivo",
- "Outbox": "Inviata",
+ "Sent": "Inviata",
"Search and follow": "Cerca e segui",
"Refresh": "Ricaricare",
"Nickname or URL. Block using *@domain or nickname@domain": "Soprannome o URL. Blocca usando *@domain o nickname@domain",
diff --git a/translations/ja.json b/translations/ja.json
index c5aafcaff..36ea8d2ef 100644
--- a/translations/ja.json
+++ b/translations/ja.json
@@ -65,7 +65,7 @@
"Create a new DM": "新しいDMを作成する",
"Switch to profile view": "縦断ビューに切り替え",
"Inbox": "受信トレイ",
- "Outbox": "送信済み",
+ "Sent": "送信済み",
"Search and follow": "検索してフォローする",
"Refresh": "リフレッシュ",
"Nickname or URL. Block using *@domain or nickname@domain": "ニックネームまたはURL。 * @ domainまたはnickname @ domainを使用してブロックする",
diff --git a/translations/oc.json b/translations/oc.json
index 1221d8e4d..ce631490f 100644
--- a/translations/oc.json
+++ b/translations/oc.json
@@ -116,7 +116,7 @@
"Remove": "Suprimir",
"Refresh": "Actualizar",
"Search and follow": "Cercar e seguir",
- "Outbox": "Enviats",
+ "Sent": "Enviats",
"Inbox": "Recepcion",
"Switch to profile view": "Passar a la vista perfil",
"Create a new DM": "Crear un messatge dirèct nòu",
diff --git a/translations/pt.json b/translations/pt.json
index 9c5caa4fb..b86088f68 100644
--- a/translations/pt.json
+++ b/translations/pt.json
@@ -65,7 +65,7 @@
"Create a new DM": "Crie uma nova mensagem direta",
"Switch to profile view": "Mudar para a vista de perfil",
"Inbox": "Entrada",
- "Outbox": "Enviado",
+ "Sent": "Enviado",
"Search and follow": "Pesquise e siga",
"Refresh": "Atualizar",
"Nickname or URL. Block using *@domain or nickname@domain": "Apelido ou URL. Bloquear usando *@domain ou apelido@domain",
diff --git a/translations/ru.json b/translations/ru.json
index e4e6d9e5b..88ea8db79 100644
--- a/translations/ru.json
+++ b/translations/ru.json
@@ -65,7 +65,7 @@
"Create a new DM": "Создать новое прямое сообщение",
"Switch to profile view": "Переключиться на вид профиля",
"Inbox": "входящие",
- "Outbox": "Отправлено",
+ "Sent": "Отправлено",
"Search and follow": "Искать и следовать",
"Refresh": "обновление",
"Nickname or URL. Block using *@domain or nickname@domain": "Псевдоним или URL. Блокировка с использованием *@domain или псевдоним@domain",
diff --git a/translations/zh.json b/translations/zh.json
index 72ed58f40..90283d086 100644
--- a/translations/zh.json
+++ b/translations/zh.json
@@ -65,7 +65,7 @@
"Create a new DM": "建立新的直接讯息",
"Switch to profile view": "切换到个人资料视图",
"Inbox": "收件箱",
- "Outbox": "发送",
+ "Sent": "发送",
"Search and follow": "搜索并关注",
"Refresh": "刷新",
"Nickname or URL. Block using *@domain or nickname@domain": "昵称或网址。 使用*@domain或昵称@domain阻止",
diff --git a/webapp_headerbuttons.py b/webapp_headerbuttons.py
index bf922d588..85c2d9fb3 100644
--- a/webapp_headerbuttons.py
+++ b/webapp_headerbuttons.py
@@ -202,7 +202,7 @@ def headerButtonsTimeline(defaultTimeline: str,
'' + \
- '' + translate['Outbox'] + \
+ '' + translate['Sent'] + \
' '
# add other buttons
diff --git a/webapp_timeline.py b/webapp_timeline.py
index 8f2e4c399..1c3cf7f63 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -385,7 +385,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
menuInbox = \
htmlHideFromScreenReader('📥') + ' ' + translate['Inbox']
menuOutbox = \
- htmlHideFromScreenReader('📤') + ' ' + translate['Outbox']
+ htmlHideFromScreenReader('📤') + ' ' + translate['Sent']
menuSearch = \
htmlHideFromScreenReader('🔍') + ' ' + \
translate['Search and follow']
From 764f6673c0db19d5fbad1688c2e229f465d22d77 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 09:54:37 +0000
Subject: [PATCH 0018/1416] Improve follow checking when a DM arrives
---
follow.py | 7 +++++++
inbox.py | 7 ++++---
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/follow.py b/follow.py
index cce18f1b2..b29632ea1 100644
--- a/follow.py
+++ b/follow.py
@@ -126,6 +126,7 @@ def _removeFromFollowRejects(baseDir: str,
def isFollowingActor(baseDir: str,
nickname: str, domain: str, actor: str) -> bool:
"""Is the given nickname following the given actor?
+ The actor can also be a handle: nickname@domain
"""
if ':' in domain:
domain = domain.split(':')[0]
@@ -137,6 +138,12 @@ def isFollowingActor(baseDir: str,
return False
if actor.lower() in open(followingFile).read().lower():
return True
+ if '@' in actor and '://' not in actor:
+ # the actor is a handle: nickname@domain
+ followingHandle = actor.lower()
+ if followingHandle in open(followingFile).read().lower():
+ return True
+ return False
followingNickname = getNicknameFromActor(actor)
if not followingNickname:
print('WARN: unable to find nickname in ' + actor)
diff --git a/inbox.py b/inbox.py
index 86507b87d..321a27480 100644
--- a/inbox.py
+++ b/inbox.py
@@ -40,6 +40,7 @@ from categories import setHashtagCategory
from httpsig import verifyPostHeaders
from session import createSession
from session import getJson
+from follow import isFollowingActor
from follow import receiveFollowRequest
from follow import getFollowersOfActor
from follow import unfollowerOfAccount
@@ -73,7 +74,6 @@ from git import receiveGitPatch
from followingCalendar import receivingCalendarEvents
from happening import saveEventPost
from delete import removeOldHashtags
-from follow import isFollowingActor
from categories import guessHashtagCategory
from context import hasValidContext
@@ -2288,8 +2288,9 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
sendH = \
sendingActorNickname + '@' + sendingActorDomain
if sendH != nickname + '@' + domain:
- if sendH not in \
- open(followingFilename).read():
+ if not isFollowingActor(baseDir,
+ nickname, domain,
+ sendH):
print(nickname + '@' + domain +
' cannot receive DM from ' +
sendH +
From 99035b1b7bcd125a42fb333557c2c1285ef0455b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 09:56:08 +0000
Subject: [PATCH 0019/1416] Redundant logic
---
follow.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/follow.py b/follow.py
index b29632ea1..c3a383664 100644
--- a/follow.py
+++ b/follow.py
@@ -138,12 +138,6 @@ def isFollowingActor(baseDir: str,
return False
if actor.lower() in open(followingFile).read().lower():
return True
- if '@' in actor and '://' not in actor:
- # the actor is a handle: nickname@domain
- followingHandle = actor.lower()
- if followingHandle in open(followingFile).read().lower():
- return True
- return False
followingNickname = getNicknameFromActor(actor)
if not followingNickname:
print('WARN: unable to find nickname in ' + actor)
From 4555917eeb04191ff549896335609219b67e4df9 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 10:05:30 +0000
Subject: [PATCH 0020/1416] Tidying
---
inbox.py | 52 +++++++++++++++++++++++++++++++---------------------
1 file changed, 31 insertions(+), 21 deletions(-)
diff --git a/inbox.py b/inbox.py
index 321a27480..01623b270 100644
--- a/inbox.py
+++ b/inbox.py
@@ -2263,42 +2263,52 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
postIsDM = isDM(postJsonObject)
if postIsDM:
if nickname != 'inbox':
+ # check for the flag file which indicates to
+ # only receive DMs from people you are following
followDMsFilename = \
baseDir + '/accounts/' + \
nickname + '@' + domain + '/.followDMs'
if os.path.isfile(followDMsFilename):
+ # get the file containing following handles
followingFilename = \
baseDir + '/accounts/' + \
nickname + '@' + domain + '/following.txt'
+ # who is sending a DM?
if not postJsonObject.get('actor'):
return False
sendingActor = postJsonObject['actor']
sendingActorNickname = \
getNicknameFromActor(sendingActor)
+ if not sendingActorNickname:
+ return False
sendingActorDomain, sendingActorPort = \
getDomainFromActor(sendingActor)
- if sendingActorNickname and sendingActorDomain:
- if not os.path.isfile(followingFilename):
- print('No following.txt file exists for ' +
- nickname + '@' + domain +
- ' so not accepting DM from ' +
- sendingActorNickname + '@' +
- sendingActorDomain)
- return False
- sendH = \
- sendingActorNickname + '@' + sendingActorDomain
- if sendH != nickname + '@' + domain:
- if not isFollowingActor(baseDir,
- nickname, domain,
- sendH):
- print(nickname + '@' + domain +
- ' cannot receive DM from ' +
- sendH +
- ' because they do not ' +
- 'follow them')
- return False
- else:
+ if not sendingActorDomain:
return False
+ # check that the following file exists
+ if not os.path.isfile(followingFilename):
+ print('No following.txt file exists for ' +
+ nickname + '@' + domain +
+ ' so not accepting DM from ' +
+ sendingActorNickname + '@' +
+ sendingActorDomain)
+ return False
+ # get the handle of the DM sender
+ sendH = \
+ sendingActorNickname + '@' + sendingActorDomain
+ # Not sending to yourself
+ if sendH != nickname + '@' + domain:
+ # check the follow
+ if not isFollowingActor(baseDir,
+ nickname, domain,
+ sendH):
+ print(nickname + '@' + domain +
+ ' cannot receive DM from ' +
+ sendH +
+ ' because they do not ' +
+ 'follow them')
+ return False
+
# dm index will be updated
updateIndexList.append('dm')
_dmNotify(baseDir, handle,
From a9de85cb1385b7aa0874124aedf56b43da06c37b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 11:01:44 +0000
Subject: [PATCH 0021/1416] Send DM bounce messages
---
inbox.py | 78 +++++++++++++++++++++++++++++++++++++++++---
translations/ar.json | 3 +-
translations/ca.json | 3 +-
translations/cy.json | 3 +-
translations/de.json | 3 +-
translations/en.json | 3 +-
translations/es.json | 3 +-
translations/fr.json | 3 +-
translations/ga.json | 3 +-
translations/hi.json | 3 +-
translations/it.json | 3 +-
translations/ja.json | 3 +-
translations/oc.json | 3 +-
translations/pt.json | 3 +-
translations/ru.json | 3 +-
translations/zh.json | 3 +-
16 files changed, 103 insertions(+), 20 deletions(-)
diff --git a/inbox.py b/inbox.py
index 01623b270..f44d17d2b 100644
--- a/inbox.py
+++ b/inbox.py
@@ -58,6 +58,7 @@ from utils import updateAnnounceCollection
from utils import undoAnnounceCollectionEntry
from utils import dangerousMarkup
from httpsig import messageContentDigest
+from posts import createDirectMessagePost
from posts import validContentWarning
from posts import downloadAnnounce
from posts import isDM
@@ -2056,6 +2057,67 @@ def _updateLastSeen(baseDir: str, handle: str, actor: str) -> None:
lastSeenFile.write(str(daysSinceEpoch))
+def _bounceDM(senderPostId: str, session, httpPrefix: str,
+ baseDir: str, nickname: str, domain: str, port: int,
+ sendingHandle: str, federationList: [],
+ sendThreads: [], postLog: [],
+ cachedWebfingers: {}, personCache: {},
+ translate: {}, debug: bool) -> None:
+ """Sends a bounce message back to the sending handle
+ if a DM has been rejected
+ """
+ print(nickname + '@' + domain +
+ ' cannot receive DM from ' + sendingHandle +
+ ' because they do not follow them')
+ senderNickname = sendingHandle.split('@')[0]
+ senderDomain = sendingHandle.split('@')[1]
+ senderPort = port
+ if ':' in senderDomain:
+ senderPortStr = senderDomain.split(':')[1]
+ if senderPortStr.isdigit():
+ senderPort = int(senderPortStr)
+ senderDomain = senderDomain.split(':')[0]
+ cc = []
+
+ # create the bounce DM
+ subject = None
+ content = translate['DM bounce']
+ followersOnly = False
+ saveToFile = False
+ clientToServer = False
+ commentsEnabled = False
+ attachImageFilename = None
+ mediaType = None
+ imageDescription = ''
+ inReplyTo = removeIdEnding(senderPostId)
+ inReplyToAtomUri = None
+ schedulePost = False
+ eventDate = None
+ eventTime = None
+ location = None
+ postJsonObject = \
+ createDirectMessagePost(baseDir, nickname, domain, port,
+ httpPrefix, content, followersOnly,
+ saveToFile, clientToServer,
+ commentsEnabled,
+ attachImageFilename, mediaType,
+ imageDescription,
+ inReplyTo, inReplyToAtomUri,
+ subject, debug, schedulePost,
+ eventDate, eventTime, location)
+ if not postJsonObject:
+ print('WARN: unable to create bounce message to ' + sendingHandle)
+ return
+ # bounce DM goes back to the sender
+ print('Sending bounce DM to ' + sendingHandle)
+ sendSignedJson(postJsonObject, session, baseDir,
+ nickname, domain, port,
+ senderNickname, senderDomain, senderPort, cc,
+ httpPrefix, False, False, federationList,
+ sendThreads, postLog, cachedWebfingers,
+ personCache, debug, __version__)
+
+
def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
session, keyId: str, handle: str, messageJson: {},
baseDir: str, httpPrefix: str, sendThreads: [],
@@ -2302,11 +2364,17 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
if not isFollowingActor(baseDir,
nickname, domain,
sendH):
- print(nickname + '@' + domain +
- ' cannot receive DM from ' +
- sendH +
- ' because they do not ' +
- 'follow them')
+ # send back a bounce DM
+ if postJsonObject.get('id'):
+ senderPostId = \
+ postJsonObject['id']
+ _bounceDM(senderPostId,
+ session, httpPrefix,
+ baseDir, nickname, domain, port,
+ sendH, federationList,
+ sendThreads, postLog,
+ cachedWebfingers, personCache,
+ translate, debug)
return False
# dm index will be updated
diff --git a/translations/ar.json b/translations/ar.json
index bec3a0389..6d4b5b6d8 100644
--- a/translations/ar.json
+++ b/translations/ar.json
@@ -370,5 +370,6 @@
"Publish a blog article": "نشر مقال بلوق",
"Featured writer": "كاتب متميز",
"Broch mode": "وضع الكتيب",
- "Pixel": "بكسل"
+ "Pixel": "بكسل",
+ "DM bounce": "يتم قبول الرسائل فقط من الحسابات المتبعة"
}
diff --git a/translations/ca.json b/translations/ca.json
index ae3607114..17ee18c1c 100644
--- a/translations/ca.json
+++ b/translations/ca.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Publicar un article del bloc",
"Featured writer": "Escriptor destacat",
"Broch mode": "Mode Broch",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Els missatges només s’accepten des dels comptes seguits"
}
diff --git a/translations/cy.json b/translations/cy.json
index 0ab618d79..b3e77400d 100644
--- a/translations/cy.json
+++ b/translations/cy.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Cyhoeddi erthygl blog",
"Featured writer": "Awdur dan sylw",
"Broch mode": "Modd Broch",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Dim ond o gyfrifon a ddilynir y derbynnir negeseuon"
}
diff --git a/translations/de.json b/translations/de.json
index a5f963c83..c7c1cb650 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Veröffentlichen Sie einen Blog-Artikel",
"Featured writer": "Ausgewählter Schriftsteller",
"Broch mode": "Broch-Modus",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Nachrichten werden nur von folgenden Konten akzeptiert"
}
diff --git a/translations/en.json b/translations/en.json
index 4d2af2ec5..4e3db4794 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Publish a blog article",
"Featured writer": "Featured writer",
"Broch mode": "Broch mode",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Messages are only accepted from followed accounts"
}
diff --git a/translations/es.json b/translations/es.json
index 095363f66..fa7f25060 100644
--- a/translations/es.json
+++ b/translations/es.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Publica un artículo de blog",
"Featured writer": "Escritora destacada",
"Broch mode": "Modo broche",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Solo se aceptan mensajes de cuentas seguidas"
}
diff --git a/translations/fr.json b/translations/fr.json
index 835b52d5f..0c8d6f0c6 100644
--- a/translations/fr.json
+++ b/translations/fr.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Publier un article de blog",
"Featured writer": "Écrivain en vedette",
"Broch mode": "Mode Broch",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Les messages ne sont acceptés que des comptes suivis"
}
diff --git a/translations/ga.json b/translations/ga.json
index b04c8b874..d9eb10393 100644
--- a/translations/ga.json
+++ b/translations/ga.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Foilsigh alt blagála",
"Featured writer": "Scríbhneoir mór le rá",
"Broch mode": "Modh broch",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Ní ghlactar le teachtaireachtaí ach ó chuntais a leanann"
}
diff --git a/translations/hi.json b/translations/hi.json
index a3a81ab27..ac8b0b00e 100644
--- a/translations/hi.json
+++ b/translations/hi.json
@@ -370,5 +370,6 @@
"Publish a blog article": "एक ब्लॉग लेख प्रकाशित करें",
"Featured writer": "फीचर्ड लेखक",
"Broch mode": "ब्रोच मोड",
- "Pixel": "पिक्सेल"
+ "Pixel": "पिक्सेल",
+ "DM bounce": "संदेश केवल अनुसरण किए गए खातों से स्वीकार किए जाते हैं"
}
diff --git a/translations/it.json b/translations/it.json
index 13a001e35..a22a09d4e 100644
--- a/translations/it.json
+++ b/translations/it.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Pubblica un articolo sul blog",
"Featured writer": "Scrittore in primo piano",
"Broch mode": "Modalità Broch",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "I messaggi sono accettati solo dagli account seguiti"
}
diff --git a/translations/ja.json b/translations/ja.json
index 36ea8d2ef..736dde695 100644
--- a/translations/ja.json
+++ b/translations/ja.json
@@ -370,5 +370,6 @@
"Publish a blog article": "ブログ記事を公開する",
"Featured writer": "注目の作家",
"Broch mode": "ブロッホモード",
- "Pixel": "ピクセル"
+ "Pixel": "ピクセル",
+ "DM bounce": "メッセージはフォローされているアカウントからのみ受け付けられます"
}
diff --git a/translations/oc.json b/translations/oc.json
index ce631490f..75d48eee6 100644
--- a/translations/oc.json
+++ b/translations/oc.json
@@ -366,5 +366,6 @@
"Publish a blog article": "Publish a blog article",
"Featured writer": "Featured writer",
"Broch mode": "Broch mode",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Messages are only accepted from followed accounts"
}
diff --git a/translations/pt.json b/translations/pt.json
index b86088f68..e1d37d4f7 100644
--- a/translations/pt.json
+++ b/translations/pt.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Publique um artigo de blog",
"Featured writer": "Escritor em destaque",
"Broch mode": "Modo broch",
- "Pixel": "Pixel"
+ "Pixel": "Pixel",
+ "DM bounce": "Mensagens são aceitas apenas de contas seguidas"
}
diff --git a/translations/ru.json b/translations/ru.json
index 88ea8db79..a1d021f05 100644
--- a/translations/ru.json
+++ b/translations/ru.json
@@ -370,5 +370,6 @@
"Publish a blog article": "Опубликовать статью в блоге",
"Featured writer": "Избранный писатель",
"Broch mode": "Брош режим",
- "Pixel": "Пиксель"
+ "Pixel": "Пиксель",
+ "DM bounce": "Сообщения принимаются только от следующих аккаунтов"
}
diff --git a/translations/zh.json b/translations/zh.json
index 90283d086..8cd6a124d 100644
--- a/translations/zh.json
+++ b/translations/zh.json
@@ -370,5 +370,6 @@
"Publish a blog article": "发布博客文章",
"Featured writer": "特色作家",
"Broch mode": "断点模式",
- "Pixel": "像素点"
+ "Pixel": "像素点",
+ "DM bounce": "仅接受来自后续帐户的邮件"
}
From cc35f0317026426e6625b14bfc3cf298da10740b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 11:09:53 +0000
Subject: [PATCH 0022/1416] Don't send bounces to replies to bounces
---
inbox.py | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/inbox.py b/inbox.py
index f44d17d2b..4f70044cb 100644
--- a/inbox.py
+++ b/inbox.py
@@ -2365,16 +2365,24 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
nickname, domain,
sendH):
# send back a bounce DM
- if postJsonObject.get('id'):
- senderPostId = \
- postJsonObject['id']
- _bounceDM(senderPostId,
- session, httpPrefix,
- baseDir, nickname, domain, port,
- sendH, federationList,
- sendThreads, postLog,
- cachedWebfingers, personCache,
- translate, debug)
+ if postJsonObject.get('id') and \
+ postJsonObject.get('object'):
+ # don't send bounces back to
+ # replies to bounce messages
+ obj = postJsonObject['object']
+ if isinstance(obj, dict):
+ if not obj.get('inReplyTo'):
+ senderPostId = \
+ postJsonObject['id']
+ _bounceDM(senderPostId,
+ session, httpPrefix,
+ baseDir,
+ nickname, domain, port,
+ sendH, federationList,
+ sendThreads, postLog,
+ cachedWebfingers,
+ personCache,
+ translate, debug)
return False
# dm index will be updated
From a0a800c980e115aee10aa72682d8145254f6deed Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 11:43:48 +0000
Subject: [PATCH 0023/1416] Don't send bounce messages too frequently
Otherwise an adversary can tie up your instance with sending bounces
---
inbox.py | 36 +++++++++++++++++++++++++++++-------
1 file changed, 29 insertions(+), 7 deletions(-)
diff --git a/inbox.py b/inbox.py
index 4f70044cb..0efca270d 100644
--- a/inbox.py
+++ b/inbox.py
@@ -2062,13 +2062,25 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
sendingHandle: str, federationList: [],
sendThreads: [], postLog: [],
cachedWebfingers: {}, personCache: {},
- translate: {}, debug: bool) -> None:
+ translate: {}, debug: bool,
+ lastBounceMessage: []) -> bool:
"""Sends a bounce message back to the sending handle
if a DM has been rejected
"""
print(nickname + '@' + domain +
' cannot receive DM from ' + sendingHandle +
' because they do not follow them')
+
+ # Don't send out bounce messages too frequently.
+ # Otherwise an adversary could try to DoS your instance
+ # by continuously sending DMs to you
+ currTime = int(time.time())
+ if currTime - lastBounceMessage[0] < 60:
+ return False
+
+ # record the last time that a bounce was generated
+ lastBounceMessage[0] = currTime
+
senderNickname = sendingHandle.split('@')[0]
senderDomain = sendingHandle.split('@')[1]
senderPort = port
@@ -2107,7 +2119,7 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
eventDate, eventTime, location)
if not postJsonObject:
print('WARN: unable to create bounce message to ' + sendingHandle)
- return
+ return False
# bounce DM goes back to the sender
print('Sending bounce DM to ' + sendingHandle)
sendSignedJson(postJsonObject, session, baseDir,
@@ -2116,6 +2128,7 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
httpPrefix, False, False, federationList,
sendThreads, postLog, cachedWebfingers,
personCache, debug, __version__)
+ return True
def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
@@ -2132,7 +2145,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
unitTest: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
allowLocalNetworkAccess: bool,
- peertubeInstances: []) -> bool:
+ peertubeInstances: [],
+ lastBounceMessage: []) -> bool:
""" Anything which needs to be done after initial checks have passed
"""
actor = keyId
@@ -2377,12 +2391,14 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
_bounceDM(senderPostId,
session, httpPrefix,
baseDir,
- nickname, domain, port,
- sendH, federationList,
+ nickname, domain,
+ port, sendH,
+ federationList,
sendThreads, postLog,
cachedWebfingers,
personCache,
- translate, debug)
+ translate, debug,
+ lastBounceMessage)
return False
# dm index will be updated
@@ -2600,6 +2616,11 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
heartBeatCtr = 0
queueRestoreCtr = 0
+ # time when the last DM bounce message was sent
+ # This is in a list so that it can be changed by reference
+ # within _bounceDM
+ lastBounceMessage = [int(time.time())]
+
while True:
time.sleep(1)
@@ -3056,7 +3077,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
YTReplacementDomain,
showPublishedDateOnly,
allowLocalNetworkAccess,
- peertubeInstances)
+ peertubeInstances,
+ lastBounceMessage)
if debug:
pprint(queueJson['post'])
From 36e921a06dbd55c6fd9810da8d21df9548b25848 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 12:08:36 +0000
Subject: [PATCH 0024/1416] Check the domain when adding or removing accounts
from commandline
---
epicyon.py | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/epicyon.py b/epicyon.py
index cf0289c65..5b5d01b8b 100644
--- a/epicyon.py
+++ b/epicyon.py
@@ -1617,6 +1617,13 @@ if args.addaccount:
if not args.domain or not getConfigParam(baseDir, 'domain'):
print('Use the --domain option to set the domain name')
sys.exit()
+
+ configuredDomain = getConfigParam(baseDir, 'domain')
+ if configuredDomain:
+ if domain != configuredDomain:
+ print('The account domain is expected to be ' + configuredDomain)
+ sys.exit()
+
if not validNickname(domain, nickname):
print(nickname + ' is a reserved name. Use something different.')
sys.exit()
@@ -1688,6 +1695,13 @@ if args.rmaccount:
if not args.domain or not getConfigParam(baseDir, 'domain'):
print('Use the --domain option to set the domain name')
sys.exit()
+
+ configuredDomain = getConfigParam(baseDir, 'domain')
+ if configuredDomain:
+ if domain != configuredDomain:
+ print('The account domain is expected to be ' + configuredDomain)
+ sys.exit()
+
if args.deactivate:
if deactivateAccount(baseDir, nickname, domain):
print('Account for ' + nickname + '@' + domain +
From fd7ff355822a41569290673dbf683e6e8a23a1b0 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 12:55:34 +0000
Subject: [PATCH 0025/1416] Showing DM icon on posts
---
webapp_post.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/webapp_post.py b/webapp_post.py
index b5646c416..9be58c1be 100644
--- a/webapp_post.py
+++ b/webapp_post.py
@@ -1270,8 +1270,9 @@ def individualPostAsHtml(allowDownloads: bool,
showRepeatIcon = showRepeats
isPublicRepeat = False
showDMicon = False
+ postIsDM = isDM(postJsonObject)
if showRepeats:
- if isDM(postJsonObject):
+ if postIsDM:
showDMicon = True
showRepeatIcon = False
else:
@@ -1347,7 +1348,7 @@ def individualPostAsHtml(allowDownloads: bool,
_logPostTiming(enableTimingLog, postStartTime, '9')
# Show a DM icon for DMs in the inbox timeline
- if showDMicon:
+ if postIsDM:
titleStr = \
titleStr + ' \n'
@@ -1501,7 +1502,7 @@ def individualPostAsHtml(allowDownloads: bool,
'" class="' + timeClass + '">' + publishedStr + ' \n'
# change the background color for DMs in inbox timeline
- if showDMicon:
+ if postIsDM:
containerClassIcons = 'containericons dm'
containerClass = 'container dm'
From 91c900a6d6574848b035e67167d169b5a87bd1eb Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 13:43:38 +0000
Subject: [PATCH 0026/1416] Background for different post types
---
epicyon-profile.css | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 2afefdc66..384c60893 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -599,15 +599,15 @@ a:focus {
vertical-align: middle;
}
-.darker {
+.container.darker {
background-color: var(--main-bg-color-reply);
}
-.dm {
+.container.dm {
background-color: var(--main-bg-color-dm);
}
-.report {
+.container.report {
border-color: #255;
background-color: var(--main-bg-color-report);
}
From e75e35fc22089d6d6d6448f5e0fc495d84973b3f Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 14:31:04 +0000
Subject: [PATCH 0027/1416] Allow gemini style links
---
webapp_column_left.py | 16 +++++++++++++++-
webapp_post.py | 2 --
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/webapp_column_left.py b/webapp_column_left.py
index 14651564f..61d1d0014 100644
--- a/webapp_column_left.py
+++ b/webapp_column_left.py
@@ -176,7 +176,8 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
if ' ' not in lineStr:
if '#' not in lineStr:
if '*' not in lineStr:
- continue
+ if not lineStr.startswith('=> '):
+ continue
lineStr = lineStr.strip()
words = lineStr.split(' ')
# get the link
@@ -186,6 +187,8 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
continue
if word == '*':
continue
+ if word == '=>':
+ continue
if '://' in word:
linkStr = word
break
@@ -203,6 +206,17 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
'rel="nofollow noopener noreferrer">' + \
lineStr + '
\n'
linksFileContainsEntries = True
+ elif lineStr.startswith('=> '):
+ # gemini style link
+ lineStr = lineStr.replace('=> ', '')
+ lineStr = lineStr.replace(linkStr, '')
+ # add link to the returned html
+ htmlStr += \
+ ' ' + \
+ lineStr.strip() + '
\n'
+ linksFileContainsEntries = True
else:
if lineStr.startswith('#') or lineStr.startswith('*'):
lineStr = lineStr[1:].strip()
diff --git a/webapp_post.py b/webapp_post.py
index 9be58c1be..f66d53a87 100644
--- a/webapp_post.py
+++ b/webapp_post.py
@@ -1269,11 +1269,9 @@ def individualPostAsHtml(allowDownloads: bool,
# If this is the inbox timeline then don't show the repeat icon on any DMs
showRepeatIcon = showRepeats
isPublicRepeat = False
- showDMicon = False
postIsDM = isDM(postJsonObject)
if showRepeats:
if postIsDM:
- showDMicon = True
showRepeatIcon = False
else:
if not isPublicPost(postJsonObject):
From 6a93f8d9a85fcdaab1358551396ce2737eae7595 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 14:41:46 +0000
Subject: [PATCH 0028/1416] Support markdown format links
---
webapp_column_left.py | 42 +++++++++++++++++++++++++++++++-----------
1 file changed, 31 insertions(+), 11 deletions(-)
diff --git a/webapp_column_left.py b/webapp_column_left.py
index 61d1d0014..598b53821 100644
--- a/webapp_column_left.py
+++ b/webapp_column_left.py
@@ -176,22 +176,42 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
if ' ' not in lineStr:
if '#' not in lineStr:
if '*' not in lineStr:
- if not lineStr.startswith('=> '):
- continue
+ if not lineStr.startswith('['):
+ if not lineStr.startswith('=> '):
+ continue
lineStr = lineStr.strip()
- words = lineStr.split(' ')
- # get the link
linkStr = None
- for word in words:
- if word == '#':
+ if not lineStr.startswith('['):
+ words = lineStr.split(' ')
+ # get the link
+ for word in words:
+ if word == '#':
+ continue
+ if word == '*':
+ continue
+ if word == '=>':
+ continue
+ if '://' in word:
+ linkStr = word
+ break
+ else:
+ # markdown link
+ if ']' not in lineStr:
continue
- if word == '*':
+ if '(' not in lineStr:
continue
- if word == '=>':
+ if ')' not in lineStr:
continue
- if '://' in word:
- linkStr = word
- break
+ linkStr = lineStr.split('(')[1]
+ if ')' not in linkStr:
+ continue
+ linkStr = linkStr.split(')')[0]
+ if '://' not in linkStr:
+ continue
+ lineStr = lineStr.split('[')[1]
+ if ']' not in lineStr:
+ continue
+ lineStr = lineStr.split(']')[0]
if linkStr:
lineStr = lineStr.replace(linkStr, '').strip()
# avoid any dubious scripts being added
From 53774bed1b21d324abedae527c12016b105fa89d Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 18:44:26 +0000
Subject: [PATCH 0029/1416] Welcome screen
---
epicyon-welcome.css | 233 +++++++++++++++++++++++++++++++++++++++++++
translations/ar.json | 3 +-
translations/ca.json | 3 +-
translations/cy.json | 3 +-
translations/de.json | 3 +-
translations/en.json | 3 +-
translations/es.json | 3 +-
translations/fr.json | 3 +-
translations/ga.json | 3 +-
translations/hi.json | 3 +-
translations/it.json | 3 +-
translations/ja.json | 3 +-
translations/oc.json | 3 +-
translations/pt.json | 3 +-
translations/ru.json | 3 +-
translations/zh.json | 3 +-
webapp_welcome.py | 61 +++++++++++
17 files changed, 324 insertions(+), 15 deletions(-)
create mode 100644 epicyon-welcome.css
create mode 100644 webapp_welcome.py
diff --git a/epicyon-welcome.css b/epicyon-welcome.css
new file mode 100644
index 000000000..70f984bc4
--- /dev/null
+++ b/epicyon-welcome.css
@@ -0,0 +1,233 @@
+@chaste "UTF-8";
+
+:root {
+ --welcome-bg-color: #282c37;
+ --link-bg-color: #282c37;
+ --welcome-fg-color: #dddddd;
+ --main-link-color: #999;
+ --main-visited-color: #888;
+ --border-color: #505050;
+ --border-width: 2px;
+ --font-size-header: 18px;
+ --font-color-header: #ccc;
+ --welcome-font-size: 22px;
+ --welcome-font-size-mobile: 40px;
+ --text-entry-foreground: #ccc;
+ --text-entry-background: #111;
+ --time-color: #aaa;
+ --button-text: #FFFFFF;
+ --button-background: #999;
+ --button-selected: #666;
+ --form-border-radius: 30px;
+ --focus-color: white;
+ --line-spacing: 130%;
+ --welcome-logo-width: 20%;
+ --main-link-color-hover: #bbb;
+ --rendering: normal;
+}
+
+@font-face {
+ font-family: 'Bedstead';
+ font-style: italic;
+ font-weight: normal;
+ font-display: block;
+ src: url('./fonts/bedstead.otf') format('opentype');
+}
+@font-face {
+ font-family: 'Bedstead';
+ font-style: normal;
+ font-weight: normal;
+ font-display: block;
+ src: url('./fonts/bedstead.otf') format('opentype');
+}
+
+body, html {
+ background-color: var(--welcome-bg-color);
+ color: var(--welcome-fg-color);
+
+ background-image: url("/welcome-background.jpg");
+ background-size: cover;
+ -webkit-background-size: cover;
+ -moz-background-size: cover;
+ background-repeat: no-repeat;
+ background-position: center;
+ height: 100%;
+ font-family: Arial, Helvetica, sans-serif;
+ max-width: 60%;
+ min-width: 600px;
+ margin: 0 auto;
+ font-size: var(--welcome-font-size);
+ line-height: var(--line-spacing);
+ image-rendering: var(--rendering);
+}
+
+a, u {
+ color: var(--welcome-fg-color);
+}
+
+a:visited{
+ color: var(--main-visited-color);
+ background: var(--link-bg-color);
+ font-weight: normal;
+ text-decoration: none;
+}
+
+a:link {
+ color: var(--main-link-color);
+ background: var(--link-bg-color);
+ font-weight: normal;
+ text-decoration: none;
+}
+
+a:link:hover {
+ color: var(--main-link-color-hover);
+}
+
+a:visited:hover {
+ color: var(--main-link-color-hover);
+}
+
+a:focus {
+ border: 2px solid var(--focus-color);
+}
+
+form {
+ border: var(--border-width) solid var(--border-color);
+ border-radius: var(--form-border-radius);
+}
+
+.transparent {
+ color: transparent;
+ background: transparent;
+ font-size: 0px;
+ line-height: 0px;
+ height: 0px;
+}
+
+button {
+ background-color: var(--button-background);
+ color: var(--button-text);
+ padding: 14px 20px;
+ margin: 8px 0;
+ border: none;
+ cursor: pointer;
+ width: 100%;
+ font-size: var(--welcome-font-size);
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+.welcome-text {
+ font-size: var(--welcome-font-size);
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+button:hover {
+ opacity: 0.8;
+}
+
+.imgcontainer {
+ text-align: center;
+ margin: 24px 0 12px 0;
+}
+
+.imgcontainer img {
+ width: var(--welcome-logo-width);
+}
+
+img.avatar {
+ width: 40%;
+ border-radius: 50%;
+}
+
+.container {
+ padding: 16px;
+}
+
+.container.next {
+ float: right;
+}
+
+span.psw {
+ float: right;
+ padding-top: 16px;
+}
+
+@media screen and (min-width: 400px) {
+ body, html {
+ background-color: var(--welcome-bg-color);
+ color: var(--welcome-fg-color);
+ height: 100%;
+ font-family: Arial, Helvetica, sans-serif;
+ max-width: 60%;
+ min-width: 600px;
+ margin: 0 auto;
+ font-size: var(--welcome-font-size);
+ font-family: Arial, Helvetica, sans-serif;
+ position: relative;
+ }
+ .welcome-text {
+ font-size: var(--welcome-font-size);
+ font-family: Arial, Helvetica, sans-serif;
+ }
+ input[type=text], input[type=password] {
+ width: 100%;
+ padding: 12px 20px;
+ margin: 8px 0;
+ display: inline-block;
+ border: 1px solid #ccc;
+ box-sizing: border-box;
+ font-size: var(--welcome-font-size);
+ font-family: Arial, Helvetica, sans-serif;
+ }
+ button {
+ background-color: var(--button-background);
+ color: var(--button-text);
+ padding: 14px 20px;
+ margin: 8px 0;
+ border: none;
+ cursor: pointer;
+ width: 100%;
+ font-size: var(--welcome-font-size);
+ font-family: Arial, Helvetica, sans-serif;
+ }
+}
+
+@media screen and (max-width: 1000px) {
+ body, html {
+ background-color: var(--welcome-bg-color);
+ color: var(--welcome-fg-color);
+ height: 100%;
+ font-family: Arial, Helvetica, sans-serif;
+ max-width: 95%;
+ min-width: 600px;
+ margin: 0 auto;
+ font-size: var(--welcome-font-size-mobile);
+ font-family: Arial, Helvetica, sans-serif;
+ position: relative;
+ }
+ .welcome-text {
+ font-size: var(--welcome-font-size-mobile);
+ font-family: Arial, Helvetica, sans-serif;
+ }
+ input[type=text], input[type=password] {
+ width: 100%;
+ padding: 12px 20px;
+ margin: 8px 0;
+ display: inline-block;
+ border: 1px solid #ccc;
+ box-sizing: border-box;
+ font-size: var(--welcome-font-size-mobile);
+ font-family: Arial, Helvetica, sans-serif;
+ }
+ button {
+ background-color: var(--button-background);
+ color: var(--button-text);
+ padding: 14px 20px;
+ margin: 8px 0;
+ border: none;
+ cursor: pointer;
+ width: 100%;
+ font-size: var(--welcome-font-size-mobile);
+ font-family: Arial, Helvetica, sans-serif;
+ }
+}
diff --git a/translations/ar.json b/translations/ar.json
index 6d4b5b6d8..41410f8b1 100644
--- a/translations/ar.json
+++ b/translations/ar.json
@@ -371,5 +371,6 @@
"Featured writer": "كاتب متميز",
"Broch mode": "وضع الكتيب",
"Pixel": "بكسل",
- "DM bounce": "يتم قبول الرسائل فقط من الحسابات المتبعة"
+ "DM bounce": "يتم قبول الرسائل فقط من الحسابات المتبعة",
+ "Next": "التالي"
}
diff --git a/translations/ca.json b/translations/ca.json
index 17ee18c1c..7bfdfc584 100644
--- a/translations/ca.json
+++ b/translations/ca.json
@@ -371,5 +371,6 @@
"Featured writer": "Escriptor destacat",
"Broch mode": "Mode Broch",
"Pixel": "Pixel",
- "DM bounce": "Els missatges només s’accepten des dels comptes seguits"
+ "DM bounce": "Els missatges només s’accepten des dels comptes seguits",
+ "Next": "Pròxim"
}
diff --git a/translations/cy.json b/translations/cy.json
index b3e77400d..e10b5049f 100644
--- a/translations/cy.json
+++ b/translations/cy.json
@@ -371,5 +371,6 @@
"Featured writer": "Awdur dan sylw",
"Broch mode": "Modd Broch",
"Pixel": "Pixel",
- "DM bounce": "Dim ond o gyfrifon a ddilynir y derbynnir negeseuon"
+ "DM bounce": "Dim ond o gyfrifon a ddilynir y derbynnir negeseuon",
+ "Next": "Nesaf"
}
diff --git a/translations/de.json b/translations/de.json
index c7c1cb650..e280a2e19 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -371,5 +371,6 @@
"Featured writer": "Ausgewählter Schriftsteller",
"Broch mode": "Broch-Modus",
"Pixel": "Pixel",
- "DM bounce": "Nachrichten werden nur von folgenden Konten akzeptiert"
+ "DM bounce": "Nachrichten werden nur von folgenden Konten akzeptiert",
+ "Next": "Nächster"
}
diff --git a/translations/en.json b/translations/en.json
index 4e3db4794..b34511781 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -371,5 +371,6 @@
"Featured writer": "Featured writer",
"Broch mode": "Broch mode",
"Pixel": "Pixel",
- "DM bounce": "Messages are only accepted from followed accounts"
+ "DM bounce": "Messages are only accepted from followed accounts",
+ "Next": "Next"
}
diff --git a/translations/es.json b/translations/es.json
index fa7f25060..c4094c7fb 100644
--- a/translations/es.json
+++ b/translations/es.json
@@ -371,5 +371,6 @@
"Featured writer": "Escritora destacada",
"Broch mode": "Modo broche",
"Pixel": "Pixel",
- "DM bounce": "Solo se aceptan mensajes de cuentas seguidas"
+ "DM bounce": "Solo se aceptan mensajes de cuentas seguidas",
+ "Next": "Próxima"
}
diff --git a/translations/fr.json b/translations/fr.json
index 0c8d6f0c6..067e9c7ac 100644
--- a/translations/fr.json
+++ b/translations/fr.json
@@ -371,5 +371,6 @@
"Featured writer": "Écrivain en vedette",
"Broch mode": "Mode Broch",
"Pixel": "Pixel",
- "DM bounce": "Les messages ne sont acceptés que des comptes suivis"
+ "DM bounce": "Les messages ne sont acceptés que des comptes suivis",
+ "Next": "Suivante"
}
diff --git a/translations/ga.json b/translations/ga.json
index d9eb10393..e90397fdc 100644
--- a/translations/ga.json
+++ b/translations/ga.json
@@ -371,5 +371,6 @@
"Featured writer": "Scríbhneoir mór le rá",
"Broch mode": "Modh broch",
"Pixel": "Pixel",
- "DM bounce": "Ní ghlactar le teachtaireachtaí ach ó chuntais a leanann"
+ "DM bounce": "Ní ghlactar le teachtaireachtaí ach ó chuntais a leanann",
+ "Next": "Ar Aghaidh"
}
diff --git a/translations/hi.json b/translations/hi.json
index ac8b0b00e..fbc481e8f 100644
--- a/translations/hi.json
+++ b/translations/hi.json
@@ -371,5 +371,6 @@
"Featured writer": "फीचर्ड लेखक",
"Broch mode": "ब्रोच मोड",
"Pixel": "पिक्सेल",
- "DM bounce": "संदेश केवल अनुसरण किए गए खातों से स्वीकार किए जाते हैं"
+ "DM bounce": "संदेश केवल अनुसरण किए गए खातों से स्वीकार किए जाते हैं",
+ "Next": "अगला"
}
diff --git a/translations/it.json b/translations/it.json
index a22a09d4e..ba842eca6 100644
--- a/translations/it.json
+++ b/translations/it.json
@@ -371,5 +371,6 @@
"Featured writer": "Scrittore in primo piano",
"Broch mode": "Modalità Broch",
"Pixel": "Pixel",
- "DM bounce": "I messaggi sono accettati solo dagli account seguiti"
+ "DM bounce": "I messaggi sono accettati solo dagli account seguiti",
+ "Next": "Il prossimo"
}
diff --git a/translations/ja.json b/translations/ja.json
index 736dde695..c4c4d8223 100644
--- a/translations/ja.json
+++ b/translations/ja.json
@@ -371,5 +371,6 @@
"Featured writer": "注目の作家",
"Broch mode": "ブロッホモード",
"Pixel": "ピクセル",
- "DM bounce": "メッセージはフォローされているアカウントからのみ受け付けられます"
+ "DM bounce": "メッセージはフォローされているアカウントからのみ受け付けられます",
+ "Next": "次"
}
diff --git a/translations/oc.json b/translations/oc.json
index 75d48eee6..a271ce5ec 100644
--- a/translations/oc.json
+++ b/translations/oc.json
@@ -367,5 +367,6 @@
"Featured writer": "Featured writer",
"Broch mode": "Broch mode",
"Pixel": "Pixel",
- "DM bounce": "Messages are only accepted from followed accounts"
+ "DM bounce": "Messages are only accepted from followed accounts",
+ "Next": "Next"
}
diff --git a/translations/pt.json b/translations/pt.json
index e1d37d4f7..4ccf54d6c 100644
--- a/translations/pt.json
+++ b/translations/pt.json
@@ -371,5 +371,6 @@
"Featured writer": "Escritor em destaque",
"Broch mode": "Modo broch",
"Pixel": "Pixel",
- "DM bounce": "Mensagens são aceitas apenas de contas seguidas"
+ "DM bounce": "Mensagens são aceitas apenas de contas seguidas",
+ "Next": "Próxima"
}
diff --git a/translations/ru.json b/translations/ru.json
index a1d021f05..f845a384d 100644
--- a/translations/ru.json
+++ b/translations/ru.json
@@ -371,5 +371,6 @@
"Featured writer": "Избранный писатель",
"Broch mode": "Брош режим",
"Pixel": "Пиксель",
- "DM bounce": "Сообщения принимаются только от следующих аккаунтов"
+ "DM bounce": "Сообщения принимаются только от следующих аккаунтов",
+ "Next": "Следующий"
}
diff --git a/translations/zh.json b/translations/zh.json
index 8cd6a124d..0e0b33e8c 100644
--- a/translations/zh.json
+++ b/translations/zh.json
@@ -371,5 +371,6 @@
"Featured writer": "特色作家",
"Broch mode": "断点模式",
"Pixel": "像素点",
- "DM bounce": "仅接受来自后续帐户的邮件"
+ "DM bounce": "仅接受来自后续帐户的邮件",
+ "Next": "下一个"
}
diff --git a/webapp_welcome.py b/webapp_welcome.py
new file mode 100644
index 000000000..95ccee620
--- /dev/null
+++ b/webapp_welcome.py
@@ -0,0 +1,61 @@
+__filename__ = "webapp_welcome.py"
+__author__ = "Bob Mottram"
+__license__ = "AGPL3+"
+__version__ = "1.2.0"
+__maintainer__ = "Bob Mottram"
+__email__ = "bob@freedombone.net"
+__status__ = "Production"
+
+import os
+from shutil import copyfile
+from utils import getConfigParam
+from webapp_utils import htmlHeaderWithExternalStyle
+from webapp_utils import htmlFooter
+
+
+def welcomeScreenShown(baseDir: str, nickname: str, domain: str):
+ """Indicates that the welcome screen has been shown for a given account
+ """
+ shownFilename = baseDir + '/accounts/.welcome_shown'
+ shownFile = open(shownFilename, 'w+')
+ if shownFile:
+ shownFile.write('\n')
+ shownFile.close()
+
+
+def htmlWelcomeScreen(baseDir: str, nickname: str, domain: str,
+ language: str, translate: {}) -> str:
+ """Returns the welcome screen
+ """
+ # set a custom background for the welcome screen
+ if os.path.isfile(baseDir + '/accounts/welcome-background-custom.jpg'):
+ if not os.path.isfile(baseDir + '/accounts/welcome-background.jpg'):
+ copyfile(baseDir + '/accounts/welcome-background-custom.jpg',
+ baseDir + '/accounts/welcome-background.jpg')
+
+ welcomeText = 'Welcome to Epicyon'
+ welcomeFilename = baseDir + '/accounts/welcome.txt'
+ if not os.path.isfile(welcomeFilename):
+ defaultFilename = baseDir + '/defaultwelcome/' + language + '.txt'
+ if os.path.isfile(defaultFilename):
+ copyfile(defaultFilename, welcomeFilename)
+ if os.path.isfile(welcomeFilename):
+ with open(baseDir + '/accounts/welcome.txt', 'r') as welcomeFile:
+ welcomeText = welcomeFile.read()
+
+ welcomeForm = ''
+ cssFilename = baseDir + '/epicyon-welcome.css'
+ if os.path.isfile(baseDir + '/welcome.css'):
+ cssFilename = baseDir + '/welcome.css'
+
+ instanceTitle = \
+ getConfigParam(baseDir, 'instanceTitle')
+ welcomeForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
+ welcomeForm += '' + welcomeText + '
\n'
+ welcomeForm += ' \n'
+ welcomeForm += ' ' + \
+ translate['Next'] + ' \n'
+ welcomeForm += '
\n'
+ welcomeForm += '\n'
+ welcomeForm += htmlFooter()
+ return welcomeForm
From 28deeff7758d5925a349bf91dc9ccf7a128f9e3d Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 18:47:29 +0000
Subject: [PATCH 0030/1416] Convert line endings
---
webapp_welcome.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/webapp_welcome.py b/webapp_welcome.py
index 95ccee620..0cdecfe11 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -42,6 +42,7 @@ def htmlWelcomeScreen(baseDir: str, nickname: str, domain: str,
if os.path.isfile(welcomeFilename):
with open(baseDir + '/accounts/welcome.txt', 'r') as welcomeFile:
welcomeText = welcomeFile.read()
+ welcomeText = welcomeText.replace('\n', ' ')
welcomeForm = ''
cssFilename = baseDir + '/epicyon-welcome.css'
From 47788d5a43f2fccbfc2336a81ca2e092c6d1df61 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 19:04:51 +0000
Subject: [PATCH 0031/1416] Formatting of welcome text
---
defaultwelcome/en.txt | 5 +++++
defaultwelcome/en.txt~ | 1 +
webapp_utils.py | 20 ++++++++++++++++++++
webapp_welcome.py | 4 ++--
4 files changed, 28 insertions(+), 2 deletions(-)
create mode 100644 defaultwelcome/en.txt
create mode 100644 defaultwelcome/en.txt~
diff --git a/defaultwelcome/en.txt b/defaultwelcome/en.txt
new file mode 100644
index 000000000..9e8186fe8
--- /dev/null
+++ b/defaultwelcome/en.txt
@@ -0,0 +1,5 @@
+# Welcome
+
+Epicyon is an ActivityPub server designed for self-hosting of a few people on low power systems such as single board computers or old laptops. It's intended to be as easy as possible to install and maintain.
+
+
diff --git a/defaultwelcome/en.txt~ b/defaultwelcome/en.txt~
new file mode 100644
index 000000000..334cab178
--- /dev/null
+++ b/defaultwelcome/en.txt~
@@ -0,0 +1 @@
+Welcome to Epicyon
diff --git a/webapp_utils.py b/webapp_utils.py
index 64b1cae89..1ab1afd40 100644
--- a/webapp_utils.py
+++ b/webapp_utils.py
@@ -21,6 +21,26 @@ from content import addHtmlTags
from content import replaceEmojiFromTags
+def markdownToHtml(markdown: str) -> str:
+ """Converts markdown formatted text to html
+ """
+ linesList = markdown.split('\n')
+ htmlStr = ''
+ for line in linesList:
+ if line.startswith('#####'):
+ line = line.replace('#####', '').strip() + ' '
+ elif line.startswith('####'):
+ line = line.replace('####', '').strip() + ' '
+ elif line.startswith('###'):
+ line = line.replace('###', '').strip() + ' '
+ elif line.startswith('##'):
+ line = line.replace('##', '').strip() + ' '
+ elif line.startswith('#'):
+ line = line.replace('#', '').strip() + ' '
+ htmlStr += line
+ return htmlStr
+
+
def getBrokenLinkSubstitute() -> str:
"""Returns html used to show a default image if the link to
an image is broken
diff --git a/webapp_welcome.py b/webapp_welcome.py
index 0cdecfe11..41f0f4d8f 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -11,6 +11,7 @@ from shutil import copyfile
from utils import getConfigParam
from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter
+from webapp_utils import markdownToHtml
def welcomeScreenShown(baseDir: str, nickname: str, domain: str):
@@ -41,8 +42,7 @@ def htmlWelcomeScreen(baseDir: str, nickname: str, domain: str,
copyfile(defaultFilename, welcomeFilename)
if os.path.isfile(welcomeFilename):
with open(baseDir + '/accounts/welcome.txt', 'r') as welcomeFile:
- welcomeText = welcomeFile.read()
- welcomeText = welcomeText.replace('\n', ' ')
+ welcomeText = markdownToHtml(welcomeFile.read())
welcomeForm = ''
cssFilename = baseDir + '/epicyon-welcome.css'
From 32eb256a496042cba6ae500cad710bf137f3c015 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 20:37:59 +0000
Subject: [PATCH 0032/1416] Welcome text in markdown
---
defaultwelcome/{en.txt => en.md} | 0
defaultwelcome/en.txt~ | 1 -
tests.py | 23 +++++++++++++++++
webapp_utils.py | 42 ++++++++++++++++++++++++++++----
webapp_welcome.py | 6 ++---
5 files changed, 63 insertions(+), 9 deletions(-)
rename defaultwelcome/{en.txt => en.md} (100%)
delete mode 100644 defaultwelcome/en.txt~
diff --git a/defaultwelcome/en.txt b/defaultwelcome/en.md
similarity index 100%
rename from defaultwelcome/en.txt
rename to defaultwelcome/en.md
diff --git a/defaultwelcome/en.txt~ b/defaultwelcome/en.txt~
deleted file mode 100644
index 334cab178..000000000
--- a/defaultwelcome/en.txt~
+++ /dev/null
@@ -1 +0,0 @@
-Welcome to Epicyon
diff --git a/tests.py b/tests.py
index 02fe2b604..79ba90062 100644
--- a/tests.py
+++ b/tests.py
@@ -98,6 +98,7 @@ from newswire import parseFeedDate
from mastoapiv1 import getMastoApiV1IdFromNickname
from mastoapiv1 import getNicknameFromMastoApiV1Id
from webapp_post import prepareHtmlPostNickname
+from webapp_utils import markdownToHtml
testServerAliceRunning = False
testServerBobRunning = False
@@ -3282,9 +3283,31 @@ def testValidHashTag():
assert not validHashTag('This=IsAlsoNotValid"')
+def testMarkdownToHtml():
+ print('testMarkdownToHtml')
+ markdown = 'This is just plain text'
+ assert markdownToHtml(markdown) == markdown
+
+ markdown = '# Title1\n### Title3\n## Title2\n'
+ assert markdownToHtml(markdown) == \
+ 'Title1 Title3 Title2 '
+
+ markdown = \
+ 'This is [a link](https://something.somewhere) to something\n' + \
+ 'And [something else](https://cat.pic).'
+ assert markdownToHtml(markdown) == \
+ 'This is ' + \
+ 'a link to something ' + \
+ 'And ' + \
+ 'something else .'
+
+
def runAllTests():
print('Running tests...')
testFunctions()
+ testMarkdownToHtml()
testValidHashTag()
testPrepareHtmlPostNickname()
testDomainHandling()
diff --git a/webapp_utils.py b/webapp_utils.py
index 1ab1afd40..52b83d424 100644
--- a/webapp_utils.py
+++ b/webapp_utils.py
@@ -24,20 +24,52 @@ from content import replaceEmojiFromTags
def markdownToHtml(markdown: str) -> str:
"""Converts markdown formatted text to html
"""
+ # replace markdown style links with html links
+ replaceLinks = {}
+ text = markdown
+ while '[' in text:
+ if ')' not in text:
+ break
+ text = text.split('[', 1)[1]
+ markdownLink = '[' + text.split(')')[0] + ')'
+ if ']' not in markdownLink or \
+ '(' not in markdownLink:
+ text = text.split(')', 1)[1]
+ continue
+ replaceLinks[markdownLink] = \
+ '' + \
+ markdownLink.split('[')[1].split(']')[0] + \
+ ' '
+ text = text.split(')', 1)[1]
+ for mdLink, htmlLink in replaceLinks.items():
+ markdown = markdown.replace(mdLink, htmlLink)
+
+ # replace headers
linesList = markdown.split('\n')
htmlStr = ''
+ ctr = 0
for line in linesList:
+ if ctr > 0:
+ htmlStr += ' '
if line.startswith('#####'):
- line = line.replace('#####', '').strip() + ' '
+ line = line.replace('#####', '').strip()
+ line = '' + line + ' '
elif line.startswith('####'):
- line = line.replace('####', '').strip() + ' '
+ line = line.replace('####', '').strip()
+ line = '' + line + ' '
elif line.startswith('###'):
- line = line.replace('###', '').strip() + ' '
+ line = line.replace('###', '').strip()
+ line = '' + line + ' '
elif line.startswith('##'):
- line = line.replace('##', '').strip() + ' '
+ line = line.replace('##', '').strip()
+ line = '' + line + ' '
elif line.startswith('#'):
- line = line.replace('#', '').strip() + ' '
+ line = line.replace('#', '').strip()
+ line = '' + line + ' '
htmlStr += line
+ ctr += 1
return htmlStr
diff --git a/webapp_welcome.py b/webapp_welcome.py
index 41f0f4d8f..2ab528d87 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -35,13 +35,13 @@ def htmlWelcomeScreen(baseDir: str, nickname: str, domain: str,
baseDir + '/accounts/welcome-background.jpg')
welcomeText = 'Welcome to Epicyon'
- welcomeFilename = baseDir + '/accounts/welcome.txt'
+ welcomeFilename = baseDir + '/accounts/welcome.md'
if not os.path.isfile(welcomeFilename):
- defaultFilename = baseDir + '/defaultwelcome/' + language + '.txt'
+ defaultFilename = baseDir + '/defaultwelcome/' + language + '.md'
if os.path.isfile(defaultFilename):
copyfile(defaultFilename, welcomeFilename)
if os.path.isfile(welcomeFilename):
- with open(baseDir + '/accounts/welcome.txt', 'r') as welcomeFile:
+ with open(baseDir + '/accounts/welcome.md', 'r') as welcomeFile:
welcomeText = markdownToHtml(welcomeFile.read())
welcomeForm = ''
From 93f7aa78895fe37ef61829349ea429827c04def9 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 20:45:38 +0000
Subject: [PATCH 0033/1416] Button link
---
webapp_welcome.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/webapp_welcome.py b/webapp_welcome.py
index 2ab528d87..d73c69cc8 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -54,8 +54,8 @@ def htmlWelcomeScreen(baseDir: str, nickname: str, domain: str,
welcomeForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
welcomeForm += '' + welcomeText + '
\n'
welcomeForm += ' \n'
welcomeForm += '\n'
welcomeForm += htmlFooter()
From b8ac29a515532eb4001481d15f7709e5c0c13dad Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 21:17:08 +0000
Subject: [PATCH 0034/1416] Displaying welcome screen
---
daemon.py | 25 +++++++++++++++++++++++++
tests.py | 2 +-
webapp_utils.py | 5 +++++
webapp_welcome.py | 27 ++++++++++++++++++++-------
4 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/daemon.py b/daemon.py
index b147c100d..04abd8e45 100644
--- a/daemon.py
+++ b/daemon.py
@@ -181,6 +181,8 @@ from webapp_search import htmlSearchEmojiTextEntry
from webapp_search import htmlSearch
from webapp_hashtagswarm import getHashtagCategoriesFeed
from webapp_hashtagswarm import htmlSearchHashtagCategory
+from webapp_welcome import htmlWelcomeScreen
+from webapp_welcome import isWelcomeScreenComplete
from shares import getSharesFeedForPerson
from shares import addShare
from shares import removeShare
@@ -10670,6 +10672,29 @@ class PubServer(BaseHTTPRequestHandler):
'show about screen done',
'robots txt')
+ if htmlGET and authorized and \
+ '/users/' in self.path and self.path.endswith('/welcome'):
+ nickname = self.path.split('/users/')[1]
+ if '/' in nickname:
+ nickname = nickname.split('/')[0]
+ if not isWelcomeScreenComplete(self.server.baseDir,
+ nickname,
+ self.server.domain):
+ msg = \
+ htmlWelcomeScreen(self.server.baseDir,
+ self.server.systemLanguage,
+ self.server.translate)
+ msg = msg.encode('utf-8')
+ msglen = len(msg)
+ self._login_headers('text/html', msglen, callingDomain)
+ self._write(msg)
+ self._benchmarkGETtimings(GETstartTime, GETtimings,
+ 'following accounts done',
+ 'show welcome screen')
+ return
+ else:
+ self.path = self.path.replace('/welcome', '')
+
# if not authorized then show the login screen
if htmlGET and self.path != '/login' and \
not self._pathIsImage(self.path) and \
diff --git a/tests.py b/tests.py
index 79ba90062..fcacfd4be 100644
--- a/tests.py
+++ b/tests.py
@@ -3290,7 +3290,7 @@ def testMarkdownToHtml():
markdown = '# Title1\n### Title3\n## Title2\n'
assert markdownToHtml(markdown) == \
- 'Title1 Title3 Title2 '
+ 'Title1 Title3 Title2 '
markdown = \
'This is [a link](https://something.somewhere) to something\n' + \
diff --git a/webapp_utils.py b/webapp_utils.py
index 52b83d424..9d144d3b3 100644
--- a/webapp_utils.py
+++ b/webapp_utils.py
@@ -56,18 +56,23 @@ def markdownToHtml(markdown: str) -> str:
if line.startswith('#####'):
line = line.replace('#####', '').strip()
line = '' + line + ' '
+ ctr = -1
elif line.startswith('####'):
line = line.replace('####', '').strip()
line = '' + line + ' '
+ ctr = -1
elif line.startswith('###'):
line = line.replace('###', '').strip()
line = '' + line + ' '
+ ctr = -1
elif line.startswith('##'):
line = line.replace('##', '').strip()
line = '' + line + ' '
+ ctr = -1
elif line.startswith('#'):
line = line.replace('#', '').strip()
line = '' + line + ' '
+ ctr = -1
htmlStr += line
ctr += 1
return htmlStr
diff --git a/webapp_welcome.py b/webapp_welcome.py
index d73c69cc8..ec7a58370 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -14,17 +14,30 @@ from webapp_utils import htmlFooter
from webapp_utils import markdownToHtml
-def welcomeScreenShown(baseDir: str, nickname: str, domain: str):
+def isWelcomeScreenComplete(baseDir: str, nickname: str, domain: str) -> bool:
+ """Returns true if the welcome screen is complete for the given account
+ """
+ accountPath = baseDir + '/accounts/' + nickname + '@' + domain
+ if not os.path.isdir(accountPath):
+ return
+ completeFilename = accountPath + '/.welcome_complete'
+ return os.path.isfile(completeFilename)
+
+
+def welcomeScreenIsComplete(baseDir: str, nickname: str, domain: str) -> None:
"""Indicates that the welcome screen has been shown for a given account
"""
- shownFilename = baseDir + '/accounts/.welcome_shown'
- shownFile = open(shownFilename, 'w+')
- if shownFile:
- shownFile.write('\n')
- shownFile.close()
+ accountPath = baseDir + '/accounts/' + nickname + '@' + domain
+ if not os.path.isdir(accountPath):
+ return
+ completeFilename = accountPath + '/.welcome_complete'
+ completeFile = open(completeFilename, 'w+')
+ if completeFile:
+ completeFile.write('\n')
+ completeFile.close()
-def htmlWelcomeScreen(baseDir: str, nickname: str, domain: str,
+def htmlWelcomeScreen(baseDir: str,
language: str, translate: {}) -> str:
"""Returns the welcome screen
"""
From 064269e4a7f1c64c2170e70c14ea3f6377c0734f Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 21:22:32 +0000
Subject: [PATCH 0035/1416] Default to English
---
webapp_welcome.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/webapp_welcome.py b/webapp_welcome.py
index ec7a58370..087240f3a 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -51,8 +51,9 @@ def htmlWelcomeScreen(baseDir: str,
welcomeFilename = baseDir + '/accounts/welcome.md'
if not os.path.isfile(welcomeFilename):
defaultFilename = baseDir + '/defaultwelcome/' + language + '.md'
- if os.path.isfile(defaultFilename):
- copyfile(defaultFilename, welcomeFilename)
+ if not os.path.isfile(defaultFilename):
+ defaultFilename = baseDir + '/defaultwelcome/en.md'
+ copyfile(defaultFilename, welcomeFilename)
if os.path.isfile(welcomeFilename):
with open(baseDir + '/accounts/welcome.md', 'r') as welcomeFile:
welcomeText = markdownToHtml(welcomeFile.read())
From 13b4307b305248c0a9b38f653ee87190de1fcb6e Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 21:27:20 +0000
Subject: [PATCH 0036/1416] Welcome text
---
defaultwelcome/en.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/defaultwelcome/en.md b/defaultwelcome/en.md
index 9e8186fe8..e05bb2c04 100644
--- a/defaultwelcome/en.md
+++ b/defaultwelcome/en.md
@@ -1,5 +1,7 @@
# Welcome
-Epicyon is an ActivityPub server designed for self-hosting of a few people on low power systems such as single board computers or old laptops. It's intended to be as easy as possible to install and maintain.
+Epicyon is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops.
+Run your own social network presence the way you want to, and say goodbye to Big Tech.
+Now, lets get going...
From bd408e73c0c999fa8eebac30b2c3dd571c6548cf Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Wed, 24 Feb 2021 21:31:53 +0000
Subject: [PATCH 0037/1416] Change link
---
webapp_welcome.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/webapp_welcome.py b/webapp_welcome.py
index 087240f3a..ff75ede00 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -68,7 +68,7 @@ def htmlWelcomeScreen(baseDir: str,
welcomeForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
welcomeForm += '' + welcomeText + '
\n'
welcomeForm += ' \n'
welcomeForm += '\n'
From 830bab130e659e0c631dff322a53e7f541113216 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 10:37:20 +0000
Subject: [PATCH 0038/1416] Allow for a series of welcome screens
---
defaultwelcome/profile_en.md | 3 +
defaultwelcome/{en.md => welcome_en.md} | 0
webapp_welcome.py | 23 ++++++--
webapp_welcome_profile.py | 73 +++++++++++++++++++++++++
4 files changed, 93 insertions(+), 6 deletions(-)
create mode 100644 defaultwelcome/profile_en.md
rename defaultwelcome/{en.md => welcome_en.md} (100%)
create mode 100644 webapp_welcome_profile.py
diff --git a/defaultwelcome/profile_en.md b/defaultwelcome/profile_en.md
new file mode 100644
index 000000000..4f00d8ae1
--- /dev/null
+++ b/defaultwelcome/profile_en.md
@@ -0,0 +1,3 @@
+# Account Setup
+
+Add your avatar image, name and description. Use a small avatar image (eg. 128x128 pixels) so that it's quick to download.
diff --git a/defaultwelcome/en.md b/defaultwelcome/welcome_en.md
similarity index 100%
rename from defaultwelcome/en.md
rename to defaultwelcome/welcome_en.md
diff --git a/webapp_welcome.py b/webapp_welcome.py
index ff75ede00..b3acadd31 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -38,7 +38,9 @@ def welcomeScreenIsComplete(baseDir: str, nickname: str, domain: str) -> None:
def htmlWelcomeScreen(baseDir: str,
- language: str, translate: {}) -> str:
+ language: str, translate: {},
+ currScreen='welcome',
+ nextScreen=None, prevScreen=None) -> str:
"""Returns the welcome screen
"""
# set a custom background for the welcome screen
@@ -47,15 +49,20 @@ def htmlWelcomeScreen(baseDir: str,
copyfile(baseDir + '/accounts/welcome-background-custom.jpg',
baseDir + '/accounts/welcome-background.jpg')
+ if not nextScreen:
+ nextScreen = 'welcome_profile'
+
welcomeText = 'Welcome to Epicyon'
- welcomeFilename = baseDir + '/accounts/welcome.md'
+ welcomeFilename = baseDir + '/accounts/' + currScreen + '.md'
if not os.path.isfile(welcomeFilename):
- defaultFilename = baseDir + '/defaultwelcome/' + language + '.md'
+ defaultFilename = \
+ baseDir + '/defaultwelcome/' + currScreen + '_' + language + '.md'
if not os.path.isfile(defaultFilename):
- defaultFilename = baseDir + '/defaultwelcome/en.md'
+ defaultFilename = \
+ baseDir + '/defaultwelcome/' + currScreen + '_en.md'
copyfile(defaultFilename, welcomeFilename)
if os.path.isfile(welcomeFilename):
- with open(baseDir + '/accounts/welcome.md', 'r') as welcomeFile:
+ with open(welcomeFilename, 'r') as welcomeFile:
welcomeText = markdownToHtml(welcomeFile.read())
welcomeForm = ''
@@ -68,7 +75,11 @@ def htmlWelcomeScreen(baseDir: str,
welcomeForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
welcomeForm += '' + welcomeText + '
\n'
welcomeForm += ' \n'
welcomeForm += '\n'
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
new file mode 100644
index 000000000..901fe5555
--- /dev/null
+++ b/webapp_welcome_profile.py
@@ -0,0 +1,73 @@
+__filename__ = "webapp_welcome_profile.py"
+__author__ = "Bob Mottram"
+__license__ = "AGPL3+"
+__version__ = "1.2.0"
+__maintainer__ = "Bob Mottram"
+__email__ = "bob@freedombone.net"
+__status__ = "Production"
+
+import os
+from shutil import copyfile
+from utils import getConfigParam
+from utils import getImageExtensions
+from webapp_utils import htmlHeaderWithExternalStyle
+from webapp_utils import htmlFooter
+from webapp_utils import markdownToHtml
+
+
+def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
+ httpPrefix: str, domainFull: str,
+ language: str, translate: {},
+ prevScreen='welcome') -> str:
+ """Returns the welcome profile screen to set avatar and bio
+ """
+ # set a custom background for the welcome screen
+ if os.path.isfile(baseDir + '/accounts/welcome-background-custom.jpg'):
+ if not os.path.isfile(baseDir + '/accounts/welcome-background.jpg'):
+ copyfile(baseDir + '/accounts/welcome-background-custom.jpg',
+ baseDir + '/accounts/welcome-background.jpg')
+
+ profileText = 'Welcome to Epicyon'
+ profileFilename = baseDir + '/accounts/welcome_profile.md'
+ if not os.path.isfile(profileFilename):
+ defaultFilename = \
+ baseDir + '/defaultwelcome/profile_' + language + '.md'
+ if not os.path.isfile(defaultFilename):
+ defaultFilename = baseDir + '/defaultwelcome/profile_en.md'
+ copyfile(defaultFilename, profileFilename)
+ if os.path.isfile(profileFilename):
+ with open(profileFilename, 'r') as profileFile:
+ profileText = markdownToHtml(profileFile.read())
+
+ profileForm = ''
+ cssFilename = baseDir + '/epicyon-welcome.css'
+ if os.path.isfile(baseDir + '/welcome.css'):
+ cssFilename = baseDir + '/welcome.css'
+
+ instanceTitle = \
+ getConfigParam(baseDir, 'instanceTitle')
+ profileForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
+
+ # get the url of the avatar
+ for ext in getImageExtensions():
+ avatarFilename = \
+ baseDir + '/accounts/' + nickname + '@' + domain + '/avatar.' + ext
+ if os.path.isfile(avatarFilename):
+ break
+ avatarUrl = \
+ httpPrefix + '://' + domainFull + \
+ '/users/' + nickname + '/avatar.' + ext
+
+ profileForm += '\n'
+ profileForm += ' \n'
+ profileForm += ' \n'
+ profileForm += '' + profileText + '
\n'
+ profileForm += ' \n'
+ profileForm += '\n'
+ profileForm += htmlFooter()
+ return profileForm
From 75249cf554f7992ce56b986109ad90302ac4c3c3 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 10:54:38 +0000
Subject: [PATCH 0039/1416] Markdown emphasis
---
tests.py | 16 ++++++++++++++--
webapp_utils.py | 25 +++++++++++++++++++++++++
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/tests.py b/tests.py
index fcacfd4be..ddab940d4 100644
--- a/tests.py
+++ b/tests.py
@@ -3288,17 +3288,29 @@ def testMarkdownToHtml():
markdown = 'This is just plain text'
assert markdownToHtml(markdown) == markdown
+ markdown = 'This is **bold**'
+ assert markdownToHtml(markdown) == 'This is bold '
+
+ markdown = 'This is *italic*'
+ assert markdownToHtml(markdown) == 'This is italic '
+
+ markdown = 'This is _underlined_'
+ assert markdownToHtml(markdown) == 'This is '
+
+ markdown = 'This is **just** plain text'
+ assert markdownToHtml(markdown) == 'This is just plain text'
+
markdown = '# Title1\n### Title3\n## Title2\n'
assert markdownToHtml(markdown) == \
'Title1 Title3 Title2 '
markdown = \
- 'This is [a link](https://something.somewhere) to something\n' + \
+ 'This is [a link](https://something.somewhere) to something.\n' + \
'And [something else](https://cat.pic).'
assert markdownToHtml(markdown) == \
'This is ' + \
- 'a link to something ' + \
+ 'a link to something. ' + \
'And ' + \
'something else .'
diff --git a/webapp_utils.py b/webapp_utils.py
index 9d144d3b3..4d7c25f8b 100644
--- a/webapp_utils.py
+++ b/webapp_utils.py
@@ -21,9 +21,34 @@ from content import addHtmlTags
from content import replaceEmojiFromTags
+def _markdownEmphasisHtml(markdown: str) -> str:
+ """Add italics and bold html markup to the given markdown
+ """
+ punctuation = ('.', ';', ':')
+ noPunctuation = markdown
+ for ch in punctuation:
+ noPunctuation = noPunctuation.replace(ch, ' ')
+ wordList = noPunctuation.split(' ')
+ replacements = {}
+ for word in wordList:
+ if word.startswith('**') and word.endswith('**'):
+ replacements[word] = \
+ '' + word.replace('*', '') + ' '
+ elif word.startswith('*') and word.endswith('*'):
+ replacements[word] = \
+ '' + word.replace('*', '') + ' '
+ elif word.startswith('_') and word.endswith('_'):
+ replacements[word] = \
+ '' + word.replace('_', '') + ' '
+ for md, html in replacements.items():
+ markdown = markdown.replace(md, html)
+ return markdown
+
+
def markdownToHtml(markdown: str) -> str:
"""Converts markdown formatted text to html
"""
+ markdown = _markdownEmphasisHtml(markdown)
# replace markdown style links with html links
replaceLinks = {}
text = markdown
From 57875659616117619efe9cf1e7be88f140a37942 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 12:17:41 +0000
Subject: [PATCH 0040/1416] Welcome profile screen
---
daemon.py | 27 ++++++++++++++++++++++
defaultwelcome/profile_en.md | 4 ++--
webapp_welcome.py | 27 +++++++++++-----------
webapp_welcome_profile.py | 45 ++++++++++++++++++++++++++++++------
4 files changed, 81 insertions(+), 22 deletions(-)
diff --git a/daemon.py b/daemon.py
index 04abd8e45..dd669485c 100644
--- a/daemon.py
+++ b/daemon.py
@@ -183,6 +183,7 @@ from webapp_hashtagswarm import getHashtagCategoriesFeed
from webapp_hashtagswarm import htmlSearchHashtagCategory
from webapp_welcome import htmlWelcomeScreen
from webapp_welcome import isWelcomeScreenComplete
+from webapp_welcome_profile import htmlWelcomeProfile
from shares import getSharesFeedForPerson
from shares import addShare
from shares import removeShare
@@ -10695,6 +10696,32 @@ class PubServer(BaseHTTPRequestHandler):
else:
self.path = self.path.replace('/welcome', '')
+ if htmlGET and authorized and \
+ '/users/' in self.path and self.path.endswith('/welcome_profile'):
+ nickname = self.path.split('/users/')[1]
+ if '/' in nickname:
+ nickname = nickname.split('/')[0]
+ if not isWelcomeScreenComplete(self.server.baseDir,
+ nickname,
+ self.server.domain):
+ msg = \
+ htmlWelcomeProfile(self.server.baseDir, nickname,
+ self.server.domain,
+ self.server.httpPrefix,
+ self.server.domainFull,
+ self.server.systemLanguage,
+ self.server.translate)
+ msg = msg.encode('utf-8')
+ msglen = len(msg)
+ self._login_headers('text/html', msglen, callingDomain)
+ self._write(msg)
+ self._benchmarkGETtimings(GETstartTime, GETtimings,
+ 'show welcome screen',
+ 'show welcome profile screen')
+ return
+ else:
+ self.path = self.path.replace('/welcome_profile', '')
+
# if not authorized then show the login screen
if htmlGET and self.path != '/login' and \
not self._pathIsImage(self.path) and \
diff --git a/defaultwelcome/profile_en.md b/defaultwelcome/profile_en.md
index 4f00d8ae1..4487c20da 100644
--- a/defaultwelcome/profile_en.md
+++ b/defaultwelcome/profile_en.md
@@ -1,3 +1,3 @@
-# Account Setup
+## Account Setup
-Add your avatar image, name and description. Use a small avatar image (eg. 128x128 pixels) so that it's quick to download.
+Select your avatar image and add your name and description. Use a small avatar image (eg. 128x128 pixels) so that it's quick to download.
diff --git a/webapp_welcome.py b/webapp_welcome.py
index b3acadd31..a7ed00635 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -24,19 +24,20 @@ def isWelcomeScreenComplete(baseDir: str, nickname: str, domain: str) -> bool:
return os.path.isfile(completeFilename)
-def welcomeScreenIsComplete(baseDir: str, nickname: str, domain: str) -> None:
- """Indicates that the welcome screen has been shown for a given account
- """
- accountPath = baseDir + '/accounts/' + nickname + '@' + domain
- if not os.path.isdir(accountPath):
- return
- completeFilename = accountPath + '/.welcome_complete'
- completeFile = open(completeFilename, 'w+')
- if completeFile:
- completeFile.write('\n')
- completeFile.close()
-
-
+# def welcomeScreenIsComplete(baseDir: str,
+# nickname: str, domain: str) -> None:
+# """Indicates that the welcome screen has been shown for a given account
+# """
+# accountPath = baseDir + '/accounts/' + nickname + '@' + domain
+# if not os.path.isdir(accountPath):
+# return
+# completeFilename = accountPath + '/.welcome_complete'
+# completeFile = open(completeFilename, 'w+')
+# if completeFile:
+# completeFile.write('\n')
+# completeFile.close()
+#
+#
def htmlWelcomeScreen(baseDir: str,
language: str, translate: {},
currScreen='welcome',
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index 901fe5555..e0ca34da4 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -8,8 +8,10 @@ __status__ = "Production"
import os
from shutil import copyfile
+from utils import loadJson
from utils import getConfigParam
from utils import getImageExtensions
+from utils import getImageFormats
from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter
from webapp_utils import markdownToHtml
@@ -17,8 +19,7 @@ from webapp_utils import markdownToHtml
def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
httpPrefix: str, domainFull: str,
- language: str, translate: {},
- prevScreen='welcome') -> str:
+ language: str, translate: {}) -> str:
"""Returns the welcome profile screen to set avatar and bio
"""
# set a custom background for the welcome screen
@@ -58,16 +59,46 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
httpPrefix + '://' + domainFull + \
'/users/' + nickname + '/avatar.' + ext
+ imageFormats = getImageFormats()
+ profileForm += \
+ '\n'
profileForm += htmlFooter()
return profileForm
From c62283c60ad402456e5cda824b85e5ed31430738 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 12:24:26 +0000
Subject: [PATCH 0041/1416] Rearrange welcome profile
---
webapp_welcome_profile.py | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index e0ca34da4..2fe237f6d 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -71,6 +71,25 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += 'accept="' + imageFormats + '">\n'
profileForm += '\n'
+
+ actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json'
+ actorJson = loadJson(actorFilename)
+ displayNickname = actorJson['name']
+ profileForm += ' ' + \
+ translate['Nickname'] + ' \n'
+ profileForm += ' \n'
+
+ profileForm += '\n'
+ bioStr = \
+ actorJson['summary'].replace('', '').replace('
', '')
+ profileForm += ' ' + \
+ translate['Your bio'] + ' \n'
+ profileForm += ' ' + bioStr + ' \n'
+
+ profileForm += ' \n'
+
profileForm += '' + profileText + '
\n'
profileForm += ' \n'
profileForm += \
@@ -82,23 +101,6 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += '
\n'
profileForm += '\n'
- actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json'
- actorJson = loadJson(actorFilename)
- displayNickname = actorJson['name']
- profileForm += ' ' + \
- translate['Nickname'] + ' \n'
- profileForm += ' \n'
-
- profileForm += '\n'
- bioStr = \
- actorJson['summary'].replace('', '').replace('
', '')
- profileForm += ' ' + \
- translate['Your bio'] + ' \n'
- profileForm += ' ' + bioStr + ' \n'
-
- profileForm += ' \n'
profileForm += '\n'
profileForm += htmlFooter()
return profileForm
From cf8d8d11399a7a0e8926263894fac13dc6eb5f8f Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 12:29:41 +0000
Subject: [PATCH 0042/1416] Not centered
---
webapp_welcome_profile.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index 2fe237f6d..505187cd2 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -80,7 +80,6 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += ' \n'
- profileForm += '\n'
bioStr = \
actorJson['summary'].replace('', '').replace('
', '')
profileForm += ' ' + \
@@ -88,8 +87,6 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += ' ' + bioStr + ' \n'
- profileForm += ' \n'
-
profileForm += '' + profileText + '
\n'
profileForm += ' \n'
profileForm += \
From d2ad309738d7dc168456691f126309faf077a4a3 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 12:31:52 +0000
Subject: [PATCH 0043/1416] Title at top
---
webapp_welcome_profile.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index 505187cd2..8dfffc9ea 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -60,10 +60,11 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
'/users/' + nickname + '/avatar.' + ext
imageFormats = getImageFormats()
+ profileForm += '' + profileText + '
\n'
profileForm += \
'\n'
+ 'action="/users/' + nickname + '/welcomeprofile">\n'
profileForm += '\n'
profileForm += ' \n'
@@ -87,7 +88,6 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += ' ' + bioStr + ' \n'
- profileForm += '' + profileText + '
\n'
profileForm += ' \n'
profileForm += \
' ' + translate['Next'] + ' \n'
profileForm += '
\n'
- profileForm += ' \n'
profileForm += '\n'
profileForm += htmlFooter()
From 78b574e00e4b6a213e5a756deb5d60dbc5eec58f Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 12:36:06 +0000
Subject: [PATCH 0044/1416] Separate divisions
---
webapp_welcome_profile.py | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index 8dfffc9ea..41d149a66 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -65,17 +65,19 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
'\n'
- profileForm += '\n'
- profileForm += ' \n'
+ profileForm += ' \n'
+ profileForm += ' \n'
- profileForm += ' \n'
-
- profileForm += ' \n'
+ profileForm += ' \n'
+ profileForm += '\n'
actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json'
actorJson = loadJson(actorFilename)
displayNickname = actorJson['name']
+ profileForm += '\n'
profileForm += ' ' + \
translate['Nickname'] + ' \n'
profileForm += ' ' + bioStr + '\n'
+ profileForm += '
\n'
- profileForm += ' \n'
+ profileForm += '
\n'
profileForm += \
' ' + translate['Go Back'] + ' \n'
+ 'name="prevWelcomeScreen">' + translate['Go Back'] + ' '
profileForm += \
' ' + translate['Next'] + ' \n'
- profileForm += '
\n'
+ profileForm += '
\n'
profileForm += ' \n'
profileForm += htmlFooter()
From d96d73a1481fa7bb8084e5004064b432d8c197c2 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 12:42:05 +0000
Subject: [PATCH 0045/1416] Welcome screen css
---
defaultwelcome/profile_en.md | 1 -
theme.py | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/defaultwelcome/profile_en.md b/defaultwelcome/profile_en.md
index 4487c20da..10d1e09e3 100644
--- a/defaultwelcome/profile_en.md
+++ b/defaultwelcome/profile_en.md
@@ -1,3 +1,2 @@
## Account Setup
-
Select your avatar image and add your name and description. Use a small avatar image (eg. 128x128 pixels) so that it's quick to download.
diff --git a/theme.py b/theme.py
index dbf78cf27..64caf6d2f 100644
--- a/theme.py
+++ b/theme.py
@@ -19,7 +19,8 @@ def _getThemeFiles() -> []:
"""
return ('epicyon.css', 'login.css', 'follow.css',
'suspended.css', 'calendar.css', 'blog.css',
- 'options.css', 'search.css', 'links.css')
+ 'options.css', 'search.css', 'links.css',
+ 'welcome.css')
def getThemesList(baseDir: str) -> []:
From 843e4b2d077298173445f714d00c5910b8414a55 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 12:47:03 +0000
Subject: [PATCH 0046/1416] Welcome screen avatar width
---
epicyon-welcome.css | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/epicyon-welcome.css b/epicyon-welcome.css
index 70f984bc4..e70744b25 100644
--- a/epicyon-welcome.css
+++ b/epicyon-welcome.css
@@ -22,6 +22,7 @@
--focus-color: white;
--line-spacing: 130%;
--welcome-logo-width: 20%;
+ --welcome-avatar-width: 40%;
--main-link-color-hover: #bbb;
--rendering: normal;
}
@@ -143,6 +144,10 @@ img.avatar {
padding: 16px;
}
+.container img.welcomeavatar {
+ width: var(--welcome-avatar-width);
+}
+
.container.next {
float: right;
}
From 6df30d02c06192f3a6bfec9ca6097949ec1550a4 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 13:07:55 +0000
Subject: [PATCH 0047/1416] Text box style
---
epicyon-welcome.css | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/epicyon-welcome.css b/epicyon-welcome.css
index e70744b25..0e3594ca7 100644
--- a/epicyon-welcome.css
+++ b/epicyon-welcome.css
@@ -174,7 +174,7 @@ span.psw {
font-size: var(--welcome-font-size);
font-family: Arial, Helvetica, sans-serif;
}
- input[type=text], input[type=password] {
+ input[type=text], input[type=password], textarea {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
@@ -214,7 +214,7 @@ span.psw {
font-size: var(--welcome-font-size-mobile);
font-family: Arial, Helvetica, sans-serif;
}
- input[type=text], input[type=password] {
+ input[type=text], input[type=password], textarea {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
From 938ad6376dd2a6d6164e8a024c20e08fa32ae9fc Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 13:08:18 +0000
Subject: [PATCH 0048/1416] Less height
---
webapp_welcome_profile.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index 41d149a66..8c4a093b5 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -88,7 +88,7 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += ' ' + \
translate['Your bio'] + ' \n'
profileForm += ' ' + bioStr + ' \n'
+ 'style="height:100px">' + bioStr + '\n'
profileForm += '\n'
profileForm += '\n'
From 4a2ecac4f46016be2ef37ec882d6526ee7474fef Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 13:10:03 +0000
Subject: [PATCH 0049/1416] More height
---
webapp_welcome_profile.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index 8c4a093b5..2e41eccee 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -88,7 +88,7 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += ' ' + \
translate['Your bio'] + ' \n'
profileForm += ' ' + bioStr + ' \n'
+ 'style="height:130px">' + bioStr + '\n'
profileForm += '
\n'
profileForm += '\n'
From 3f6beb73c26fece12d137deac89d7e87fb446499 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 13:16:11 +0000
Subject: [PATCH 0050/1416] Button width
---
epicyon-welcome.css | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/epicyon-welcome.css b/epicyon-welcome.css
index 0e3594ca7..39f448057 100644
--- a/epicyon-welcome.css
+++ b/epicyon-welcome.css
@@ -15,6 +15,7 @@
--text-entry-foreground: #ccc;
--text-entry-background: #111;
--time-color: #aaa;
+ --welcome-button-width: 10ch;
--button-text: #FFFFFF;
--button-background: #999;
--button-selected: #666;
@@ -112,7 +113,7 @@ button {
margin: 8px 0;
border: none;
cursor: pointer;
- width: 100%;
+ width: var(--welcome-button-width);
font-size: var(--welcome-font-size);
font-family: Arial, Helvetica, sans-serif;
}
@@ -191,7 +192,7 @@ span.psw {
margin: 8px 0;
border: none;
cursor: pointer;
- width: 100%;
+ width: var(--welcome-button-width);
font-size: var(--welcome-font-size);
font-family: Arial, Helvetica, sans-serif;
}
@@ -231,7 +232,7 @@ span.psw {
margin: 8px 0;
border: none;
cursor: pointer;
- width: 100%;
+ width: var(--welcome-button-width);
font-size: var(--welcome-font-size-mobile);
font-family: Arial, Helvetica, sans-serif;
}
From f59b5f48d71363f8bbf2babecf8bb0cba1fda863 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 13:26:09 +0000
Subject: [PATCH 0051/1416] Preview button
---
translations/ar.json | 3 ++-
translations/ca.json | 3 ++-
translations/cy.json | 3 ++-
translations/de.json | 3 ++-
translations/en.json | 3 ++-
translations/es.json | 3 ++-
translations/fr.json | 3 ++-
translations/ga.json | 3 ++-
translations/hi.json | 3 ++-
translations/it.json | 3 ++-
translations/ja.json | 3 ++-
translations/oc.json | 3 ++-
translations/pt.json | 3 ++-
translations/ru.json | 3 ++-
translations/zh.json | 3 ++-
webapp_welcome_profile.py | 10 ++++++++--
16 files changed, 38 insertions(+), 17 deletions(-)
diff --git a/translations/ar.json b/translations/ar.json
index 41410f8b1..5ced3e7f3 100644
--- a/translations/ar.json
+++ b/translations/ar.json
@@ -372,5 +372,6 @@
"Broch mode": "وضع الكتيب",
"Pixel": "بكسل",
"DM bounce": "يتم قبول الرسائل فقط من الحسابات المتبعة",
- "Next": "التالي"
+ "Next": "التالي",
+ "Preview": "معاينة"
}
diff --git a/translations/ca.json b/translations/ca.json
index 7bfdfc584..289209daa 100644
--- a/translations/ca.json
+++ b/translations/ca.json
@@ -372,5 +372,6 @@
"Broch mode": "Mode Broch",
"Pixel": "Pixel",
"DM bounce": "Els missatges només s’accepten des dels comptes seguits",
- "Next": "Pròxim"
+ "Next": "Pròxim",
+ "Preview": "Vista prèvia"
}
diff --git a/translations/cy.json b/translations/cy.json
index e10b5049f..e113a37ae 100644
--- a/translations/cy.json
+++ b/translations/cy.json
@@ -372,5 +372,6 @@
"Broch mode": "Modd Broch",
"Pixel": "Pixel",
"DM bounce": "Dim ond o gyfrifon a ddilynir y derbynnir negeseuon",
- "Next": "Nesaf"
+ "Next": "Nesaf",
+ "Preview": "Rhagolwg"
}
diff --git a/translations/de.json b/translations/de.json
index e280a2e19..6b5cfd4a8 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -372,5 +372,6 @@
"Broch mode": "Broch-Modus",
"Pixel": "Pixel",
"DM bounce": "Nachrichten werden nur von folgenden Konten akzeptiert",
- "Next": "Nächster"
+ "Next": "Nächster",
+ "Preview": "Vorschau"
}
diff --git a/translations/en.json b/translations/en.json
index b34511781..a80f3da5f 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -372,5 +372,6 @@
"Broch mode": "Broch mode",
"Pixel": "Pixel",
"DM bounce": "Messages are only accepted from followed accounts",
- "Next": "Next"
+ "Next": "Next",
+ "Preview": "Preview"
}
diff --git a/translations/es.json b/translations/es.json
index c4094c7fb..a18c27d52 100644
--- a/translations/es.json
+++ b/translations/es.json
@@ -372,5 +372,6 @@
"Broch mode": "Modo broche",
"Pixel": "Pixel",
"DM bounce": "Solo se aceptan mensajes de cuentas seguidas",
- "Next": "Próxima"
+ "Next": "Próxima",
+ "Preview": "Avance"
}
diff --git a/translations/fr.json b/translations/fr.json
index 067e9c7ac..e0a42b4c2 100644
--- a/translations/fr.json
+++ b/translations/fr.json
@@ -372,5 +372,6 @@
"Broch mode": "Mode Broch",
"Pixel": "Pixel",
"DM bounce": "Les messages ne sont acceptés que des comptes suivis",
- "Next": "Suivante"
+ "Next": "Suivante",
+ "Preview": "Aperçu"
}
diff --git a/translations/ga.json b/translations/ga.json
index e90397fdc..f459bc1b0 100644
--- a/translations/ga.json
+++ b/translations/ga.json
@@ -372,5 +372,6 @@
"Broch mode": "Modh broch",
"Pixel": "Pixel",
"DM bounce": "Ní ghlactar le teachtaireachtaí ach ó chuntais a leanann",
- "Next": "Ar Aghaidh"
+ "Next": "Ar Aghaidh",
+ "Preview": "Réamhamharc"
}
diff --git a/translations/hi.json b/translations/hi.json
index fbc481e8f..13e65d5f3 100644
--- a/translations/hi.json
+++ b/translations/hi.json
@@ -372,5 +372,6 @@
"Broch mode": "ब्रोच मोड",
"Pixel": "पिक्सेल",
"DM bounce": "संदेश केवल अनुसरण किए गए खातों से स्वीकार किए जाते हैं",
- "Next": "अगला"
+ "Next": "अगला",
+ "Preview": "पूर्वावलोकन"
}
diff --git a/translations/it.json b/translations/it.json
index ba842eca6..8446396c8 100644
--- a/translations/it.json
+++ b/translations/it.json
@@ -372,5 +372,6 @@
"Broch mode": "Modalità Broch",
"Pixel": "Pixel",
"DM bounce": "I messaggi sono accettati solo dagli account seguiti",
- "Next": "Il prossimo"
+ "Next": "Il prossimo",
+ "Preview": "Anteprima"
}
diff --git a/translations/ja.json b/translations/ja.json
index c4c4d8223..f8ee10565 100644
--- a/translations/ja.json
+++ b/translations/ja.json
@@ -372,5 +372,6 @@
"Broch mode": "ブロッホモード",
"Pixel": "ピクセル",
"DM bounce": "メッセージはフォローされているアカウントからのみ受け付けられます",
- "Next": "次"
+ "Next": "次",
+ "Preview": "プレビュー"
}
diff --git a/translations/oc.json b/translations/oc.json
index a271ce5ec..e597567f2 100644
--- a/translations/oc.json
+++ b/translations/oc.json
@@ -368,5 +368,6 @@
"Broch mode": "Broch mode",
"Pixel": "Pixel",
"DM bounce": "Messages are only accepted from followed accounts",
- "Next": "Next"
+ "Next": "Next",
+ "Preview": "Preview"
}
diff --git a/translations/pt.json b/translations/pt.json
index 4ccf54d6c..10e0bcd8b 100644
--- a/translations/pt.json
+++ b/translations/pt.json
@@ -372,5 +372,6 @@
"Broch mode": "Modo broch",
"Pixel": "Pixel",
"DM bounce": "Mensagens são aceitas apenas de contas seguidas",
- "Next": "Próxima"
+ "Next": "Próxima",
+ "Preview": "Antevisão"
}
diff --git a/translations/ru.json b/translations/ru.json
index f845a384d..bf1f5129b 100644
--- a/translations/ru.json
+++ b/translations/ru.json
@@ -372,5 +372,6 @@
"Broch mode": "Брош режим",
"Pixel": "Пиксель",
"DM bounce": "Сообщения принимаются только от следующих аккаунтов",
- "Next": "Следующий"
+ "Next": "Следующий",
+ "Preview": "Предварительный просмотр"
}
diff --git a/translations/zh.json b/translations/zh.json
index 0e0b33e8c..9b09b3300 100644
--- a/translations/zh.json
+++ b/translations/zh.json
@@ -372,5 +372,6 @@
"Broch mode": "断点模式",
"Pixel": "像素点",
"DM bounce": "仅接受来自后续帐户的邮件",
- "Next": "下一个"
+ "Next": "下一个",
+ "Preview": "预览"
}
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index 2e41eccee..ede490da4 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -60,11 +60,11 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
'/users/' + nickname + '/avatar.' + ext
imageFormats = getImageFormats()
- profileForm += '' + profileText + '
\n'
+ profileForm += '' + profileText + '
\n'
profileForm += \
'\n'
+ 'action="/users/' + nickname + '/welcomeprofile">\n'
profileForm += '\n'
profileForm += '
\n'
profileForm += ' ' + translate['Preview'] + ' '
+ profileForm += ' \n'
+
actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json'
actorJson = loadJson(actorFilename)
displayNickname = actorJson['name']
From 4545145a9ca6086c2399d39b2c1ba6ad4c458bf1 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 14:53:19 +0000
Subject: [PATCH 0052/1416] Debug for welcome buttons
---
daemon.py | 14 ++++++++++++++
webapp_welcome_profile.py | 2 +-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/daemon.py b/daemon.py
index dd669485c..deeebcec1 100644
--- a/daemon.py
+++ b/daemon.py
@@ -5006,6 +5006,20 @@ class PubServer(BaseHTTPRequestHandler):
self._postToOutbox(updateActorJson,
__version__, nickname)
+ # preview avatar button on welcome profile screen
+ if fields.get('previewAvatar'):
+ print('previewAvatar: ' + str(fields['previewAvatar']))
+
+ # prev button on welcome profile screen
+ if fields.get('prevWelcomeScreen'):
+ print('prevWelcomeScreen: ' +
+ str(fields['prevWelcomeScreen']))
+
+ # next button on welcome profile screen
+ if fields.get('nextWelcomeScreen'):
+ print('nextWelcomeScreen: ' +
+ str(fields['nextWelcomeScreen']))
+
# deactivate the account
if fields.get('deactivateThisAccount'):
if fields['deactivateThisAccount'] == 'on':
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index ede490da4..b5c04827f 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -64,7 +64,7 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += \
'\n'
+ 'action="/users/' + nickname + '/profiledata">\n'
profileForm += '\n'
profileForm += '
\n'
profileForm += ' bool:
return os.path.isfile(completeFilename)
-# def welcomeScreenIsComplete(baseDir: str,
-# nickname: str, domain: str) -> None:
-# """Indicates that the welcome screen has been shown for a given account
-# """
-# accountPath = baseDir + '/accounts/' + nickname + '@' + domain
-# if not os.path.isdir(accountPath):
-# return
-# completeFilename = accountPath + '/.welcome_complete'
-# completeFile = open(completeFilename, 'w+')
-# if completeFile:
-# completeFile.write('\n')
-# completeFile.close()
-#
-#
+def welcomeScreenIsComplete(baseDir: str,
+ nickname: str, domain: str) -> None:
+ """Indicates that the welcome screen has been shown for a given account
+ """
+ accountPath = baseDir + '/accounts/' + nickname + '@' + domain
+ if not os.path.isdir(accountPath):
+ return
+ completeFilename = accountPath + '/.welcome_complete'
+ completeFile = open(completeFilename, 'w+')
+ if completeFile:
+ completeFile.write('\n')
+ completeFile.close()
+
+
def htmlWelcomeScreen(baseDir: str,
language: str, translate: {},
currScreen='welcome',
diff --git a/webapp_welcome_final.py b/webapp_welcome_final.py
new file mode 100644
index 000000000..2e3f6f293
--- /dev/null
+++ b/webapp_welcome_final.py
@@ -0,0 +1,65 @@
+__filename__ = "webapp_welcome_final.py"
+__author__ = "Bob Mottram"
+__license__ = "AGPL3+"
+__version__ = "1.2.0"
+__maintainer__ = "Bob Mottram"
+__email__ = "bob@freedombone.net"
+__status__ = "Production"
+
+import os
+from shutil import copyfile
+from utils import getConfigParam
+from webapp_utils import htmlHeaderWithExternalStyle
+from webapp_utils import htmlFooter
+from webapp_utils import markdownToHtml
+
+
+def htmlWelcomeFinal(baseDir: str, nickname: str, domain: str,
+ httpPrefix: str, domainFull: str,
+ language: str, translate: {}) -> str:
+ """Returns the final welcome screen after first login
+ """
+ # set a custom background for the welcome screen
+ if os.path.isfile(baseDir + '/accounts/welcome-background-custom.jpg'):
+ if not os.path.isfile(baseDir + '/accounts/welcome-background.jpg'):
+ copyfile(baseDir + '/accounts/welcome-background-custom.jpg',
+ baseDir + '/accounts/welcome-background.jpg')
+
+ finalText = 'Welcome to Epicyon'
+ finalFilename = baseDir + '/accounts/welcome_final.md'
+ if not os.path.isfile(finalFilename):
+ defaultFilename = \
+ baseDir + '/defaultwelcome/final_' + language + '.md'
+ if not os.path.isfile(defaultFilename):
+ defaultFilename = baseDir + '/defaultwelcome/final_en.md'
+ copyfile(defaultFilename, finalFilename)
+ if os.path.isfile(finalFilename):
+ with open(finalFilename, 'r') as finalFile:
+ finalText = markdownToHtml(finalFile.read())
+
+ finalForm = ''
+ cssFilename = baseDir + '/epicyon-welcome.css'
+ if os.path.isfile(baseDir + '/welcome.css'):
+ cssFilename = baseDir + '/welcome.css'
+
+ instanceTitle = \
+ getConfigParam(baseDir, 'instanceTitle')
+ finalForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
+
+ finalForm += '' + finalText + '
\n'
+ finalForm += \
+ '\n'
+ finalForm += '\n'
+ finalForm += \
+ ' ' + translate['Go Back'] + ' \n'
+ finalForm += \
+ ' ' + translate['Next'] + ' \n'
+ finalForm += '
\n'
+
+ finalForm += ' \n'
+ finalForm += htmlFooter()
+ return finalForm
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index b5c04827f..b84b474db 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -100,10 +100,10 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
profileForm += '\n'
profileForm += \
' ' + translate['Go Back'] + ' '
+ 'name="initialWelcomeScreen">' + translate['Go Back'] + ' '
profileForm += \
' ' + translate['Next'] + ' \n'
+ 'name="finalWelcomeScreen">' + translate['Next'] + '\n'
profileForm += '
\n'
profileForm += '\n'
From 21b8e246d1eacc901452913cf4b356231c5872d8 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 16:59:26 +0000
Subject: [PATCH 0058/1416] Remove line
---
defaultwelcome/welcome_en.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/defaultwelcome/welcome_en.md b/defaultwelcome/welcome_en.md
index e05bb2c04..2a90b3a52 100644
--- a/defaultwelcome/welcome_en.md
+++ b/defaultwelcome/welcome_en.md
@@ -1,5 +1,4 @@
# Welcome
-
Epicyon is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops.
Run your own social network presence the way you want to, and say goodbye to Big Tech.
From efedbffc3cd6b4a9452592f78da03c3191a5dca0 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 17:06:07 +0000
Subject: [PATCH 0059/1416] Next button on initial welcome screen
---
daemon.py | 2 +-
webapp_welcome.py | 22 ++++++++++------------
2 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/daemon.py b/daemon.py
index 78b6ca0bb..bbe7f63b2 100644
--- a/daemon.py
+++ b/daemon.py
@@ -10711,7 +10711,7 @@ class PubServer(BaseHTTPRequestHandler):
nickname,
self.server.domain):
msg = \
- htmlWelcomeScreen(self.server.baseDir,
+ htmlWelcomeScreen(self.server.baseDir, nickname,
self.server.systemLanguage,
self.server.translate)
msg = msg.encode('utf-8')
diff --git a/webapp_welcome.py b/webapp_welcome.py
index f041e5a64..e623b3242 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -38,10 +38,9 @@ def welcomeScreenIsComplete(baseDir: str,
completeFile.close()
-def htmlWelcomeScreen(baseDir: str,
+def htmlWelcomeScreen(baseDir: str, nickname: str,
language: str, translate: {},
- currScreen='welcome',
- nextScreen=None, prevScreen=None) -> str:
+ currScreen='welcome') -> str:
"""Returns the welcome screen
"""
# set a custom background for the welcome screen
@@ -50,9 +49,6 @@ def htmlWelcomeScreen(baseDir: str,
copyfile(baseDir + '/accounts/welcome-background-custom.jpg',
baseDir + '/accounts/welcome-background.jpg')
- if not nextScreen:
- nextScreen = 'welcome_profile'
-
welcomeText = 'Welcome to Epicyon'
welcomeFilename = baseDir + '/accounts/' + currScreen + '.md'
if not os.path.isfile(welcomeFilename):
@@ -74,15 +70,17 @@ def htmlWelcomeScreen(baseDir: str,
instanceTitle = \
getConfigParam(baseDir, 'instanceTitle')
welcomeForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
+ welcomeForm += \
+ '\n'
welcomeForm += '' + welcomeText + '
\n'
welcomeForm += ' \n'
welcomeForm += ' \n'
+ welcomeForm += ' \n'
welcomeForm += htmlFooter()
return welcomeForm
From a0469db654e99335b306d8453b123aa63dcb7f76 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 17:19:22 +0000
Subject: [PATCH 0060/1416] Avoid erasing bio
---
daemon.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/daemon.py b/daemon.py
index bbe7f63b2..c215c8c89 100644
--- a/daemon.py
+++ b/daemon.py
@@ -4566,9 +4566,10 @@ class PubServer(BaseHTTPRequestHandler):
else:
if checkNameAndBio:
redirectPath = 'previewAvatar'
- if actorJson['summary']:
- actorJson['summary'] = ''
- actorChanged = True
+ else:
+ if actorJson['summary']:
+ actorJson['summary'] = ''
+ actorChanged = True
adminNickname = \
getConfigParam(baseDir, 'admin')
From 4b584f66483519b43643c1e5982e384439c3d032 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 17:20:48 +0000
Subject: [PATCH 0061/1416] Don't remove bio
---
daemon.py | 4 ----
1 file changed, 4 deletions(-)
diff --git a/daemon.py b/daemon.py
index c215c8c89..b5349c621 100644
--- a/daemon.py
+++ b/daemon.py
@@ -4566,10 +4566,6 @@ class PubServer(BaseHTTPRequestHandler):
else:
if checkNameAndBio:
redirectPath = 'previewAvatar'
- else:
- if actorJson['summary']:
- actorJson['summary'] = ''
- actorChanged = True
adminNickname = \
getConfigParam(baseDir, 'admin')
From 377b6a9be313b6a51808ad20a6cbaee135964396 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 17:57:15 +0000
Subject: [PATCH 0062/1416] Fix markdown emphasis
---
defaultwelcome/final_en.md | 1 -
webapp_utils.py | 53 ++++++++++++++++++++++++++------------
2 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/defaultwelcome/final_en.md b/defaultwelcome/final_en.md
index fdfaf801b..ef9eb2601 100644
--- a/defaultwelcome/final_en.md
+++ b/defaultwelcome/final_en.md
@@ -2,7 +2,6 @@
You are now ready to begin using Epicyon. This is a moderated social space, so please make sure to abide by our [terms of service](/terms), and have fun.
### Hints
-
Use the **magnifier** icon 🔍 to search for fediverse handles and follow people.
Selecting the **banner at the top** of the screen switches between timeline view and your profile.
diff --git a/webapp_utils.py b/webapp_utils.py
index 4d7c25f8b..5c3983bc2 100644
--- a/webapp_utils.py
+++ b/webapp_utils.py
@@ -24,24 +24,45 @@ from content import replaceEmojiFromTags
def _markdownEmphasisHtml(markdown: str) -> str:
"""Add italics and bold html markup to the given markdown
"""
- punctuation = ('.', ';', ':')
- noPunctuation = markdown
- for ch in punctuation:
- noPunctuation = noPunctuation.replace(ch, ' ')
- wordList = noPunctuation.split(' ')
- replacements = {}
- for word in wordList:
- if word.startswith('**') and word.endswith('**'):
- replacements[word] = \
- '' + word.replace('*', '') + ' '
- elif word.startswith('*') and word.endswith('*'):
- replacements[word] = \
- '' + word.replace('*', '') + ' '
- elif word.startswith('_') and word.endswith('_'):
- replacements[word] = \
- '' + word.replace('_', '') + ' '
+ replacements = {
+ ' **': ' ',
+ '** ': ' ',
+ '**.': '.',
+ '**:': ':',
+ '**;': ';',
+ '**,': ',',
+ '**\n': '\n',
+ ' *': ' ',
+ '* ': ' ',
+ '*.': '.',
+ '*:': ':',
+ '*;': ';',
+ '*,': ',',
+ '*\n': '\n',
+ ' _': ' ',
+ '_.': '.',
+ '_:': ':',
+ '_;': ';',
+ '_,': ',',
+ '_\n': '\n'
+ }
for md, html in replacements.items():
markdown = markdown.replace(md, html)
+
+ if markdown.startswith('**'):
+ markdown = markdown[2:] + ''
+ elif markdown.startswith('*'):
+ markdown = markdown[1:] + ''
+ elif markdown.startswith('_'):
+ markdown = markdown[1:] + ''
+
+ if markdown.endswith('**'):
+ markdown = markdown[:len(markdown) - 2] + ' '
+ elif markdown.endswith('*'):
+ markdown = markdown[:len(markdown) - 1] + ''
+ elif markdown.endswith('_'):
+ markdown = markdown[:len(markdown) - 1] + ''
return markdown
From e5f4807a6dee865d0913a3787669d496bf815444 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 18:10:43 +0000
Subject: [PATCH 0063/1416] Theme colors for welcome screens
---
epicyon-welcome.css | 2 +-
theme/blue/theme.json | 1 +
theme/debian/theme.json | 3 +++
theme/hacker/theme.json | 2 ++
theme/henge/theme.json | 2 ++
theme/indymediaclassic/theme.json | 6 +++++-
theme/indymediamodern/theme.json | 4 ++++
theme/lcd/theme.json | 2 ++
theme/light/theme.json | 2 ++
theme/night/theme.json | 2 ++
theme/pixel/theme.json | 2 ++
theme/purple/theme.json | 2 ++
theme/rc3/theme.json | 4 ++++
theme/solidaric/theme.json | 2 ++
theme/starlight/theme.json | 2 ++
theme/zen/theme.json | 1 +
16 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/epicyon-welcome.css b/epicyon-welcome.css
index 39f448057..21a2ec8a1 100644
--- a/epicyon-welcome.css
+++ b/epicyon-welcome.css
@@ -15,7 +15,7 @@
--text-entry-foreground: #ccc;
--text-entry-background: #111;
--time-color: #aaa;
- --welcome-button-width: 10ch;
+ --welcome-button-width: 12ch;
--button-text: #FFFFFF;
--button-background: #999;
--button-selected: #666;
diff --git a/theme/blue/theme.json b/theme/blue/theme.json
index 2abaf6666..39bb7effd 100644
--- a/theme/blue/theme.json
+++ b/theme/blue/theme.json
@@ -18,6 +18,7 @@
"gallery-font-size-mobile": "55px",
"main-bg-color": "#002365",
"login-bg-color": "#002365",
+ "welcome-bg-color": "#002365",
"options-bg-color": "#002365",
"post-bg-color": "#002365",
"timeline-posts-background-color": "#002365",
diff --git a/theme/debian/theme.json b/theme/debian/theme.json
index 225bf948c..a494551b9 100644
--- a/theme/debian/theme.json
+++ b/theme/debian/theme.json
@@ -9,6 +9,7 @@
"button-selected-highlighted": "#2b5c6d",
"button-approve": "#2b5c6d",
"login-button-color": "#2b5c6d",
+ "welcome-button-color": "#2b5c6d",
"button-event-background-color": "#2b5c6d",
"post-separator-margin-top": "10px",
"post-separator-margin-bottom": "10px",
@@ -42,6 +43,7 @@
"column-left-color": "#e6ebf0",
"main-bg-color": "#e6ebf0",
"login-bg-color": "#010026",
+ "welcome-bg-color": "#010026",
"options-bg-color": "#010026",
"post-bg-color": "#e6ebf0",
"timeline-posts-background-color": "#e6ebf0",
@@ -54,6 +56,7 @@
"cw-color": "#2d2c37",
"main-fg-color": "#2d2c37",
"login-fg-color": "white",
+ "welcome-fg-color": "white",
"options-fg-color": "lightgrey",
"column-left-fg-color": "#2d2c37",
"border-color": "#c0cdd9",
diff --git a/theme/hacker/theme.json b/theme/hacker/theme.json
index a33b48b7b..b4ceed266 100644
--- a/theme/hacker/theme.json
+++ b/theme/hacker/theme.json
@@ -7,6 +7,7 @@
"focus-color": "green",
"main-bg-color": "black",
"login-bg-color": "black",
+ "welcome-bg-color": "black",
"options-bg-color": "black",
"post-bg-color": "black",
"timeline-posts-background-color": "black",
@@ -20,6 +21,7 @@
"cw-color": "#00ff00",
"main-fg-color": "#00ff00",
"login-fg-color": "#00ff00",
+ "welcome-fg-color": "#00ff00",
"options-fg-color": "#00ff00",
"column-left-fg-color": "#00ff00",
"border-color": "#035103",
diff --git a/theme/henge/theme.json b/theme/henge/theme.json
index 0048d7b0d..4f6fce492 100644
--- a/theme/henge/theme.json
+++ b/theme/henge/theme.json
@@ -4,7 +4,9 @@
"time-color": "grey",
"event-color": "white",
"login-bg-color": "#567726",
+ "welcome-bg-color": "#567726",
"login-fg-color": "black",
+ "welcome-fg-color": "black",
"options-bg-color": "black",
"newswire-publish-icon": "True",
"full-width-timeline-buttons": "False",
diff --git a/theme/indymediaclassic/theme.json b/theme/indymediaclassic/theme.json
index 80d9c6eff..1605d885b 100644
--- a/theme/indymediaclassic/theme.json
+++ b/theme/indymediaclassic/theme.json
@@ -28,6 +28,7 @@
"font-size5": "22px",
"main-bg-color": "black",
"login-bg-color": "black",
+ "welcome-bg-color": "black",
"options-bg-color": "black",
"post-bg-color": "black",
"timeline-posts-background-color": "black",
@@ -47,6 +48,7 @@
"cw-color": "white",
"main-fg-color": "white",
"login-fg-color": "white",
+ "welcome-fg-color": "white",
"options-fg-color": "white",
"column-left-fg-color": "white",
"main-bg-color-dm": "#0b0a0a",
@@ -80,5 +82,7 @@
"column-right-width": "20vw",
"column-right-icon-size": "11%",
"login-button-color": "red",
- "login-button-fg-color": "white"
+ "welcome-button-color": "red",
+ "login-button-fg-color": "white",
+ "welcome-button-fg-color": "white"
}
diff --git a/theme/indymediamodern/theme.json b/theme/indymediamodern/theme.json
index 8f9d41143..88884f3bf 100644
--- a/theme/indymediamodern/theme.json
+++ b/theme/indymediamodern/theme.json
@@ -64,7 +64,9 @@
"tab-border-color": "transparent",
"button-corner-radius": "0px",
"login-button-color": "#25408f",
+ "welcome-button-color": "#25408f",
"login-button-fg-color": "white",
+ "welcome-button-fg-color": "white",
"column-left-width": "10vw",
"column-center-width": "75vw",
"column-right-width": "15vw",
@@ -91,6 +93,7 @@
"column-left-color": "#efefef",
"main-bg-color": "#efefef",
"login-bg-color": "#efefef",
+ "welcome-bg-color": "#efefef",
"options-bg-color": "#efefef",
"post-bg-color": "white",
"timeline-posts-background-color": "white",
@@ -102,6 +105,7 @@
"cw-color": "black",
"main-fg-color": "black",
"login-fg-color": "black",
+ "welcome-fg-color": "black",
"options-fg-color": "black",
"column-left-fg-color": "#25408f",
"border-color": "#c0cdd9",
diff --git a/theme/lcd/theme.json b/theme/lcd/theme.json
index 8f80f567e..457d0bf61 100644
--- a/theme/lcd/theme.json
+++ b/theme/lcd/theme.json
@@ -9,6 +9,7 @@
"column-left-header-color": "#33390d",
"main-bg-color": "#9fb42b",
"login-bg-color": "#9fb42b",
+ "welcome-bg-color": "#9fb42b",
"options-bg-color": "#9fb42b",
"post-bg-color": "#9fb42b",
"timeline-posts-background-color": "#9fb42b",
@@ -25,6 +26,7 @@
"cw-color": "#33390d",
"main-fg-color": "#33390d",
"login-fg-color": "#33390d",
+ "welcome-fg-color": "#33390d",
"options-fg-color": "#33390d",
"border-color": "#33390d",
"border-width": "5px",
diff --git a/theme/light/theme.json b/theme/light/theme.json
index 586a04bcd..836b0c2be 100644
--- a/theme/light/theme.json
+++ b/theme/light/theme.json
@@ -27,6 +27,7 @@
"column-left-color": "#e6ebf0",
"main-bg-color": "#e6ebf0",
"login-bg-color": "#e6ebf0",
+ "welcome-bg-color": "#e6ebf0",
"options-bg-color": "#e6ebf0",
"post-bg-color": "#e6ebf0",
"timeline-posts-background-color": "#e6ebf0",
@@ -39,6 +40,7 @@
"cw-color": "#777",
"main-fg-color": "#2d2c37",
"login-fg-color": "#2d2c37",
+ "welcome-fg-color": "#2d2c37",
"options-fg-color": "#2d2c37",
"column-left-fg-color": "#2d2c37",
"border-color": "#c0cdd9",
diff --git a/theme/night/theme.json b/theme/night/theme.json
index f29c4cd12..d7ebe9bb0 100644
--- a/theme/night/theme.json
+++ b/theme/night/theme.json
@@ -22,6 +22,7 @@
"font-size5": "22px",
"main-bg-color": "#0f0d10",
"login-bg-color": "#0f0d10",
+ "welcome-bg-color": "#0f0d10",
"options-bg-color": "#0f0d10",
"post-bg-color": "#0f0d10",
"timeline-posts-background-color": "#0f0d10",
@@ -36,6 +37,7 @@
"cw-color": "#0481f5",
"main-fg-color": "#0481f5",
"login-fg-color": "#0481f5",
+ "welcome-fg-color": "#0481f5",
"options-fg-color": "#0481f5",
"column-left-fg-color": "#0481f5",
"main-bg-color-dm": "#0b0a0a",
diff --git a/theme/pixel/theme.json b/theme/pixel/theme.json
index d51e87316..0aec8c372 100644
--- a/theme/pixel/theme.json
+++ b/theme/pixel/theme.json
@@ -34,6 +34,7 @@
"button-approve": "#12435f",
"border-color": "#7152a3",
"login-fg-color": "black",
+ "welcome-fg-color": "black",
"cw-color": "black",
"main-link-color": "#333",
"options-main-link-color": "#333",
@@ -44,6 +45,7 @@
"dropdown-bg-color": "#8ba0d4",
"dropdown-bg-color-hover": "#7ba0d4",
"login-bg-color": "#9ba0d4",
+ "welcome-bg-color": "#9ba0d4",
"text-entry-background": "#8ba0d4",
"timeline-posts-background-color": "#9ba0d4",
"header-bg-color": "#9ba0d4",
diff --git a/theme/purple/theme.json b/theme/purple/theme.json
index 3a1e8582d..66b17a17c 100644
--- a/theme/purple/theme.json
+++ b/theme/purple/theme.json
@@ -21,6 +21,7 @@
"font-size5": "22px",
"main-bg-color": "#1f152d",
"login-bg-color": "#1f152d",
+ "welcome-bg-color": "#1f152d",
"options-bg-color": "#1f152d",
"post-bg-color": "#1f152d",
"timeline-posts-background-color": "#1f152d",
@@ -33,6 +34,7 @@
"cw-color": "#f98bb0",
"main-fg-color": "#f98bb0",
"login-fg-color": "#f98bb0",
+ "welcome-fg-color": "#f98bb0",
"options-fg-color": "#f98bb0",
"column-left-fg-color": "#f98bb0",
"border-color": "#3f2145",
diff --git a/theme/rc3/theme.json b/theme/rc3/theme.json
index 95b54d546..e41930aec 100644
--- a/theme/rc3/theme.json
+++ b/theme/rc3/theme.json
@@ -12,7 +12,9 @@
"button-selected-highlighted": "#0481f5",
"button-fg-highlighted": "white",
"login-button-color": "#6800e7",
+ "welcome-button-color": "#6800e7",
"login-button-fg-color": "white",
+ "welcome-button-fg-color": "white",
"verticals-width": "16px",
"tab-border-color": "#6800e7",
"timeline-border-radius": "0",
@@ -43,6 +45,7 @@
"font-size-likes": "10px",
"main-bg-color": "#100e23",
"login-bg-color": "#100e23",
+ "welcome-bg-color": "#100e23",
"options-bg-color": "#100e23",
"post-bg-color": "#100e23",
"timeline-posts-background-color": "#100e23",
@@ -57,6 +60,7 @@
"cw-color": "white",
"main-fg-color": "white",
"login-fg-color": "white",
+ "welcome-fg-color": "white",
"options-fg-color": "white",
"title-color": "white",
"column-left-fg-color": "#05b9ec",
diff --git a/theme/solidaric/theme.json b/theme/solidaric/theme.json
index e3e46b6ff..cdb9c08c3 100644
--- a/theme/solidaric/theme.json
+++ b/theme/solidaric/theme.json
@@ -35,6 +35,7 @@
"rgba(0, 0, 0, 0.5)": "rgba(0, 0, 0, 0.0)",
"main-bg-color": "#eeeeee",
"login-bg-color": "#eeeeee",
+ "welcome-bg-color": "#eeeeee",
"options-bg-color": "#eeeeee",
"post-bg-color": "#eeeeee",
"timeline-posts-background-color": "#eeeeee",
@@ -48,6 +49,7 @@
"cw-color": "#2d2c37",
"main-fg-color": "#2d2c37",
"login-fg-color": "#2d2c37",
+ "welcome-fg-color": "#2d2c37",
"options-fg-color": "#2d2c37",
"column-left-fg-color": "#2d2c37",
"border-color": "#c0cdd9",
diff --git a/theme/starlight/theme.json b/theme/starlight/theme.json
index 1be4c4002..f91141886 100644
--- a/theme/starlight/theme.json
+++ b/theme/starlight/theme.json
@@ -19,6 +19,7 @@
"font-size5": "22px",
"main-bg-color": "#0f0d10",
"login-bg-color": "#0f0d10",
+ "welcome-bg-color": "#0f0d10",
"options-bg-color": "#0f0d10",
"post-bg-color": "#0f0d10",
"timeline-posts-background-color": "#0f0d10",
@@ -36,6 +37,7 @@
"cw-color": "#ffc4bc",
"main-fg-color": "#ffc4bc",
"login-fg-color": "#ffc4bc",
+ "welcome-fg-color": "#ffc4bc",
"options-fg-color": "#ffc4bc",
"column-left-fg-color": "#ffc4bc",
"main-bg-color-dm": "#0b0a0a",
diff --git a/theme/zen/theme.json b/theme/zen/theme.json
index 03b743247..7eb3b5d86 100644
--- a/theme/zen/theme.json
+++ b/theme/zen/theme.json
@@ -6,6 +6,7 @@
"button-text": "#d5c7b7",
"button-selected-text": "#d5c7b7",
"login-bg-color": "#212e3f",
+ "welcome-bg-color": "#212e3f",
"lines-color": "#b6a188",
"day-number": "black",
"day-number2": "#bbb",
From c63912ed05e933d417537d82e9652e72fdd47198 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 18:25:41 +0000
Subject: [PATCH 0064/1416] Redirect to login screen
---
daemon.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/daemon.py b/daemon.py
index b5349c621..5df1ced52 100644
--- a/daemon.py
+++ b/daemon.py
@@ -10373,6 +10373,18 @@ class PubServer(BaseHTTPRequestHandler):
if '/users/' in self.path:
usersInPath = True
+ # redirect to the welcome screen
+ if htmlGET and authorized and usersInPath:
+ nickname = self.path.split('/users/')[1]
+ if '/' in nickname:
+ nickname = nickname.split('/')[0]
+ if '?' in nickname:
+ nickname = nickname.split('?')[0]
+ if not isWelcomeScreenComplete(self.server.baseDir,
+ nickname,
+ self.server.domain):
+ self.path = '/users/' + nickname + '/welcome'
+
if not htmlGET and \
usersInPath and self.path.endswith('/pinned'):
nickname = self.path.split('/users/')[1]
From 55c6faf20bb344a72bde20b154c3b1ef98c11b93 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 18:29:23 +0000
Subject: [PATCH 0065/1416] Redirect to welcome
---
daemon.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/daemon.py b/daemon.py
index 5df1ced52..eda5f4bed 100644
--- a/daemon.py
+++ b/daemon.py
@@ -10383,7 +10383,9 @@ class PubServer(BaseHTTPRequestHandler):
if not isWelcomeScreenComplete(self.server.baseDir,
nickname,
self.server.domain):
- self.path = '/users/' + nickname + '/welcome'
+ self._redirect_headers('/users/' + nickname + '/welcome',
+ cookie, callingDomain)
+ return
if not htmlGET and \
usersInPath and self.path.endswith('/pinned'):
From 307d386cc3effadf010278a5fc83948d9ccd091b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 18:31:10 +0000
Subject: [PATCH 0066/1416] Avoid circularity
---
daemon.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/daemon.py b/daemon.py
index eda5f4bed..76ed6d7b9 100644
--- a/daemon.py
+++ b/daemon.py
@@ -10374,7 +10374,8 @@ class PubServer(BaseHTTPRequestHandler):
usersInPath = True
# redirect to the welcome screen
- if htmlGET and authorized and usersInPath:
+ if htmlGET and authorized and usersInPath and \
+ not self.path.endswith('/welcome'):
nickname = self.path.split('/users/')[1]
if '/' in nickname:
nickname = nickname.split('/')[0]
From bcc59bac97e22f9a7b8d0d2763c38e3711dd609c Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 18:33:35 +0000
Subject: [PATCH 0067/1416] Extra reserved name
---
daemon.py | 2 +-
utils.py | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/daemon.py b/daemon.py
index 76ed6d7b9..7fd7523cc 100644
--- a/daemon.py
+++ b/daemon.py
@@ -10375,7 +10375,7 @@ class PubServer(BaseHTTPRequestHandler):
# redirect to the welcome screen
if htmlGET and authorized and usersInPath and \
- not self.path.endswith('/welcome'):
+ '/welcome' not in self.path:
nickname = self.path.split('/users/')[1]
if '/' in nickname:
nickname = nickname.split('/')[0]
diff --git a/utils.py b/utils.py
index 8f2348062..25499145e 100644
--- a/utils.py
+++ b/utils.py
@@ -1273,7 +1273,8 @@ def _isReservedName(nickname: str) -> bool:
'likes', 'users', 'statuses', 'tags',
'accounts', 'channels', 'profile', 'u',
'updates', 'repeat', 'announce',
- 'shares', 'fonts', 'icons', 'avatars')
+ 'shares', 'fonts', 'icons', 'avatars',
+ 'welcome')
if nickname in reservedNames:
return True
return False
From 7e9937cbd02c789318ef6f05422dba7a7542ac1a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 18:38:18 +0000
Subject: [PATCH 0068/1416] Check authorized nickname
---
daemon.py | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/daemon.py b/daemon.py
index 7fd7523cc..aef342dd7 100644
--- a/daemon.py
+++ b/daemon.py
@@ -10381,12 +10381,14 @@ class PubServer(BaseHTTPRequestHandler):
nickname = nickname.split('/')[0]
if '?' in nickname:
nickname = nickname.split('?')[0]
- if not isWelcomeScreenComplete(self.server.baseDir,
- nickname,
- self.server.domain):
- self._redirect_headers('/users/' + nickname + '/welcome',
- cookie, callingDomain)
- return
+ if nickname == self.authorizedNickname and \
+ self.path != '/users/' + nickname:
+ if not isWelcomeScreenComplete(self.server.baseDir,
+ nickname,
+ self.server.domain):
+ self._redirect_headers('/users/' + nickname + '/welcome',
+ cookie, callingDomain)
+ return
if not htmlGET and \
usersInPath and self.path.endswith('/pinned'):
From a7e0985ac81fa84159f84e12b36f97fa634f5159 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 19:07:45 +0000
Subject: [PATCH 0069/1416] Themed welcome screen background
---
daemon.py | 12 ++++++------
theme.py | 5 ++++-
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/daemon.py b/daemon.py
index aef342dd7..3008469f4 100644
--- a/daemon.py
+++ b/daemon.py
@@ -10383,12 +10383,12 @@ class PubServer(BaseHTTPRequestHandler):
nickname = nickname.split('?')[0]
if nickname == self.authorizedNickname and \
self.path != '/users/' + nickname:
- if not isWelcomeScreenComplete(self.server.baseDir,
- nickname,
- self.server.domain):
- self._redirect_headers('/users/' + nickname + '/welcome',
- cookie, callingDomain)
- return
+ if not isWelcomeScreenComplete(self.server.baseDir,
+ nickname,
+ self.server.domain):
+ self._redirect_headers('/users/' + nickname + '/welcome',
+ cookie, callingDomain)
+ return
if not htmlGET and \
usersInPath and self.path.endswith('/pinned'):
diff --git a/theme.py b/theme.py
index 64caf6d2f..008d0a7f3 100644
--- a/theme.py
+++ b/theme.py
@@ -265,6 +265,8 @@ def _setThemeFromDict(baseDir: str, name: str,
_setBackgroundFormat(baseDir, name, 'options', bgParams['options'])
if bgParams.get('search'):
_setBackgroundFormat(baseDir, name, 'search', bgParams['search'])
+ if bgParams.get('welcome'):
+ _setBackgroundFormat(baseDir, name, 'welcome', bgParams['welcome'])
def _setBackgroundFormat(baseDir: str, name: str,
@@ -508,7 +510,8 @@ def _setThemeImages(baseDir: str, name: str) -> None:
_setTextModeTheme(baseDir, themeNameLower)
backgroundNames = ('login', 'shares', 'delete', 'follow',
- 'options', 'block', 'search', 'calendar')
+ 'options', 'block', 'search', 'calendar',
+ 'welcome')
extensions = getImageExtensions()
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
From 3c270c39a52f6b82fbbdfede5ef23a7638a2d175 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 19:15:04 +0000
Subject: [PATCH 0070/1416] Remove html from loaded markdown
---
webapp_welcome.py | 3 ++-
webapp_welcome_final.py | 3 ++-
webapp_welcome_profile.py | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/webapp_welcome.py b/webapp_welcome.py
index e623b3242..d5530a681 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -9,6 +9,7 @@ __status__ = "Production"
import os
from shutil import copyfile
from utils import getConfigParam
+from utils import removeHtml
from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter
from webapp_utils import markdownToHtml
@@ -60,7 +61,7 @@ def htmlWelcomeScreen(baseDir: str, nickname: str,
copyfile(defaultFilename, welcomeFilename)
if os.path.isfile(welcomeFilename):
with open(welcomeFilename, 'r') as welcomeFile:
- welcomeText = markdownToHtml(welcomeFile.read())
+ welcomeText = markdownToHtml(removeHtml(welcomeFile.read()))
welcomeForm = ''
cssFilename = baseDir + '/epicyon-welcome.css'
diff --git a/webapp_welcome_final.py b/webapp_welcome_final.py
index 2e3f6f293..5b61bab51 100644
--- a/webapp_welcome_final.py
+++ b/webapp_welcome_final.py
@@ -8,6 +8,7 @@ __status__ = "Production"
import os
from shutil import copyfile
+from utils import removeHtml
from utils import getConfigParam
from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter
@@ -35,7 +36,7 @@ def htmlWelcomeFinal(baseDir: str, nickname: str, domain: str,
copyfile(defaultFilename, finalFilename)
if os.path.isfile(finalFilename):
with open(finalFilename, 'r') as finalFile:
- finalText = markdownToHtml(finalFile.read())
+ finalText = markdownToHtml(removeHtml(finalFile.read()))
finalForm = ''
cssFilename = baseDir + '/epicyon-welcome.css'
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index b84b474db..5f1d4b9ca 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -8,6 +8,7 @@ __status__ = "Production"
import os
from shutil import copyfile
+from utils import removeHtml
from utils import loadJson
from utils import getConfigParam
from utils import getImageExtensions
@@ -38,7 +39,7 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
copyfile(defaultFilename, profileFilename)
if os.path.isfile(profileFilename):
with open(profileFilename, 'r') as profileFile:
- profileText = markdownToHtml(profileFile.read())
+ profileText = markdownToHtml(removeHtml(profileFile.read()))
profileForm = ''
cssFilename = baseDir + '/epicyon-welcome.css'
From 864bd5a8c297669f54e165813ffd91075ff21636 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 20:19:28 +0000
Subject: [PATCH 0071/1416] Welcome screen translations
---
defaultwelcome/final_ar.md | 9 +++++++++
defaultwelcome/final_ca.md | 9 +++++++++
defaultwelcome/final_cy.md | 9 +++++++++
defaultwelcome/final_es.md | 9 +++++++++
defaultwelcome/final_fr.md | 9 +++++++++
defaultwelcome/final_ga.md | 9 +++++++++
defaultwelcome/final_hi.md | 9 +++++++++
defaultwelcome/final_it.md | 9 +++++++++
defaultwelcome/final_ja.md | 9 +++++++++
defaultwelcome/final_oc.md | 9 +++++++++
defaultwelcome/final_pt.md | 9 +++++++++
defaultwelcome/final_ru.md | 9 +++++++++
defaultwelcome/final_zh.md | 9 +++++++++
defaultwelcome/profile_ar.md | 2 ++
defaultwelcome/profile_ca.md | 2 ++
defaultwelcome/profile_cy.md | 2 ++
defaultwelcome/profile_de.md | 2 ++
defaultwelcome/profile_es.md | 2 ++
defaultwelcome/profile_fr.md | 2 ++
defaultwelcome/profile_ga.md | 2 ++
defaultwelcome/profile_hi.md | 2 ++
defaultwelcome/profile_it.md | 2 ++
defaultwelcome/profile_ja.md | 2 ++
defaultwelcome/profile_oc.md | 2 ++
defaultwelcome/profile_pt.md | 2 ++
defaultwelcome/profile_ru.md | 2 ++
defaultwelcome/profile_zh.md | 2 ++
defaultwelcome/welcome_ar.md | 6 ++++++
defaultwelcome/welcome_ca.md | 6 ++++++
defaultwelcome/welcome_cy.md | 6 ++++++
defaultwelcome/welcome_de.md | 6 ++++++
defaultwelcome/welcome_es.md | 6 ++++++
defaultwelcome/welcome_fr.md | 6 ++++++
defaultwelcome/welcome_ga.md | 6 ++++++
defaultwelcome/welcome_hi.md | 6 ++++++
defaultwelcome/welcome_it.md | 6 ++++++
defaultwelcome/welcome_ja.md | 6 ++++++
defaultwelcome/welcome_oc.md | 6 ++++++
defaultwelcome/welcome_pt.md | 6 ++++++
defaultwelcome/welcome_ru.md | 6 ++++++
defaultwelcome/welcome_zh.md | 6 ++++++
41 files changed, 229 insertions(+)
create mode 100644 defaultwelcome/final_ar.md
create mode 100644 defaultwelcome/final_ca.md
create mode 100644 defaultwelcome/final_cy.md
create mode 100644 defaultwelcome/final_es.md
create mode 100644 defaultwelcome/final_fr.md
create mode 100644 defaultwelcome/final_ga.md
create mode 100644 defaultwelcome/final_hi.md
create mode 100644 defaultwelcome/final_it.md
create mode 100644 defaultwelcome/final_ja.md
create mode 100644 defaultwelcome/final_oc.md
create mode 100644 defaultwelcome/final_pt.md
create mode 100644 defaultwelcome/final_ru.md
create mode 100644 defaultwelcome/final_zh.md
create mode 100644 defaultwelcome/profile_ar.md
create mode 100644 defaultwelcome/profile_ca.md
create mode 100644 defaultwelcome/profile_cy.md
create mode 100644 defaultwelcome/profile_de.md
create mode 100644 defaultwelcome/profile_es.md
create mode 100644 defaultwelcome/profile_fr.md
create mode 100644 defaultwelcome/profile_ga.md
create mode 100644 defaultwelcome/profile_hi.md
create mode 100644 defaultwelcome/profile_it.md
create mode 100644 defaultwelcome/profile_ja.md
create mode 100644 defaultwelcome/profile_oc.md
create mode 100644 defaultwelcome/profile_pt.md
create mode 100644 defaultwelcome/profile_ru.md
create mode 100644 defaultwelcome/profile_zh.md
create mode 100644 defaultwelcome/welcome_ar.md
create mode 100644 defaultwelcome/welcome_ca.md
create mode 100644 defaultwelcome/welcome_cy.md
create mode 100644 defaultwelcome/welcome_de.md
create mode 100644 defaultwelcome/welcome_es.md
create mode 100644 defaultwelcome/welcome_fr.md
create mode 100644 defaultwelcome/welcome_ga.md
create mode 100644 defaultwelcome/welcome_hi.md
create mode 100644 defaultwelcome/welcome_it.md
create mode 100644 defaultwelcome/welcome_ja.md
create mode 100644 defaultwelcome/welcome_oc.md
create mode 100644 defaultwelcome/welcome_pt.md
create mode 100644 defaultwelcome/welcome_ru.md
create mode 100644 defaultwelcome/welcome_zh.md
diff --git a/defaultwelcome/final_ar.md b/defaultwelcome/final_ar.md
new file mode 100644
index 000000000..fd5240496
--- /dev/null
+++ b/defaultwelcome/final_ar.md
@@ -0,0 +1,9 @@
+# تهانينا!
+أنت الآن جاهز لبدء استخدام Epicyon. هذه مساحة اجتماعية خاضعة للإشراف ، لذا يرجى التأكد من الالتزام بـ [شروط الخدمة](/terms) الخاصة بنا ، واستمتع.
+
+### تلميحات
+استخدم رمز **المكبر** 🔍 للبحث عن مقابض الكون المشترك ومتابعة الأشخاص.
+
+يؤدي تحديد **الشعار في الجزء العلوي** من الشاشة إلى التبديل بين عرض المخطط الزمني وملف التعريف الخاص بك.
+
+لن يتم تحديث الشاشة تلقائيًا عند وصول المنشورات ، لذا استخدم **F5** أو زر البريد الوارد للتحديث.
diff --git a/defaultwelcome/final_ca.md b/defaultwelcome/final_ca.md
new file mode 100644
index 000000000..cc139b21c
--- /dev/null
+++ b/defaultwelcome/final_ca.md
@@ -0,0 +1,9 @@
+# Enhorabona!
+Ja esteu a punt per començar a utilitzar Epicyon. Aquest és un espai social moderat, així que assegureu-vos de complir les nostres [condicions del servei](/terms) i divertir-vos.
+
+### Consells
+Utilitzeu la icona de **lupa** 🔍 per cercar manetes fedivers i seguir les persones.
+
+Si seleccioneu el **bàner a la part superior** de la pantalla es canvia entre la visualització de la línia de temps i el vostre perfil.
+
+La pantalla no s'actualitzarà automàticament quan arribin les publicacions, així que utilitzeu **F5** o el botó **Safata d'entrada** per actualitzar.
diff --git a/defaultwelcome/final_cy.md b/defaultwelcome/final_cy.md
new file mode 100644
index 000000000..6ec6f4e86
--- /dev/null
+++ b/defaultwelcome/final_cy.md
@@ -0,0 +1,9 @@
+# Llongyfarchiadau!
+Rydych nawr yn barod i ddechrau defnyddio Epicyon. Mae hwn yn ofod cymdeithasol wedi'i gymedroli, felly gwnewch yn siŵr eich bod yn cadw at ein [telerau gwasanaeth](/terms), a chael hwyl.
+
+### Awgrymiadau
+Defnyddiwch yr eicon **chwyddwydr** 🔍 i chwilio am ddolenni bwydo a dilyn pobl.
+
+Mae dewis y faner **ar frig** y sgrin yn newid rhwng yr olygfa llinell amser a'ch proffil.
+
+Ni fydd y sgrin yn adnewyddu'n awtomatig pan fydd pyst yn cyrraedd, felly defnyddiwch **F5** neu'r botwm **Mewnflwch** i adnewyddu.
diff --git a/defaultwelcome/final_es.md b/defaultwelcome/final_es.md
new file mode 100644
index 000000000..d316d9e2c
--- /dev/null
+++ b/defaultwelcome/final_es.md
@@ -0,0 +1,9 @@
+# ¡Felicidades!
+Ahora está listo para comenzar a usar Epicyon. Este es un espacio social moderado, así que asegúrese de cumplir con nuestros [términos de servicio](/terms) y diviértase.
+
+### Sugerencias
+Utilice el icono de **lupa** 🔍 para buscar identificadores de fediverse y seguir a las personas.
+
+Al seleccionar el **banner en la parte superior** de la pantalla, se cambia entre la vista de línea de tiempo y su perfil.
+
+La pantalla no se actualizará automáticamente cuando lleguen las publicaciones, así que use **F5** o el botón **Bandeja de entrada** para actualizar.
diff --git a/defaultwelcome/final_fr.md b/defaultwelcome/final_fr.md
new file mode 100644
index 000000000..c2693a5af
--- /dev/null
+++ b/defaultwelcome/final_fr.md
@@ -0,0 +1,9 @@
+# Toutes nos félicitations!
+Vous êtes maintenant prêt à commencer à utiliser Epicyon. Il s'agit d'un espace social modéré, alors assurez-vous de respecter nos [conditions d'utilisation](/terms) et amusez-vous.
+
+### Conseils
+Utilisez l'icône **loupe** 🔍 pour rechercher des poignées fediverse et suivre les gens.
+
+La sélection de la **bannière en haut** de l'écran bascule entre la vue chronologique et votre profil.
+
+L'écran ne s'actualisera pas automatiquement à l'arrivée des messages, utilisez donc **F5** ou le bouton **Boîte de réception** pour actualiser.
diff --git a/defaultwelcome/final_ga.md b/defaultwelcome/final_ga.md
new file mode 100644
index 000000000..a7290f030
--- /dev/null
+++ b/defaultwelcome/final_ga.md
@@ -0,0 +1,9 @@
+# Comhghairdeas!
+Tá tú réidh anois chun Epicyon a úsáid. Is spás sóisialta measartha é seo, mar sin déan cinnte cloí lenár [dtéarmaí seirbhíse](/terms), agus spraoi a bheith agat.
+
+### Leideanna
+Úsáid an deilbhín **formhéadaitheoir** chun cuardach a dhéanamh ar láimhseálacha beathaithe agus lean daoine.
+
+Ag roghnú an bhratach **ag barr** na lasca scáileáin idir amharc amlíne agus do phróifíl.
+
+Ní dhéanfaidh an scáileán athnuachan go huathoibríoch nuair a thiocfaidh na poist, mar sin bain úsáid as **F5** nó an cnaipe **Bosca Isteach** chun athnuachan a dhéanamh.
diff --git a/defaultwelcome/final_hi.md b/defaultwelcome/final_hi.md
new file mode 100644
index 000000000..9e83e11a7
--- /dev/null
+++ b/defaultwelcome/final_hi.md
@@ -0,0 +1,9 @@
+# बधाई हो!
+अब आप एपिसकॉन का उपयोग शुरू करने के लिए तैयार हैं। यह एक मध्यम सामाजिक स्थान है, इसलिए कृपया हमारी [सेवा की शर्तों](/terms) का पालन करना सुनिश्चित करें, और मज़े करें।
+
+### संकेत
+फ़ेडरिवर्स हैंडल की खोज करने और लोगों का अनुसरण करने के लिए **आवर्धक आइकन** का उपयोग करें।
+
+समय दृश्य और आपकी प्रोफ़ाइल के बीच स्क्रीन स्विच के शीर्ष **पर स्थित** बैनर का चयन करना।
+
+पोस्ट आने पर स्क्रीन अपने आप रिफ्रेश नहीं होगी, इसलिए रीफ्रेश करने के लिए **F5** या **इनबॉक्स** बटन का उपयोग करें।
diff --git a/defaultwelcome/final_it.md b/defaultwelcome/final_it.md
new file mode 100644
index 000000000..688137e72
--- /dev/null
+++ b/defaultwelcome/final_it.md
@@ -0,0 +1,9 @@
+# Congratulazioni!
+Ora sei pronto per iniziare a utilizzare Epicyon. Questo è uno spazio social moderato, quindi assicurati di rispettare i nostri [termini di servizio](/terms) e divertiti.
+
+### Suggerimenti
+Usa l'icona **lente d'ingrandimento** 🔍 per cercare gli handle di fediverse e seguire le persone.
+
+Selezionando il **banner nella parte superiore** dello schermo si passa dalla visualizzazione della sequenza temporale al tuo profilo.
+
+La schermata non si aggiornerà automaticamente all'arrivo dei post, quindi utilizza **F5** o il pulsante **Posta in arrivo** per aggiornare.
diff --git a/defaultwelcome/final_ja.md b/defaultwelcome/final_ja.md
new file mode 100644
index 000000000..97076a0fa
--- /dev/null
+++ b/defaultwelcome/final_ja.md
@@ -0,0 +1,9 @@
+# おめでとう!
+これで、Epicyonの使用を開始する準備が整いました。 適度な社交空間ですので、必ず [利用規約](/terms) を遵守して楽しんでください。
+
+### ヒント
+**拡大鏡** アイコン🔍を使用して、fediverseハンドルを検索し、人々をフォローします。
+
+画面の上部にある **バナー** を選択すると、タイムラインビューとプロファイルが切り替わります。
+
+投稿が到着しても画面は自動的に更新されないため、 **F5** または **受信トレイ** ボタンを使用して更新してください。
diff --git a/defaultwelcome/final_oc.md b/defaultwelcome/final_oc.md
new file mode 100644
index 000000000..ef9eb2601
--- /dev/null
+++ b/defaultwelcome/final_oc.md
@@ -0,0 +1,9 @@
+# Congratulations!
+You are now ready to begin using Epicyon. This is a moderated social space, so please make sure to abide by our [terms of service](/terms), and have fun.
+
+### Hints
+Use the **magnifier** icon 🔍 to search for fediverse handles and follow people.
+
+Selecting the **banner at the top** of the screen switches between timeline view and your profile.
+
+The screen will not automatically refresh when posts arrive, so use **F5** or the **Inbox** button to refresh.
diff --git a/defaultwelcome/final_pt.md b/defaultwelcome/final_pt.md
new file mode 100644
index 000000000..3f8cdf87b
--- /dev/null
+++ b/defaultwelcome/final_pt.md
@@ -0,0 +1,9 @@
+# Parabéns!
+Agora você está pronto para começar a usar o Epicyon. Este é um espaço social moderado, portanto, certifique-se de seguir nossos [termos de serviço](/terms) e divirta-se.
+
+### Dicas
+Use o ícone de **lupa** 🔍 para pesquisar as alças do fediverse e seguir pessoas.
+
+Selecionar o **banner na parte superior** da tela alterna entre a visualização da linha do tempo e seu perfil.
+
+A tela não será atualizada automaticamente quando as postagens chegarem, então use **F5** ou o botão **Caixa de entrada** para atualizar.
diff --git a/defaultwelcome/final_ru.md b/defaultwelcome/final_ru.md
new file mode 100644
index 000000000..d765519b3
--- /dev/null
+++ b/defaultwelcome/final_ru.md
@@ -0,0 +1,9 @@
+# Поздравляю!
+Теперь вы готовы начать использовать Epicyon. Это модерируемое социальное пространство, поэтому, пожалуйста, соблюдайте наши [условия обслуживания](/terms) и получайте удовольствие.
+
+### Подсказки
+Используйте значок **лупы** 🔍, чтобы искать нужные метки и следить за людьми.
+
+При выборе **баннера вверху** экрана выполняется переключение между представлением временной шкалы и вашим профилем.
+
+Экран не обновляется автоматически при поступлении сообщений, поэтому используйте **F5** или кнопку **Входящие** для обновления.
diff --git a/defaultwelcome/final_zh.md b/defaultwelcome/final_zh.md
new file mode 100644
index 000000000..8507c3644
--- /dev/null
+++ b/defaultwelcome/final_zh.md
@@ -0,0 +1,9 @@
+# 恭喜你!
+您现在可以开始使用Epicyon。 这是一个温和的社交空间,因此请务必遵守我们的 [服务条款](/terms),并从中获得乐趣。
+
+### 提示
+使用 放大镜图标🔍搜索fed回的手柄并关注他人。
+
+选择屏幕顶部的“横幅” 可在时间轴视图和您的个人资料之间切换。
+
+帖子到达时,屏幕不会自动刷新,因此请使用 **F5** 或 **收件箱** 按钮进行刷新。
diff --git a/defaultwelcome/profile_ar.md b/defaultwelcome/profile_ar.md
new file mode 100644
index 000000000..ba99dcff5
--- /dev/null
+++ b/defaultwelcome/profile_ar.md
@@ -0,0 +1,2 @@
+## اعدادات الحساب
+حدد صورتك الرمزية وأضف اسمك ووصفك. استخدم صورة رمزية صغيرة (على سبيل المثال ، 128 × 128 بكسل) بحيث يمكن تنزيلها بسرعة.
diff --git a/defaultwelcome/profile_ca.md b/defaultwelcome/profile_ca.md
new file mode 100644
index 000000000..dfbf60f70
--- /dev/null
+++ b/defaultwelcome/profile_ca.md
@@ -0,0 +1,2 @@
+## Configuració del compte
+Seleccioneu la vostra imatge d’avatar i afegiu el vostre nom i la vostra descripció. Utilitzeu una imatge d’avatar petita (per exemple, 128x128 píxels) per baixar-la ràpidament.
diff --git a/defaultwelcome/profile_cy.md b/defaultwelcome/profile_cy.md
new file mode 100644
index 000000000..0dc1a77f5
--- /dev/null
+++ b/defaultwelcome/profile_cy.md
@@ -0,0 +1,2 @@
+## Gosod Cyfrif
+Dewiswch eich delwedd avatar ac ychwanegwch eich enw a'ch disgrifiad. Defnyddiwch ddelwedd avatar fach (ee 128x128 picsel) fel ei bod yn gyflym i'w lawrlwytho.
diff --git a/defaultwelcome/profile_de.md b/defaultwelcome/profile_de.md
new file mode 100644
index 000000000..ea74851e3
--- /dev/null
+++ b/defaultwelcome/profile_de.md
@@ -0,0 +1,2 @@
+## Kontoeinrichtung
+Wählen Sie Ihr Avatar-Bild aus und fügen Sie Ihren Namen und Ihre Beschreibung hinzu. Verwenden Sie ein kleines Avatar-Bild (z. B. 128 x 128 Pixel), damit es schnell heruntergeladen werden kann.
diff --git a/defaultwelcome/profile_es.md b/defaultwelcome/profile_es.md
new file mode 100644
index 000000000..4e7ea5ede
--- /dev/null
+++ b/defaultwelcome/profile_es.md
@@ -0,0 +1,2 @@
+## Configuracion de cuenta
+Seleccione su imagen de avatar y agregue su nombre y descripción. Utilice una imagen de avatar pequeña (por ejemplo, 128x128 píxeles) para que se descargue rápidamente.
diff --git a/defaultwelcome/profile_fr.md b/defaultwelcome/profile_fr.md
new file mode 100644
index 000000000..e73a5c6cb
--- /dev/null
+++ b/defaultwelcome/profile_fr.md
@@ -0,0 +1,2 @@
+## Configuration du compte
+Sélectionnez l'image de votre avatar et ajoutez votre nom et votre description. Utilisez une petite image d'avatar (par exemple, 128x128 pixels) pour un téléchargement rapide.
diff --git a/defaultwelcome/profile_ga.md b/defaultwelcome/profile_ga.md
new file mode 100644
index 000000000..73863220f
--- /dev/null
+++ b/defaultwelcome/profile_ga.md
@@ -0,0 +1,2 @@
+## Socrú Cuntas
+Roghnaigh d’íomhá avatar agus cuir d’ainm agus do thuairisc leis. Úsáid íomhá bheag avatar (m.sh. 128x128 picteilín) ionas go mbeidh sí gasta le híoslódáil.
diff --git a/defaultwelcome/profile_hi.md b/defaultwelcome/profile_hi.md
new file mode 100644
index 000000000..a1c69e9fa
--- /dev/null
+++ b/defaultwelcome/profile_hi.md
@@ -0,0 +1,2 @@
+## खाता स्थापित करना
+अपनी अवतार छवि का चयन करें और अपना नाम और विवरण जोड़ें। एक छोटी अवतार छवि (जैसे। 128x128 पिक्सेल) का उपयोग करें ताकि यह डाउनलोड करने में तेज हो।
diff --git a/defaultwelcome/profile_it.md b/defaultwelcome/profile_it.md
new file mode 100644
index 000000000..aab8cd484
--- /dev/null
+++ b/defaultwelcome/profile_it.md
@@ -0,0 +1,2 @@
+## Configurazione dell'account
+Seleziona la tua immagine avatar e aggiungi il tuo nome e la descrizione. Usa una piccola immagine avatar (es. 128x128 pixel) in modo che sia veloce da scaricare.
diff --git a/defaultwelcome/profile_ja.md b/defaultwelcome/profile_ja.md
new file mode 100644
index 000000000..833e2857a
--- /dev/null
+++ b/defaultwelcome/profile_ja.md
@@ -0,0 +1,2 @@
+## アカウントの設定
+アバター画像を選択し、名前と説明を追加します。 小さなアバター画像(128x128ピクセルなど)を使用して、すばやくダウンロードできるようにします。
diff --git a/defaultwelcome/profile_oc.md b/defaultwelcome/profile_oc.md
new file mode 100644
index 000000000..10d1e09e3
--- /dev/null
+++ b/defaultwelcome/profile_oc.md
@@ -0,0 +1,2 @@
+## Account Setup
+Select your avatar image and add your name and description. Use a small avatar image (eg. 128x128 pixels) so that it's quick to download.
diff --git a/defaultwelcome/profile_pt.md b/defaultwelcome/profile_pt.md
new file mode 100644
index 000000000..9371c6ad3
--- /dev/null
+++ b/defaultwelcome/profile_pt.md
@@ -0,0 +1,2 @@
+## Configuração da conta
+Selecione sua imagem de avatar e adicione seu nome e descrição. Use uma pequena imagem de avatar (por exemplo, 128x128 pixels) para que o download seja rápido.
diff --git a/defaultwelcome/profile_ru.md b/defaultwelcome/profile_ru.md
new file mode 100644
index 000000000..b925532d2
--- /dev/null
+++ b/defaultwelcome/profile_ru.md
@@ -0,0 +1,2 @@
+## Настройка учетной записи
+Выберите изображение своего аватара и добавьте свое имя и описание. Используйте небольшое изображение аватара (например, 128x128 пикселей), чтобы его можно было быстро загрузить.
diff --git a/defaultwelcome/profile_zh.md b/defaultwelcome/profile_zh.md
new file mode 100644
index 000000000..6237ea24b
--- /dev/null
+++ b/defaultwelcome/profile_zh.md
@@ -0,0 +1,2 @@
+## 帐户设定
+选择您的头像图片并添加您的姓名和描述。 使用较小的头像图片(例如128x128像素),以便快速下载。
diff --git a/defaultwelcome/welcome_ar.md b/defaultwelcome/welcome_ar.md
new file mode 100644
index 000000000..655d76864
--- /dev/null
+++ b/defaultwelcome/welcome_ar.md
@@ -0,0 +1,6 @@
+# أهلا بك
+Epicyon هو خادم ActivityPub مصمم للاستضافة الذاتية السهلة لعدد قليل من الأشخاص على أنظمة منخفضة الطاقة ، مثل أجهزة الكمبيوتر ذات اللوحة الواحدة أو أجهزة الكمبيوتر المحمولة القديمة.
+
+قم بتشغيل وجودك على الشبكة الاجتماعية بالطريقة التي تريدها ، وداعًا لشركة Big Tech.
+
+الآن ، لنبدأ ...
diff --git a/defaultwelcome/welcome_ca.md b/defaultwelcome/welcome_ca.md
new file mode 100644
index 000000000..02875db13
--- /dev/null
+++ b/defaultwelcome/welcome_ca.md
@@ -0,0 +1,6 @@
+# Benvingut
+Epicyon és un servidor ActivityPub dissenyat per allotjar fàcilment algunes persones en sistemes de poca potència, com ara ordinadors de placa única o portàtils antics.
+
+Gestioneu la vostra pròpia presència a la xarxa social com vulgueu i acomiadeu-vos de Big Tech.
+
+Ara, comencem ...
diff --git a/defaultwelcome/welcome_cy.md b/defaultwelcome/welcome_cy.md
new file mode 100644
index 000000000..81e57dfe5
--- /dev/null
+++ b/defaultwelcome/welcome_cy.md
@@ -0,0 +1,6 @@
+# Croeso
+Gweinydd ActivityPub yw Epicyon a ddyluniwyd ar gyfer hunangynhaliol hawdd ychydig o bobl ar systemau pŵer isel, megis cyfrifiaduron bwrdd sengl neu hen gliniaduron.
+
+Rhedeg eich presenoldeb rhwydwaith cymdeithasol eich hun yn y ffordd rydych chi eisiau, a ffarwelio â Big Tech.
+
+Nawr, gadewch i ni fynd ...
diff --git a/defaultwelcome/welcome_de.md b/defaultwelcome/welcome_de.md
new file mode 100644
index 000000000..39ef9ba2b
--- /dev/null
+++ b/defaultwelcome/welcome_de.md
@@ -0,0 +1,6 @@
+# Herzlich willkommen
+Epicyon ist ein ActivityPub-Server, der für das einfache Selbsthosting einiger weniger Personen auf Systemen mit geringem Stromverbrauch wie Single-Board-Computern oder alten Laptops entwickelt wurde.
+
+Führen Sie Ihre eigene soziale Netzwerkpräsenz so, wie Sie möchten, und verabschieden Sie sich von Big Tech.
+
+Jetzt geht's los ...
diff --git a/defaultwelcome/welcome_es.md b/defaultwelcome/welcome_es.md
new file mode 100644
index 000000000..4928e0635
--- /dev/null
+++ b/defaultwelcome/welcome_es.md
@@ -0,0 +1,6 @@
+# Bienvenida
+Epicyon es un servidor ActivityPub diseñado para el autohospedaje sencillo de algunas personas en sistemas de baja potencia, como computadoras de placa única o laptops antiguas.
+
+Ejecute su propia presencia en las redes sociales de la forma que desee y despídase de las grandes tecnologías.
+
+Ahora, vayamos ...
diff --git a/defaultwelcome/welcome_fr.md b/defaultwelcome/welcome_fr.md
new file mode 100644
index 000000000..75a0e82bd
--- /dev/null
+++ b/defaultwelcome/welcome_fr.md
@@ -0,0 +1,6 @@
+# Bienvenue
+Epicyon est un serveur ActivityPub conçu pour l'auto-hébergement facile de quelques personnes sur des systèmes à faible consommation d'énergie, tels que des ordinateurs monocarte ou d'anciens ordinateurs portables.
+
+Gérez votre propre présence sur les réseaux sociaux comme vous le souhaitez et dites au revoir à Big Tech.
+
+Maintenant, allons-y ...
diff --git a/defaultwelcome/welcome_ga.md b/defaultwelcome/welcome_ga.md
new file mode 100644
index 000000000..0bda3e4b0
--- /dev/null
+++ b/defaultwelcome/welcome_ga.md
@@ -0,0 +1,6 @@
+# Fáilte
+Is freastalaí ActivityPub é Epicyon atá deartha chun féin-óstáil éasca a dhéanamh ar chúpla duine ar chórais ísealchumhachta, mar ríomhairí boird aonair nó sean ríomhairí glúine.
+
+Rith do láithreacht líonra sóisialta féin ar an mbealach is mian leat, agus slán a fhágáil le Big Tech.
+
+Anois, ligeann duit dul ...
diff --git a/defaultwelcome/welcome_hi.md b/defaultwelcome/welcome_hi.md
new file mode 100644
index 000000000..64b5f5044
--- /dev/null
+++ b/defaultwelcome/welcome_hi.md
@@ -0,0 +1,6 @@
+# स्वागत हे
+एपिसिपोन एक एक्टिविटीपब सर्वर है, जो कम पावर सिस्टम पर सिंगल बोर्ड कंप्यूटर या पुराने लैपटॉप जैसे कुछ लोगों की आसान सेल्फ-होस्टिंग के लिए बनाया गया है।
+
+जिस तरह से आप चाहते हैं, अपने खुद के सोशल नेटवर्क उपस्थिति को चलाएं और बिग टेक को अलविदा कहें।
+
+अब, चल रहा है ...
diff --git a/defaultwelcome/welcome_it.md b/defaultwelcome/welcome_it.md
new file mode 100644
index 000000000..17bb0ff37
--- /dev/null
+++ b/defaultwelcome/welcome_it.md
@@ -0,0 +1,6 @@
+# Benvenuta
+Epicyon è un server ActivityPub progettato per un facile self-hosting di poche persone su sistemi a bassa potenza, come computer a scheda singola o vecchi laptop.
+
+Gestisci la tua presenza sui social network come preferisci e saluta Big Tech.
+
+Ora andiamo ...
diff --git a/defaultwelcome/welcome_ja.md b/defaultwelcome/welcome_ja.md
new file mode 100644
index 000000000..b306ab3dc
--- /dev/null
+++ b/defaultwelcome/welcome_ja.md
@@ -0,0 +1,6 @@
+# ようこそ
+Epicyonは、シングルボードコンピューターや古いラップトップなどの低電力システムで数人を簡単にセルフホスティングできるように設計されたActivityPubサーバーです。
+
+独自のソーシャルネットワークプレゼンスを希望どおりに実行し、BigTechに別れを告げます。
+
+さあ、始めましょう...
diff --git a/defaultwelcome/welcome_oc.md b/defaultwelcome/welcome_oc.md
new file mode 100644
index 000000000..2a90b3a52
--- /dev/null
+++ b/defaultwelcome/welcome_oc.md
@@ -0,0 +1,6 @@
+# Welcome
+Epicyon is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops.
+
+Run your own social network presence the way you want to, and say goodbye to Big Tech.
+
+Now, lets get going...
diff --git a/defaultwelcome/welcome_pt.md b/defaultwelcome/welcome_pt.md
new file mode 100644
index 000000000..df46bc080
--- /dev/null
+++ b/defaultwelcome/welcome_pt.md
@@ -0,0 +1,6 @@
+# Receber
+Epicyon é um servidor ActivityPub projetado para fácil auto-hospedagem de algumas pessoas em sistemas de baixa energia, como computadores de placa única ou laptops antigos.
+
+Administre sua própria presença na rede social do jeito que você quiser e diga adeus à Big Tech.
+
+Agora, vamos indo ...
diff --git a/defaultwelcome/welcome_ru.md b/defaultwelcome/welcome_ru.md
new file mode 100644
index 000000000..6761a996a
--- /dev/null
+++ b/defaultwelcome/welcome_ru.md
@@ -0,0 +1,6 @@
+# Добро пожаловать
+Epicyon - это сервер ActivityPub, предназначенный для простого самостоятельного размещения нескольких человек в системах с низким энергопотреблением, таких как одноплатные компьютеры или старые ноутбуки.
+
+Управляйте своим присутствием в социальных сетях так, как вы хотите, и попрощайтесь с Big Tech.
+
+А теперь поехали ...
diff --git a/defaultwelcome/welcome_zh.md b/defaultwelcome/welcome_zh.md
new file mode 100644
index 000000000..44c642c51
--- /dev/null
+++ b/defaultwelcome/welcome_zh.md
@@ -0,0 +1,6 @@
+# 欢迎
+Epicyon是一个ActivityPub服务器,其设计用于在低功耗系统(例如单板计算机或旧笔记本电脑)上轻松实现一些人的自我托管。
+
+随心所欲地经营自己的社交网络,并与Big Tech道别。
+
+现在,开始吧...
From 6c6618fa3baf3359d382add3b7c32007d19e949b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 22:25:01 +0000
Subject: [PATCH 0072/1416] Substitute instance title within welcome screens
---
defaultwelcome/welcome_en.md | 4 ++--
webapp_welcome.py | 12 +++++++++---
webapp_welcome_final.py | 12 +++++++++---
webapp_welcome_profile.py | 12 +++++++++---
4 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/defaultwelcome/welcome_en.md b/defaultwelcome/welcome_en.md
index 2a90b3a52..c069ae1c6 100644
--- a/defaultwelcome/welcome_en.md
+++ b/defaultwelcome/welcome_en.md
@@ -1,5 +1,5 @@
-# Welcome
-Epicyon is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops.
+# Welcome to INSTANCE
+This is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops.
Run your own social network presence the way you want to, and say goodbye to Big Tech.
diff --git a/webapp_welcome.py b/webapp_welcome.py
index d5530a681..77c868707 100644
--- a/webapp_welcome.py
+++ b/webapp_welcome.py
@@ -59,17 +59,23 @@ def htmlWelcomeScreen(baseDir: str, nickname: str,
defaultFilename = \
baseDir + '/defaultwelcome/' + currScreen + '_en.md'
copyfile(defaultFilename, welcomeFilename)
+
+ instanceTitle = \
+ getConfigParam(baseDir, 'instanceTitle')
+ if not instanceTitle:
+ instanceTitle = 'Epicyon'
+
if os.path.isfile(welcomeFilename):
with open(welcomeFilename, 'r') as welcomeFile:
- welcomeText = markdownToHtml(removeHtml(welcomeFile.read()))
+ welcomeText = welcomeFile.read()
+ welcomeText = welcomeText.replace('INSTANCE', instanceTitle)
+ welcomeText = markdownToHtml(removeHtml(welcomeText))
welcomeForm = ''
cssFilename = baseDir + '/epicyon-welcome.css'
if os.path.isfile(baseDir + '/welcome.css'):
cssFilename = baseDir + '/welcome.css'
- instanceTitle = \
- getConfigParam(baseDir, 'instanceTitle')
welcomeForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
welcomeForm += \
'' + finalText + ' \n'
diff --git a/webapp_welcome_profile.py b/webapp_welcome_profile.py
index 5f1d4b9ca..341ad5b55 100644
--- a/webapp_welcome_profile.py
+++ b/webapp_welcome_profile.py
@@ -37,17 +37,23 @@ def htmlWelcomeProfile(baseDir: str, nickname: str, domain: str,
if not os.path.isfile(defaultFilename):
defaultFilename = baseDir + '/defaultwelcome/profile_en.md'
copyfile(defaultFilename, profileFilename)
+
+ instanceTitle = \
+ getConfigParam(baseDir, 'instanceTitle')
+ if not instanceTitle:
+ instanceTitle = 'Epicyon'
+
if os.path.isfile(profileFilename):
with open(profileFilename, 'r') as profileFile:
- profileText = markdownToHtml(removeHtml(profileFile.read()))
+ profileText = profileFile.read()
+ profileText = profileText.replace('INSTANCE', instanceTitle)
+ profileText = markdownToHtml(removeHtml(profileText))
profileForm = ''
cssFilename = baseDir + '/epicyon-welcome.css'
if os.path.isfile(baseDir + '/welcome.css'):
cssFilename = baseDir + '/welcome.css'
- instanceTitle = \
- getConfigParam(baseDir, 'instanceTitle')
profileForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
# get the url of the avatar
From 181e97cedb61830078d86d3a8ccf1f5cef92836d Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 22:26:36 +0000
Subject: [PATCH 0073/1416] Smaller
---
defaultwelcome/welcome_en.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/defaultwelcome/welcome_en.md b/defaultwelcome/welcome_en.md
index c069ae1c6..5d942a9a5 100644
--- a/defaultwelcome/welcome_en.md
+++ b/defaultwelcome/welcome_en.md
@@ -1,4 +1,4 @@
-# Welcome to INSTANCE
+### Welcome to INSTANCE
This is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops.
Run your own social network presence the way you want to, and say goodbye to Big Tech.
From 3ebb9ce7e0fdff23d084598ab34a96f9057a29c2 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 25 Feb 2021 22:53:13 +0000
Subject: [PATCH 0074/1416] Tweaking welcome text
---
defaultwelcome/final_ar.md | 4 ++--
defaultwelcome/final_ca.md | 4 ++--
defaultwelcome/final_cy.md | 4 ++--
defaultwelcome/final_en.md | 4 ++--
defaultwelcome/final_es.md | 4 ++--
defaultwelcome/final_fr.md | 4 ++--
defaultwelcome/final_ga.md | 4 ++--
defaultwelcome/final_hi.md | 4 ++--
defaultwelcome/final_it.md | 4 ++--
defaultwelcome/final_ja.md | 4 ++--
defaultwelcome/final_ru.md | 4 ++--
defaultwelcome/final_zh.md | 12 ++++++------
defaultwelcome/profile_ar.md | 2 +-
defaultwelcome/profile_ca.md | 2 +-
defaultwelcome/profile_cy.md | 2 +-
defaultwelcome/profile_de.md | 2 +-
defaultwelcome/profile_en.md | 2 +-
defaultwelcome/profile_es.md | 2 +-
defaultwelcome/profile_fr.md | 2 +-
defaultwelcome/profile_ga.md | 2 +-
defaultwelcome/profile_hi.md | 2 +-
defaultwelcome/profile_it.md | 2 +-
defaultwelcome/profile_ja.md | 2 +-
defaultwelcome/profile_ru.md | 2 +-
defaultwelcome/profile_zh.md | 2 +-
defaultwelcome/welcome_ar.md | 4 ++--
defaultwelcome/welcome_ca.md | 4 ++--
defaultwelcome/welcome_cy.md | 4 ++--
defaultwelcome/welcome_de.md | 4 ++--
defaultwelcome/welcome_es.md | 4 ++--
defaultwelcome/welcome_fr.md | 4 ++--
defaultwelcome/welcome_ga.md | 4 ++--
defaultwelcome/welcome_hi.md | 4 ++--
defaultwelcome/welcome_it.md | 4 ++--
defaultwelcome/welcome_ja.md | 4 ++--
defaultwelcome/welcome_pt.md | 4 ++--
defaultwelcome/welcome_ru.md | 4 ++--
defaultwelcome/welcome_zh.md | 4 ++--
38 files changed, 67 insertions(+), 67 deletions(-)
diff --git a/defaultwelcome/final_ar.md b/defaultwelcome/final_ar.md
index fd5240496..0d663d636 100644
--- a/defaultwelcome/final_ar.md
+++ b/defaultwelcome/final_ar.md
@@ -1,7 +1,7 @@
-# تهانينا!
+### تهانينا!
أنت الآن جاهز لبدء استخدام Epicyon. هذه مساحة اجتماعية خاضعة للإشراف ، لذا يرجى التأكد من الالتزام بـ [شروط الخدمة](/terms) الخاصة بنا ، واستمتع.
-### تلميحات
+#### تلميحات
استخدم رمز **المكبر** 🔍 للبحث عن مقابض الكون المشترك ومتابعة الأشخاص.
يؤدي تحديد **الشعار في الجزء العلوي** من الشاشة إلى التبديل بين عرض المخطط الزمني وملف التعريف الخاص بك.
diff --git a/defaultwelcome/final_ca.md b/defaultwelcome/final_ca.md
index cc139b21c..deff371ba 100644
--- a/defaultwelcome/final_ca.md
+++ b/defaultwelcome/final_ca.md
@@ -1,7 +1,7 @@
-# Enhorabona!
+### Enhorabona!
Ja esteu a punt per començar a utilitzar Epicyon. Aquest és un espai social moderat, així que assegureu-vos de complir les nostres [condicions del servei](/terms) i divertir-vos.
-### Consells
+#### Consells
Utilitzeu la icona de **lupa** 🔍 per cercar manetes fedivers i seguir les persones.
Si seleccioneu el **bàner a la part superior** de la pantalla es canvia entre la visualització de la línia de temps i el vostre perfil.
diff --git a/defaultwelcome/final_cy.md b/defaultwelcome/final_cy.md
index 6ec6f4e86..12211aa7a 100644
--- a/defaultwelcome/final_cy.md
+++ b/defaultwelcome/final_cy.md
@@ -1,7 +1,7 @@
-# Llongyfarchiadau!
+### Llongyfarchiadau!
Rydych nawr yn barod i ddechrau defnyddio Epicyon. Mae hwn yn ofod cymdeithasol wedi'i gymedroli, felly gwnewch yn siŵr eich bod yn cadw at ein [telerau gwasanaeth](/terms), a chael hwyl.
-### Awgrymiadau
+#### Awgrymiadau
Defnyddiwch yr eicon **chwyddwydr** 🔍 i chwilio am ddolenni bwydo a dilyn pobl.
Mae dewis y faner **ar frig** y sgrin yn newid rhwng yr olygfa llinell amser a'ch proffil.
diff --git a/defaultwelcome/final_en.md b/defaultwelcome/final_en.md
index ef9eb2601..81aad26cd 100644
--- a/defaultwelcome/final_en.md
+++ b/defaultwelcome/final_en.md
@@ -1,7 +1,7 @@
-# Congratulations!
+### Congratulations!
You are now ready to begin using Epicyon. This is a moderated social space, so please make sure to abide by our [terms of service](/terms), and have fun.
-### Hints
+#### Hints
Use the **magnifier** icon 🔍 to search for fediverse handles and follow people.
Selecting the **banner at the top** of the screen switches between timeline view and your profile.
diff --git a/defaultwelcome/final_es.md b/defaultwelcome/final_es.md
index d316d9e2c..9050750a9 100644
--- a/defaultwelcome/final_es.md
+++ b/defaultwelcome/final_es.md
@@ -1,7 +1,7 @@
-# ¡Felicidades!
+### ¡Felicidades!
Ahora está listo para comenzar a usar Epicyon. Este es un espacio social moderado, así que asegúrese de cumplir con nuestros [términos de servicio](/terms) y diviértase.
-### Sugerencias
+#### Sugerencias
Utilice el icono de **lupa** 🔍 para buscar identificadores de fediverse y seguir a las personas.
Al seleccionar el **banner en la parte superior** de la pantalla, se cambia entre la vista de línea de tiempo y su perfil.
diff --git a/defaultwelcome/final_fr.md b/defaultwelcome/final_fr.md
index c2693a5af..272133245 100644
--- a/defaultwelcome/final_fr.md
+++ b/defaultwelcome/final_fr.md
@@ -1,7 +1,7 @@
-# Toutes nos félicitations!
+### Toutes nos félicitations!
Vous êtes maintenant prêt à commencer à utiliser Epicyon. Il s'agit d'un espace social modéré, alors assurez-vous de respecter nos [conditions d'utilisation](/terms) et amusez-vous.
-### Conseils
+#### Conseils
Utilisez l'icône **loupe** 🔍 pour rechercher des poignées fediverse et suivre les gens.
La sélection de la **bannière en haut** de l'écran bascule entre la vue chronologique et votre profil.
diff --git a/defaultwelcome/final_ga.md b/defaultwelcome/final_ga.md
index a7290f030..b8c1e576b 100644
--- a/defaultwelcome/final_ga.md
+++ b/defaultwelcome/final_ga.md
@@ -1,7 +1,7 @@
-# Comhghairdeas!
+### Comhghairdeas!
Tá tú réidh anois chun Epicyon a úsáid. Is spás sóisialta measartha é seo, mar sin déan cinnte cloí lenár [dtéarmaí seirbhíse](/terms), agus spraoi a bheith agat.
-### Leideanna
+#### Leideanna
Úsáid an deilbhín **formhéadaitheoir** chun cuardach a dhéanamh ar láimhseálacha beathaithe agus lean daoine.
Ag roghnú an bhratach **ag barr** na lasca scáileáin idir amharc amlíne agus do phróifíl.
diff --git a/defaultwelcome/final_hi.md b/defaultwelcome/final_hi.md
index 9e83e11a7..971af274c 100644
--- a/defaultwelcome/final_hi.md
+++ b/defaultwelcome/final_hi.md
@@ -1,7 +1,7 @@
-# बधाई हो!
+### बधाई हो!
अब आप एपिसकॉन का उपयोग शुरू करने के लिए तैयार हैं। यह एक मध्यम सामाजिक स्थान है, इसलिए कृपया हमारी [सेवा की शर्तों](/terms) का पालन करना सुनिश्चित करें, और मज़े करें।
-### संकेत
+#### संकेत
फ़ेडरिवर्स हैंडल की खोज करने और लोगों का अनुसरण करने के लिए **आवर्धक आइकन** का उपयोग करें।
समय दृश्य और आपकी प्रोफ़ाइल के बीच स्क्रीन स्विच के शीर्ष **पर स्थित** बैनर का चयन करना।
diff --git a/defaultwelcome/final_it.md b/defaultwelcome/final_it.md
index 688137e72..818b231f9 100644
--- a/defaultwelcome/final_it.md
+++ b/defaultwelcome/final_it.md
@@ -1,7 +1,7 @@
-# Congratulazioni!
+### Congratulazioni!
Ora sei pronto per iniziare a utilizzare Epicyon. Questo è uno spazio social moderato, quindi assicurati di rispettare i nostri [termini di servizio](/terms) e divertiti.
-### Suggerimenti
+#### Suggerimenti
Usa l'icona **lente d'ingrandimento** 🔍 per cercare gli handle di fediverse e seguire le persone.
Selezionando il **banner nella parte superiore** dello schermo si passa dalla visualizzazione della sequenza temporale al tuo profilo.
diff --git a/defaultwelcome/final_ja.md b/defaultwelcome/final_ja.md
index 97076a0fa..40b4e2575 100644
--- a/defaultwelcome/final_ja.md
+++ b/defaultwelcome/final_ja.md
@@ -1,7 +1,7 @@
-# おめでとう!
+### おめでとう!
これで、Epicyonの使用を開始する準備が整いました。 適度な社交空間ですので、必ず [利用規約](/terms) を遵守して楽しんでください。
-### ヒント
+#### ヒント
**拡大鏡** アイコン🔍を使用して、fediverseハンドルを検索し、人々をフォローします。
画面の上部にある **バナー** を選択すると、タイムラインビューとプロファイルが切り替わります。
diff --git a/defaultwelcome/final_ru.md b/defaultwelcome/final_ru.md
index d765519b3..31e11700f 100644
--- a/defaultwelcome/final_ru.md
+++ b/defaultwelcome/final_ru.md
@@ -1,7 +1,7 @@
-# Поздравляю!
+### Поздравляю!
Теперь вы готовы начать использовать Epicyon. Это модерируемое социальное пространство, поэтому, пожалуйста, соблюдайте наши [условия обслуживания](/terms) и получайте удовольствие.
-### Подсказки
+#### Подсказки
Используйте значок **лупы** 🔍, чтобы искать нужные метки и следить за людьми.
При выборе **баннера вверху** экрана выполняется переключение между представлением временной шкалы и вашим профилем.
diff --git a/defaultwelcome/final_zh.md b/defaultwelcome/final_zh.md
index 8507c3644..1cd50c41b 100644
--- a/defaultwelcome/final_zh.md
+++ b/defaultwelcome/final_zh.md
@@ -1,9 +1,9 @@
-# 恭喜你!
-您现在可以开始使用Epicyon。 这是一个温和的社交空间,因此请务必遵守我们的 [服务条款](/terms),并从中获得乐趣。
+### 恭喜你!
+您现在可以开始使用Epicyon。 这是一个温和的社交空间,因此请务必遵守我们的[服务条款](/terms),并从中获得乐趣。
-### 提示
-使用 放大镜图标🔍搜索fed回的手柄并关注他人。
+####提示
+使用放大镜图标search搜索fed性的手柄并关注他人。
-选择屏幕顶部的“横幅” 可在时间轴视图和您的个人资料之间切换。
+选择屏幕顶部的横幅广告可在时间轴视图和个人资料之间切换。
-帖子到达时,屏幕不会自动刷新,因此请使用 **F5** 或 **收件箱** 按钮进行刷新。
+帖子到达时,屏幕不会自动刷新,因此请使用F5或“收件箱”按钮刷新。
diff --git a/defaultwelcome/profile_ar.md b/defaultwelcome/profile_ar.md
index ba99dcff5..0d0ed4ab9 100644
--- a/defaultwelcome/profile_ar.md
+++ b/defaultwelcome/profile_ar.md
@@ -1,2 +1,2 @@
-## اعدادات الحساب
+### اعدادات الحساب
حدد صورتك الرمزية وأضف اسمك ووصفك. استخدم صورة رمزية صغيرة (على سبيل المثال ، 128 × 128 بكسل) بحيث يمكن تنزيلها بسرعة.
diff --git a/defaultwelcome/profile_ca.md b/defaultwelcome/profile_ca.md
index dfbf60f70..90c5d6c85 100644
--- a/defaultwelcome/profile_ca.md
+++ b/defaultwelcome/profile_ca.md
@@ -1,2 +1,2 @@
-## Configuració del compte
+### Configuració del compte
Seleccioneu la vostra imatge d’avatar i afegiu el vostre nom i la vostra descripció. Utilitzeu una imatge d’avatar petita (per exemple, 128x128 píxels) per baixar-la ràpidament.
diff --git a/defaultwelcome/profile_cy.md b/defaultwelcome/profile_cy.md
index 0dc1a77f5..92ced863e 100644
--- a/defaultwelcome/profile_cy.md
+++ b/defaultwelcome/profile_cy.md
@@ -1,2 +1,2 @@
-## Gosod Cyfrif
+### Gosod Cyfrif
Dewiswch eich delwedd avatar ac ychwanegwch eich enw a'ch disgrifiad. Defnyddiwch ddelwedd avatar fach (ee 128x128 picsel) fel ei bod yn gyflym i'w lawrlwytho.
diff --git a/defaultwelcome/profile_de.md b/defaultwelcome/profile_de.md
index ea74851e3..668da69ce 100644
--- a/defaultwelcome/profile_de.md
+++ b/defaultwelcome/profile_de.md
@@ -1,2 +1,2 @@
-## Kontoeinrichtung
+### Kontoeinrichtung
Wählen Sie Ihr Avatar-Bild aus und fügen Sie Ihren Namen und Ihre Beschreibung hinzu. Verwenden Sie ein kleines Avatar-Bild (z. B. 128 x 128 Pixel), damit es schnell heruntergeladen werden kann.
diff --git a/defaultwelcome/profile_en.md b/defaultwelcome/profile_en.md
index 10d1e09e3..2a1768332 100644
--- a/defaultwelcome/profile_en.md
+++ b/defaultwelcome/profile_en.md
@@ -1,2 +1,2 @@
-## Account Setup
+### Account Setup
Select your avatar image and add your name and description. Use a small avatar image (eg. 128x128 pixels) so that it's quick to download.
diff --git a/defaultwelcome/profile_es.md b/defaultwelcome/profile_es.md
index 4e7ea5ede..63bac75b9 100644
--- a/defaultwelcome/profile_es.md
+++ b/defaultwelcome/profile_es.md
@@ -1,2 +1,2 @@
-## Configuracion de cuenta
+### Configuracion de cuenta
Seleccione su imagen de avatar y agregue su nombre y descripción. Utilice una imagen de avatar pequeña (por ejemplo, 128x128 píxeles) para que se descargue rápidamente.
diff --git a/defaultwelcome/profile_fr.md b/defaultwelcome/profile_fr.md
index e73a5c6cb..56f93d648 100644
--- a/defaultwelcome/profile_fr.md
+++ b/defaultwelcome/profile_fr.md
@@ -1,2 +1,2 @@
-## Configuration du compte
+### Configuration du compte
Sélectionnez l'image de votre avatar et ajoutez votre nom et votre description. Utilisez une petite image d'avatar (par exemple, 128x128 pixels) pour un téléchargement rapide.
diff --git a/defaultwelcome/profile_ga.md b/defaultwelcome/profile_ga.md
index 73863220f..b0019e644 100644
--- a/defaultwelcome/profile_ga.md
+++ b/defaultwelcome/profile_ga.md
@@ -1,2 +1,2 @@
-## Socrú Cuntas
+### Socrú Cuntas
Roghnaigh d’íomhá avatar agus cuir d’ainm agus do thuairisc leis. Úsáid íomhá bheag avatar (m.sh. 128x128 picteilín) ionas go mbeidh sí gasta le híoslódáil.
diff --git a/defaultwelcome/profile_hi.md b/defaultwelcome/profile_hi.md
index a1c69e9fa..5190b999d 100644
--- a/defaultwelcome/profile_hi.md
+++ b/defaultwelcome/profile_hi.md
@@ -1,2 +1,2 @@
-## खाता स्थापित करना
+### खाता स्थापित करना
अपनी अवतार छवि का चयन करें और अपना नाम और विवरण जोड़ें। एक छोटी अवतार छवि (जैसे। 128x128 पिक्सेल) का उपयोग करें ताकि यह डाउनलोड करने में तेज हो।
diff --git a/defaultwelcome/profile_it.md b/defaultwelcome/profile_it.md
index aab8cd484..97487bc62 100644
--- a/defaultwelcome/profile_it.md
+++ b/defaultwelcome/profile_it.md
@@ -1,2 +1,2 @@
-## Configurazione dell'account
+### Configurazione dell'account
Seleziona la tua immagine avatar e aggiungi il tuo nome e la descrizione. Usa una piccola immagine avatar (es. 128x128 pixel) in modo che sia veloce da scaricare.
diff --git a/defaultwelcome/profile_ja.md b/defaultwelcome/profile_ja.md
index 833e2857a..d63a80d55 100644
--- a/defaultwelcome/profile_ja.md
+++ b/defaultwelcome/profile_ja.md
@@ -1,2 +1,2 @@
-## アカウントの設定
+### アカウントの設定
アバター画像を選択し、名前と説明を追加します。 小さなアバター画像(128x128ピクセルなど)を使用して、すばやくダウンロードできるようにします。
diff --git a/defaultwelcome/profile_ru.md b/defaultwelcome/profile_ru.md
index b925532d2..b0d53a568 100644
--- a/defaultwelcome/profile_ru.md
+++ b/defaultwelcome/profile_ru.md
@@ -1,2 +1,2 @@
-## Настройка учетной записи
+### Настройка учетной записи
Выберите изображение своего аватара и добавьте свое имя и описание. Используйте небольшое изображение аватара (например, 128x128 пикселей), чтобы его можно было быстро загрузить.
diff --git a/defaultwelcome/profile_zh.md b/defaultwelcome/profile_zh.md
index 6237ea24b..33a1b0a6d 100644
--- a/defaultwelcome/profile_zh.md
+++ b/defaultwelcome/profile_zh.md
@@ -1,2 +1,2 @@
-## 帐户设定
+### 帐户设定
选择您的头像图片并添加您的姓名和描述。 使用较小的头像图片(例如128x128像素),以便快速下载。
diff --git a/defaultwelcome/welcome_ar.md b/defaultwelcome/welcome_ar.md
index 655d76864..8e88deb0a 100644
--- a/defaultwelcome/welcome_ar.md
+++ b/defaultwelcome/welcome_ar.md
@@ -1,5 +1,5 @@
-# أهلا بك
-Epicyon هو خادم ActivityPub مصمم للاستضافة الذاتية السهلة لعدد قليل من الأشخاص على أنظمة منخفضة الطاقة ، مثل أجهزة الكمبيوتر ذات اللوحة الواحدة أو أجهزة الكمبيوتر المحمولة القديمة.
+### مرحبًا بكم في INSTANCE
+هذا خادم ActivityPub مصمم للاستضافة الذاتية السهلة لعدد قليل من الأشخاص على أنظمة منخفضة الطاقة ، مثل أجهزة الكمبيوتر ذات اللوحة الواحدة أو أجهزة الكمبيوتر المحمولة القديمة.
قم بتشغيل وجودك على الشبكة الاجتماعية بالطريقة التي تريدها ، وداعًا لشركة Big Tech.
diff --git a/defaultwelcome/welcome_ca.md b/defaultwelcome/welcome_ca.md
index 02875db13..0721e7e14 100644
--- a/defaultwelcome/welcome_ca.md
+++ b/defaultwelcome/welcome_ca.md
@@ -1,5 +1,5 @@
-# Benvingut
-Epicyon és un servidor ActivityPub dissenyat per allotjar fàcilment algunes persones en sistemes de poca potència, com ara ordinadors de placa única o portàtils antics.
+### Benvingut a INSTANCE
+Es tracta d’un servidor ActivityPub dissenyat per allotjar fàcilment algunes persones en sistemes de poca potència, com ara ordinadors de placa única o portàtils antics.
Gestioneu la vostra pròpia presència a la xarxa social com vulgueu i acomiadeu-vos de Big Tech.
diff --git a/defaultwelcome/welcome_cy.md b/defaultwelcome/welcome_cy.md
index 81e57dfe5..7596a7927 100644
--- a/defaultwelcome/welcome_cy.md
+++ b/defaultwelcome/welcome_cy.md
@@ -1,5 +1,5 @@
-# Croeso
-Gweinydd ActivityPub yw Epicyon a ddyluniwyd ar gyfer hunangynhaliol hawdd ychydig o bobl ar systemau pŵer isel, megis cyfrifiaduron bwrdd sengl neu hen gliniaduron.
+### Croeso i INSTANCE
+Gweinydd ActivityPub yw hwn sydd wedi'i gynllunio ar gyfer hunan-letya ychydig o bobl ar systemau pŵer isel yn hawdd, fel cyfrifiaduron bwrdd sengl neu hen gliniaduron.
Rhedeg eich presenoldeb rhwydwaith cymdeithasol eich hun yn y ffordd rydych chi eisiau, a ffarwelio â Big Tech.
diff --git a/defaultwelcome/welcome_de.md b/defaultwelcome/welcome_de.md
index 39ef9ba2b..f1dedb95b 100644
--- a/defaultwelcome/welcome_de.md
+++ b/defaultwelcome/welcome_de.md
@@ -1,5 +1,5 @@
-# Herzlich willkommen
-Epicyon ist ein ActivityPub-Server, der für das einfache Selbsthosting einiger weniger Personen auf Systemen mit geringem Stromverbrauch wie Single-Board-Computern oder alten Laptops entwickelt wurde.
+### Willkommen bei INSTANCE
+Dies ist ein ActivityPub-Server, der für das einfache Selbsthosting einiger weniger Personen auf Systemen mit geringem Stromverbrauch wie Single-Board-Computern oder alten Laptops entwickelt wurde.
Führen Sie Ihre eigene soziale Netzwerkpräsenz so, wie Sie möchten, und verabschieden Sie sich von Big Tech.
diff --git a/defaultwelcome/welcome_es.md b/defaultwelcome/welcome_es.md
index 4928e0635..f9ba98454 100644
--- a/defaultwelcome/welcome_es.md
+++ b/defaultwelcome/welcome_es.md
@@ -1,5 +1,5 @@
-# Bienvenida
-Epicyon es un servidor ActivityPub diseñado para el autohospedaje sencillo de algunas personas en sistemas de baja potencia, como computadoras de placa única o laptops antiguas.
+### Bienvenido a INSTANCE
+Este es un servidor ActivityPub diseñado para el autohospedaje sencillo de algunas personas en sistemas de bajo consumo de energía, como computadoras de placa única o laptops antiguas.
Ejecute su propia presencia en las redes sociales de la forma que desee y despídase de las grandes tecnologías.
diff --git a/defaultwelcome/welcome_fr.md b/defaultwelcome/welcome_fr.md
index 75a0e82bd..9fd72437e 100644
--- a/defaultwelcome/welcome_fr.md
+++ b/defaultwelcome/welcome_fr.md
@@ -1,5 +1,5 @@
-# Bienvenue
-Epicyon est un serveur ActivityPub conçu pour l'auto-hébergement facile de quelques personnes sur des systèmes à faible consommation d'énergie, tels que des ordinateurs monocarte ou d'anciens ordinateurs portables.
+### Bienvenue à INSTANCE
+Il s'agit d'un serveur ActivityPub conçu pour l'auto-hébergement facile de quelques personnes sur des systèmes à faible consommation d'énergie, tels que des ordinateurs monocarte ou d'anciens ordinateurs portables.
Gérez votre propre présence sur les réseaux sociaux comme vous le souhaitez et dites au revoir à Big Tech.
diff --git a/defaultwelcome/welcome_ga.md b/defaultwelcome/welcome_ga.md
index 0bda3e4b0..c9a11c680 100644
--- a/defaultwelcome/welcome_ga.md
+++ b/defaultwelcome/welcome_ga.md
@@ -1,5 +1,5 @@
-# Fáilte
-Is freastalaí ActivityPub é Epicyon atá deartha chun féin-óstáil éasca a dhéanamh ar chúpla duine ar chórais ísealchumhachta, mar ríomhairí boird aonair nó sean ríomhairí glúine.
+### Fáilte go INSTANCE
+Is freastalaí ActivityPub é seo atá deartha chun féin-óstáil éasca a dhéanamh ar chúpla duine ar chórais ísealchumhachta, mar ríomhairí boird aonair nó sean ríomhairí glúine.
Rith do láithreacht líonra sóisialta féin ar an mbealach is mian leat, agus slán a fhágáil le Big Tech.
diff --git a/defaultwelcome/welcome_hi.md b/defaultwelcome/welcome_hi.md
index 64b5f5044..13923d095 100644
--- a/defaultwelcome/welcome_hi.md
+++ b/defaultwelcome/welcome_hi.md
@@ -1,5 +1,5 @@
-# स्वागत हे
-एपिसिपोन एक एक्टिविटीपब सर्वर है, जो कम पावर सिस्टम पर सिंगल बोर्ड कंप्यूटर या पुराने लैपटॉप जैसे कुछ लोगों की आसान सेल्फ-होस्टिंग के लिए बनाया गया है।
+### INSTANCE पर आपका स्वागत है
+यह एक एक्टिविटीपब सर्वर है जो कम पावर सिस्टम पर सिंगल बोर्ड कंप्यूटर या पुराने लैपटॉप जैसे कुछ लोगों की आसान सेल्फ-होस्टिंग के लिए बनाया गया है।
जिस तरह से आप चाहते हैं, अपने खुद के सोशल नेटवर्क उपस्थिति को चलाएं और बिग टेक को अलविदा कहें।
diff --git a/defaultwelcome/welcome_it.md b/defaultwelcome/welcome_it.md
index 17bb0ff37..498caf115 100644
--- a/defaultwelcome/welcome_it.md
+++ b/defaultwelcome/welcome_it.md
@@ -1,5 +1,5 @@
-# Benvenuta
-Epicyon è un server ActivityPub progettato per un facile self-hosting di poche persone su sistemi a bassa potenza, come computer a scheda singola o vecchi laptop.
+### Benvenuto in INSTANCE
+Questo è un server ActivityPub progettato per un facile self-hosting di poche persone su sistemi a basso consumo, come computer a scheda singola o vecchi laptop.
Gestisci la tua presenza sui social network come preferisci e saluta Big Tech.
diff --git a/defaultwelcome/welcome_ja.md b/defaultwelcome/welcome_ja.md
index b306ab3dc..7e21a1821 100644
--- a/defaultwelcome/welcome_ja.md
+++ b/defaultwelcome/welcome_ja.md
@@ -1,5 +1,5 @@
-# ようこそ
-Epicyonは、シングルボードコンピューターや古いラップトップなどの低電力システムで数人を簡単にセルフホスティングできるように設計されたActivityPubサーバーです。
+### INSTANCEへようこそ
+これは、シングルボードコンピューターや古いラップトップなどの低電力システムで数人を簡単にセルフホスティングするために設計されたActivityPubサーバーです。
独自のソーシャルネットワークプレゼンスを希望どおりに実行し、BigTechに別れを告げます。
diff --git a/defaultwelcome/welcome_pt.md b/defaultwelcome/welcome_pt.md
index df46bc080..f302f5aec 100644
--- a/defaultwelcome/welcome_pt.md
+++ b/defaultwelcome/welcome_pt.md
@@ -1,5 +1,5 @@
-# Receber
-Epicyon é um servidor ActivityPub projetado para fácil auto-hospedagem de algumas pessoas em sistemas de baixa energia, como computadores de placa única ou laptops antigos.
+# Bem-vindo a INSTANCE
+Este é um servidor ActivityPub projetado para fácil auto-hospedagem de algumas pessoas em sistemas de baixo consumo de energia, como computadores de placa única ou laptops antigos.
Administre sua própria presença na rede social do jeito que você quiser e diga adeus à Big Tech.
diff --git a/defaultwelcome/welcome_ru.md b/defaultwelcome/welcome_ru.md
index 6761a996a..65c82400d 100644
--- a/defaultwelcome/welcome_ru.md
+++ b/defaultwelcome/welcome_ru.md
@@ -1,5 +1,5 @@
-# Добро пожаловать
-Epicyon - это сервер ActivityPub, предназначенный для простого самостоятельного размещения нескольких человек в системах с низким энергопотреблением, таких как одноплатные компьютеры или старые ноутбуки.
+### Добро пожаловать в INSTANCE
+Это сервер ActivityPub, предназначенный для простого самостоятельного размещения нескольких человек в системах с низким энергопотреблением, таких как одноплатные компьютеры или старые ноутбуки.
Управляйте своим присутствием в социальных сетях так, как вы хотите, и попрощайтесь с Big Tech.
diff --git a/defaultwelcome/welcome_zh.md b/defaultwelcome/welcome_zh.md
index 44c642c51..978734e94 100644
--- a/defaultwelcome/welcome_zh.md
+++ b/defaultwelcome/welcome_zh.md
@@ -1,5 +1,5 @@
-# 欢迎
-Epicyon是一个ActivityPub服务器,其设计用于在低功耗系统(例如单板计算机或旧笔记本电脑)上轻松实现一些人的自我托管。
+### 欢迎来到INSTANCE
+这是一个ActivityPub服务器,设计用于在低功耗系统(例如单板计算机或旧笔记本电脑)上轻松实现一些人的自我托管。
随心所欲地经营自己的社交网络,并与Big Tech道别。
From 543fd3816665bbe4e2d2ee49171903883077aa65 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 10:29:50 +0000
Subject: [PATCH 0075/1416] Function to show help text when initial timeline
has no posts in it
---
webapp_timeline.py | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/webapp_timeline.py b/webapp_timeline.py
index 1c3cf7f63..99025d82c 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -8,12 +8,15 @@ __status__ = "Production"
import os
import time
+from shutil import copyfile
+from utils import removeHtml
from utils import getConfigParam
from utils import getFullDomain
from utils import isEditor
from utils import removeIdEnding
from follow import followerApprovalActive
from person import isPersonSnoozed
+from webapp_utils import markdownToHtml
from webapp_utils import htmlKeyboardNavigation
from webapp_utils import htmlHideFromScreenReader
from webapp_utils import htmlPostSeparator
@@ -42,6 +45,36 @@ def _logTimelineTiming(enableTimingLog: bool, timelineStartTime,
boxName + ' ' + debugId + ' = ' + str(timeDiff))
+def _getHelpForTimeline(baseDir: str, boxName: str) -> str:
+ """Shows help text for the given timeline
+ """
+ # get the filename for help for this timeline
+ helpFilename = baseDir + '/accounts/help_' + boxName + '.md'
+ if not os.path.isfile(helpFilename):
+ language = \
+ getConfigParam(baseDir, 'language')
+ defaultFilename = \
+ baseDir + '/defaultwelcome/' + \
+ 'help_' + boxName + '_' + language + '.md'
+ if not os.path.isfile(defaultFilename):
+ defaultFilename = \
+ baseDir + '/defaultwelcome/help_' + boxName + '_en.md'
+ if os.path.isfile(defaultFilename):
+ copyfile(defaultFilename, helpFilename)
+
+ # show help text
+ if os.path.isfile(helpFilename):
+ instanceTitle = \
+ getConfigParam(baseDir, 'instanceTitle')
+ if not instanceTitle:
+ instanceTitle = 'Epicyon'
+ with open(helpFilename, 'r') as helpFile:
+ helpText = helpFile.read()
+ helpText = helpText.replace('INSTANCE', instanceTitle)
+ return markdownToHtml(removeHtml(helpText))
+ return ''
+
+
def htmlTimeline(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int,
@@ -698,6 +731,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
translate['Page down'] + '">\n' + \
' \n'
tlStr += textModeSeparator
+ elif itemCtr == 0:
+ tlStr += _getHelpForTimeline(baseDir, boxName)
# end of timeline-posts
tlStr += ' \n'
From 23da356baf08d9f1811b32252c7ed0c2c3d1e9f4 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 11:15:43 +0000
Subject: [PATCH 0076/1416] Inbox help text
---
defaultwelcome/help_inbox_en.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 defaultwelcome/help_inbox_en.md
diff --git a/defaultwelcome/help_inbox_en.md b/defaultwelcome/help_inbox_en.md
new file mode 100644
index 000000000..31d75c21a
--- /dev/null
+++ b/defaultwelcome/help_inbox_en.md
@@ -0,0 +1,20 @@
+### Middle column
+Incoming posts will appear here, as a chronological timeline.
+
+### 🡱 The top banner 🡱
+At the top of the screen you can select the **banner** to switch to your profile, and edit it or log out.
+
+### 🡱 Timeline buttons and icons 🡱
+The **buttons** below the top banner allow you to select different timelines. There are also **icons** on the right to **search**, view your **calendar** or create **new posts**.
+
+The **show/hide** icon allows more timeline buttons to be shown, along with moderator controls.
+
+### 🡰 Left column 🡰
+Here you can add **useful links**. This only appears on desktop displays or devices with larger screens. It is similar to a *blogroll*. You can only add or edit links if you have an **administrator** or **editor** role.
+
+If you are on mobile then user the **links icon** at the top to read news.
+
+### 🡲 Right column 🡲
+RSS feeds can be added in the right column, known as the *newswire*. This only appears on desktop displays or devices with larger screens. You can only add or edit feeds if you have an **administrator** or **editor** role, and incoming feed items can also be moderated.
+
+If you are on mobile then user the **newswire icon** at the top to read news.
From 8ec20ab79c888ea08aa270871e17d0bffca5b037 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 11:29:57 +0000
Subject: [PATCH 0077/1416] Direct message help text
---
defaultwelcome/help_dm_en.md | 1 +
defaultwelcome/help_inbox_en.md | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
create mode 100644 defaultwelcome/help_dm_en.md
diff --git a/defaultwelcome/help_dm_en.md b/defaultwelcome/help_dm_en.md
new file mode 100644
index 000000000..1846dab1e
--- /dev/null
+++ b/defaultwelcome/help_dm_en.md
@@ -0,0 +1 @@
+Direct messages will appear here, as a chronological timeline.
diff --git a/defaultwelcome/help_inbox_en.md b/defaultwelcome/help_inbox_en.md
index 31d75c21a..d864646f8 100644
--- a/defaultwelcome/help_inbox_en.md
+++ b/defaultwelcome/help_inbox_en.md
@@ -1,5 +1,5 @@
### Middle column
-Incoming posts will appear here, as a chronological timeline.
+Incoming posts will appear here, as a chronological timeline. If you send any posts they will also appear here.
### 🡱 The top banner 🡱
At the top of the screen you can select the **banner** to switch to your profile, and edit it or log out.
@@ -15,6 +15,6 @@ Here you can add **useful links**. This only appears on desktop displays or devi
If you are on mobile then user the **links icon** at the top to read news.
### 🡲 Right column 🡲
-RSS feeds can be added in the right column, known as the *newswire*. This only appears on desktop displays or devices with larger screens. You can only add or edit feeds if you have an **administrator** or **editor** role, and incoming feed items can also be moderated.
+**RSS feeds** can be added in the right column, known as the *newswire*. This only appears on desktop displays or devices with larger screens. You can only add or edit feeds if you have an **administrator** or **editor** role, and incoming feed items can also be moderated.
If you are on mobile then user the **newswire icon** at the top to read news.
From 52a9e7d0bbd2610c31d7fcf989337c27f1b50ae7 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 11:32:15 +0000
Subject: [PATCH 0078/1416] Outbox help text
---
defaultwelcome/help_outbox_en.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 defaultwelcome/help_outbox_en.md
diff --git a/defaultwelcome/help_outbox_en.md b/defaultwelcome/help_outbox_en.md
new file mode 100644
index 000000000..7651570d6
--- /dev/null
+++ b/defaultwelcome/help_outbox_en.md
@@ -0,0 +1 @@
+Your sent posts will appear here, as a cronological timeline.
From 6265da8661494fb1fb74e5f9ed5d212ca664b359 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 11:34:34 +0000
Subject: [PATCH 0079/1416] Media timeline help text
---
defaultwelcome/help_tlmedia_en.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 defaultwelcome/help_tlmedia_en.md
diff --git a/defaultwelcome/help_tlmedia_en.md b/defaultwelcome/help_tlmedia_en.md
new file mode 100644
index 000000000..b5daee390
--- /dev/null
+++ b/defaultwelcome/help_tlmedia_en.md
@@ -0,0 +1 @@
+Any incoming posts which contain **images**, **video** or **audio** files will appear here, together with their descriptions.
From 8b2d2db8d1a598f716472fda3b9f0bd6cfcff4a8 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 11:58:58 +0000
Subject: [PATCH 0080/1416] Shares timeline help text
---
defaultwelcome/help_tlshares_en.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 defaultwelcome/help_tlshares_en.md
diff --git a/defaultwelcome/help_tlshares_en.md b/defaultwelcome/help_tlshares_en.md
new file mode 100644
index 000000000..75f2364e8
--- /dev/null
+++ b/defaultwelcome/help_tlshares_en.md
@@ -0,0 +1,4 @@
+## Shared items
+Shared items are typically physical objects or local services, exchanged or given away without use of money.
+
+For example, you may want to share **equipment** between members of a sports team on the same instance, share any surplus **clothing**, share **gadgets** which you are no longer using, or share plants and gardening **tools** between people using the same growing space.
From 3eca92d4512c7e8b04c12e0e4cba034adbdd14f7 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:04:01 +0000
Subject: [PATCH 0081/1416] Shared items
---
defaultwelcome/help_tlshares_en.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/defaultwelcome/help_tlshares_en.md b/defaultwelcome/help_tlshares_en.md
index 75f2364e8..840af66da 100644
--- a/defaultwelcome/help_tlshares_en.md
+++ b/defaultwelcome/help_tlshares_en.md
@@ -2,3 +2,5 @@
Shared items are typically physical objects or local services, exchanged or given away without use of money.
For example, you may want to share **equipment** between members of a sports team on the same instance, share any surplus **clothing**, share **gadgets** which you are no longer using, or share plants and gardening **tools** between people using the same growing space.
+
+In order to avoid spam, shared items are not federated via ActivityPub and are local to members on the same instance.
From f0d6218beafd0eadad2c23825b3a4ed6a1ac1db4 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:04:58 +0000
Subject: [PATCH 0082/1416] Help text for bookmarks
---
defaultwelcome/help_tlbookmarks_en.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 defaultwelcome/help_tlbookmarks_en.md
diff --git a/defaultwelcome/help_tlbookmarks_en.md b/defaultwelcome/help_tlbookmarks_en.md
new file mode 100644
index 000000000..829c860dc
--- /dev/null
+++ b/defaultwelcome/help_tlbookmarks_en.md
@@ -0,0 +1 @@
+Any bookmarked posts appear here.
From 78fd05a5d6324bc9aef947b236ad2e7df62421de Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:05:27 +0000
Subject: [PATCH 0083/1416] More concise
---
defaultwelcome/help_tlshares_en.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/defaultwelcome/help_tlshares_en.md b/defaultwelcome/help_tlshares_en.md
index 840af66da..d3b7bed72 100644
--- a/defaultwelcome/help_tlshares_en.md
+++ b/defaultwelcome/help_tlshares_en.md
@@ -3,4 +3,4 @@ Shared items are typically physical objects or local services, exchanged or give
For example, you may want to share **equipment** between members of a sports team on the same instance, share any surplus **clothing**, share **gadgets** which you are no longer using, or share plants and gardening **tools** between people using the same growing space.
-In order to avoid spam, shared items are not federated via ActivityPub and are local to members on the same instance.
+To avoid spam, shared items are not federated via ActivityPub and are local to members on the same instance.
From 8e8e9f8a452149674799cda843c2a47feee07d13 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:06:20 +0000
Subject: [PATCH 0084/1416] Header style
---
defaultwelcome/help_tlshares_en.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/defaultwelcome/help_tlshares_en.md b/defaultwelcome/help_tlshares_en.md
index d3b7bed72..af9975e05 100644
--- a/defaultwelcome/help_tlshares_en.md
+++ b/defaultwelcome/help_tlshares_en.md
@@ -1,4 +1,4 @@
-## Shared items
+### Shared items
Shared items are typically physical objects or local services, exchanged or given away without use of money.
For example, you may want to share **equipment** between members of a sports team on the same instance, share any surplus **clothing**, share **gadgets** which you are no longer using, or share plants and gardening **tools** between people using the same growing space.
From 47d5ff89dc45f71c1271842ac08838efc7a0b378 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:06:50 +0000
Subject: [PATCH 0085/1416] More concise
---
defaultwelcome/help_tlshares_en.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/defaultwelcome/help_tlshares_en.md b/defaultwelcome/help_tlshares_en.md
index af9975e05..e984d407c 100644
--- a/defaultwelcome/help_tlshares_en.md
+++ b/defaultwelcome/help_tlshares_en.md
@@ -1,5 +1,5 @@
### Shared items
-Shared items are typically physical objects or local services, exchanged or given away without use of money.
+These are typically physical objects or local services, exchanged or given away without use of money.
For example, you may want to share **equipment** between members of a sports team on the same instance, share any surplus **clothing**, share **gadgets** which you are no longer using, or share plants and gardening **tools** between people using the same growing space.
From f3d035a6daed57a808991166380c4213bd4119dc Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:24:55 +0000
Subject: [PATCH 0086/1416] Default language
---
webapp_timeline.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/webapp_timeline.py b/webapp_timeline.py
index 99025d82c..ccf5a7a85 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -53,6 +53,8 @@ def _getHelpForTimeline(baseDir: str, boxName: str) -> str:
if not os.path.isfile(helpFilename):
language = \
getConfigParam(baseDir, 'language')
+ if not language:
+ language = 'en'
defaultFilename = \
baseDir + '/defaultwelcome/' + \
'help_' + boxName + '_' + language + '.md'
From 39ca550503916de460cdc36218dd8223dd3cd111 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:29:42 +0000
Subject: [PATCH 0087/1416] Container for help text
---
defaultwelcome/help_inbox_en.md | 2 +-
webapp_timeline.py | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/defaultwelcome/help_inbox_en.md b/defaultwelcome/help_inbox_en.md
index d864646f8..d7ca2e813 100644
--- a/defaultwelcome/help_inbox_en.md
+++ b/defaultwelcome/help_inbox_en.md
@@ -15,6 +15,6 @@ Here you can add **useful links**. This only appears on desktop displays or devi
If you are on mobile then user the **links icon** at the top to read news.
### 🡲 Right column 🡲
-**RSS feeds** can be added in the right column, known as the *newswire*. This only appears on desktop displays or devices with larger screens. You can only add or edit feeds if you have an **administrator** or **editor** role, and incoming feed items can also be moderated.
+RSS feeds can be added in the right column, known as the *newswire*. This only appears on desktop displays or devices with larger screens. You can only add or edit feeds if you have an **administrator** or **editor** role, and incoming feed items can also be moderated.
If you are on mobile then user the **newswire icon** at the top to read news.
diff --git a/webapp_timeline.py b/webapp_timeline.py
index ccf5a7a85..b6b9bacd8 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -73,7 +73,9 @@ def _getHelpForTimeline(baseDir: str, boxName: str) -> str:
with open(helpFilename, 'r') as helpFile:
helpText = helpFile.read()
helpText = helpText.replace('INSTANCE', instanceTitle)
- return markdownToHtml(removeHtml(helpText))
+ return '\n' + \
+ markdownToHtml(removeHtml(helpText)) + \
+ '<\div>\n'
return ''
From 9caf332e51099f3783c639fe3c757b1fda5aa3b5 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:37:02 +0000
Subject: [PATCH 0088/1416] Section endings
---
webapp_timeline.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/webapp_timeline.py b/webapp_timeline.py
index b6b9bacd8..2b44add0c 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -738,11 +738,12 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
elif itemCtr == 0:
tlStr += _getHelpForTimeline(baseDir, boxName)
- # end of timeline-posts
- tlStr += '
\n'
+ if itemCtr > 0:
+ # end of timeline-posts
+ tlStr += ' \n'
- # end of column-center
- tlStr += ' \n'
+ # end of column-center
+ tlStr += ' \n'
# right column
rightColumnStr = getRightColumnContent(baseDir, nickname, domainFull,
From ee9a8cad48b7abaa4b8d5c3b5c5282e16b687e04 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:38:13 +0000
Subject: [PATCH 0089/1416] Section endings
---
webapp_timeline.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/webapp_timeline.py b/webapp_timeline.py
index 2b44add0c..ab6043912 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -738,10 +738,10 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
elif itemCtr == 0:
tlStr += _getHelpForTimeline(baseDir, boxName)
- if itemCtr > 0:
- # end of timeline-posts
- tlStr += ' \n'
+ # end of timeline-posts
+ tlStr += ' \n'
+ if itemCtr > 0:
# end of column-center
tlStr += ' \n'
From e541a03a591ae82eed0851b9bab1fac9cbd1751e Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:41:09 +0000
Subject: [PATCH 0090/1416] Newline
---
webapp_timeline.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/webapp_timeline.py b/webapp_timeline.py
index ab6043912..e1f1fd322 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -74,7 +74,7 @@ def _getHelpForTimeline(baseDir: str, boxName: str) -> str:
helpText = helpFile.read()
helpText = helpText.replace('INSTANCE', instanceTitle)
return '\n' + \
- markdownToHtml(removeHtml(helpText)) + \
+ markdownToHtml(removeHtml(helpText)) + '\n' + \
'<\div>\n'
return ''
@@ -741,9 +741,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
# end of timeline-posts
tlStr += '
\n'
- if itemCtr > 0:
- # end of column-center
- tlStr += ' \n'
+ # end of column-center
+ tlStr += ' \n'
# right column
rightColumnStr = getRightColumnContent(baseDir, nickname, domainFull,
From 993ae3141e39f54c9344234df53500e43183dc5e Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:42:29 +0000
Subject: [PATCH 0091/1416] Slash
---
webapp_timeline.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/webapp_timeline.py b/webapp_timeline.py
index e1f1fd322..4022382c6 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -75,7 +75,7 @@ def _getHelpForTimeline(baseDir: str, boxName: str) -> str:
helpText = helpText.replace('INSTANCE', instanceTitle)
return '\n' + \
markdownToHtml(removeHtml(helpText)) + '\n' + \
- '<\div>\n'
+ '
\n'
return ''
From a85e6cb2236bfac2b4dff030a586173f68e06fb2 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:44:37 +0000
Subject: [PATCH 0092/1416] Don't use unicode emoji in help text
---
defaultwelcome/help_inbox_en.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/defaultwelcome/help_inbox_en.md b/defaultwelcome/help_inbox_en.md
index d7ca2e813..2ae21843f 100644
--- a/defaultwelcome/help_inbox_en.md
+++ b/defaultwelcome/help_inbox_en.md
@@ -1,20 +1,20 @@
### Middle column
Incoming posts will appear here, as a chronological timeline. If you send any posts they will also appear here.
-### 🡱 The top banner 🡱
+### The top banner
At the top of the screen you can select the **banner** to switch to your profile, and edit it or log out.
-### 🡱 Timeline buttons and icons 🡱
+### Timeline buttons and icons
The **buttons** below the top banner allow you to select different timelines. There are also **icons** on the right to **search**, view your **calendar** or create **new posts**.
The **show/hide** icon allows more timeline buttons to be shown, along with moderator controls.
-### 🡰 Left column 🡰
+### <- Left column
Here you can add **useful links**. This only appears on desktop displays or devices with larger screens. It is similar to a *blogroll*. You can only add or edit links if you have an **administrator** or **editor** role.
If you are on mobile then user the **links icon** at the top to read news.
-### 🡲 Right column 🡲
+### Right column ->
RSS feeds can be added in the right column, known as the *newswire*. This only appears on desktop displays or devices with larger screens. You can only add or edit feeds if you have an **administrator** or **editor** role, and incoming feed items can also be moderated.
If you are on mobile then user the **newswire icon** at the top to read news.
From 2335ef30d4d701b3abc6df8c10d3be9bfd741bc4 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:46:06 +0000
Subject: [PATCH 0093/1416] No html-like characters
---
defaultwelcome/help_inbox_en.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/defaultwelcome/help_inbox_en.md b/defaultwelcome/help_inbox_en.md
index 2ae21843f..64eedba69 100644
--- a/defaultwelcome/help_inbox_en.md
+++ b/defaultwelcome/help_inbox_en.md
@@ -9,12 +9,12 @@ The **buttons** below the top banner allow you to select different timelines. Th
The **show/hide** icon allows more timeline buttons to be shown, along with moderator controls.
-### <- Left column
+### Left column
Here you can add **useful links**. This only appears on desktop displays or devices with larger screens. It is similar to a *blogroll*. You can only add or edit links if you have an **administrator** or **editor** role.
If you are on mobile then user the **links icon** at the top to read news.
-### Right column ->
+### Right column
RSS feeds can be added in the right column, known as the *newswire*. This only appears on desktop displays or devices with larger screens. You can only add or edit feeds if you have an **administrator** or **editor** role, and incoming feed items can also be moderated.
If you are on mobile then user the **newswire icon** at the top to read news.
From 2bb116ceed9716f1e7a1983935906fe2d4e9e72a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:48:20 +0000
Subject: [PATCH 0094/1416] No initial title
---
defaultwelcome/help_inbox_en.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/defaultwelcome/help_inbox_en.md b/defaultwelcome/help_inbox_en.md
index 64eedba69..23555331f 100644
--- a/defaultwelcome/help_inbox_en.md
+++ b/defaultwelcome/help_inbox_en.md
@@ -1,4 +1,3 @@
-### Middle column
Incoming posts will appear here, as a chronological timeline. If you send any posts they will also appear here.
### The top banner
From 51ff0fb438a77d45c87e6a7ae632676930fc41fa Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 12:58:29 +0000
Subject: [PATCH 0095/1416] Don't remove html, but check for dangerous markup
---
webapp_timeline.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/webapp_timeline.py b/webapp_timeline.py
index 4022382c6..a1f4e2fb0 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -9,7 +9,7 @@ __status__ = "Production"
import os
import time
from shutil import copyfile
-from utils import removeHtml
+from utils import dangerousMarkup
from utils import getConfigParam
from utils import getFullDomain
from utils import isEditor
@@ -72,9 +72,11 @@ def _getHelpForTimeline(baseDir: str, boxName: str) -> str:
instanceTitle = 'Epicyon'
with open(helpFilename, 'r') as helpFile:
helpText = helpFile.read()
+ if dangerousMarkup(helpText, False):
+ return ''
helpText = helpText.replace('INSTANCE', instanceTitle)
return '\n' + \
- markdownToHtml(removeHtml(helpText)) + '\n' + \
+ markdownToHtml(helpText) + '\n' + \
'
\n'
return ''
From 4b3c5792659a19e3da49c32e1f69967d2634afd2 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 13:11:11 +0000
Subject: [PATCH 0096/1416] Use
---
defaultwelcome/help_inbox_en.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/defaultwelcome/help_inbox_en.md b/defaultwelcome/help_inbox_en.md
index 23555331f..82b95bb05 100644
--- a/defaultwelcome/help_inbox_en.md
+++ b/defaultwelcome/help_inbox_en.md
@@ -11,9 +11,9 @@ The **show/hide** icon allows more timeline buttons to be shown, along with mode
### Left column
Here you can add **useful links**. This only appears on desktop displays or devices with larger screens. It is similar to a *blogroll*. You can only add or edit links if you have an **administrator** or **editor** role.
-If you are on mobile then user the **links icon** at the top to read news.
+If you are on mobile then use the **links icon** at the top to read news.
### Right column
RSS feeds can be added in the right column, known as the *newswire*. This only appears on desktop displays or devices with larger screens. You can only add or edit feeds if you have an **administrator** or **editor** role, and incoming feed items can also be moderated.
-If you are on mobile then user the **newswire icon** at the top to read news.
+If you are on mobile then use the **newswire icon** at the top to read news.
From 94f0e48072f6d1b780b3de0ce9ea7c4b484bee62 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 13:31:31 +0000
Subject: [PATCH 0097/1416] Show help on shares timeline
---
webapp_timeline.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/webapp_timeline.py b/webapp_timeline.py
index a1f4e2fb0..cf0e17719 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -829,6 +829,7 @@ def _htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int,
' \n'
separatorStr = htmlPostSeparator(baseDir, None)
+ ctr = 0
for published, item in sharesJson.items():
showContactButton = False
if item['actor'] != actor:
@@ -840,6 +841,10 @@ def _htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int,
htmlIndividualShare(actor, item, translate,
showContactButton, showRemoveButton)
timelineStr += separatorStr
+ ctr += 1
+
+ if ctr == 0:
+ timelineStr += _getHelpForTimeline(baseDir, 'tlshares')
if not lastPage:
timelineStr += \
From 19908a73c45dce80cebac07a10becd9c1bb52753 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 13:38:55 +0000
Subject: [PATCH 0098/1416] Mention dm policy
---
defaultwelcome/help_dm_en.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/defaultwelcome/help_dm_en.md b/defaultwelcome/help_dm_en.md
index 1846dab1e..2f58489bf 100644
--- a/defaultwelcome/help_dm_en.md
+++ b/defaultwelcome/help_dm_en.md
@@ -1 +1,3 @@
Direct messages will appear here, as a chronological timeline.
+
+To avoid spam and improve security, by default you will only be able to receive direct messages *from people that you're following*. You can turn this off within your profile settings if you need to, by selecting the top **banner** and then the **edit** icon.
From 786a3f79e35bfb53ac051cf1f9fc4cce48f7b643 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 14:01:42 +0000
Subject: [PATCH 0099/1416] Ensure that default settings are preserved during
the welcome screen sequence
---
daemon.py | 70 ++++++++++++++++++++++++++++++++++---------------------
1 file changed, 43 insertions(+), 27 deletions(-)
diff --git a/daemon.py b/daemon.py
index 3008469f4..81820505b 100644
--- a/daemon.py
+++ b/daemon.py
@@ -4717,15 +4717,20 @@ class PubServer(BaseHTTPRequestHandler):
nickname, domain)
# approve followers
- approveFollowers = False
- if fields.get('approveFollowers'):
- if fields['approveFollowers'] == 'on':
- approveFollowers = True
- if approveFollowers != \
- actorJson['manuallyApprovesFollowers']:
- actorJson['manuallyApprovesFollowers'] = \
- approveFollowers
+ if checkNameAndBio:
+ # Default setting created via the welcome screen
+ actorJson['manuallyApprovesFollowers'] = True
actorChanged = True
+ else:
+ approveFollowers = False
+ if fields.get('approveFollowers'):
+ if fields['approveFollowers'] == 'on':
+ approveFollowers = True
+ if approveFollowers != \
+ actorJson['manuallyApprovesFollowers']:
+ actorJson['manuallyApprovesFollowers'] = \
+ approveFollowers
+ actorChanged = True
# remove a custom font
if fields.get('removeCustomFont'):
@@ -4773,15 +4778,21 @@ class PubServer(BaseHTTPRequestHandler):
baseDir + '/accounts/' + \
nickname + '@' + domain + \
'/.followDMs'
- followDMsActive = False
- if fields.get('followDMs'):
- if fields['followDMs'] == 'on':
- followDMsActive = True
- with open(followDMsFilename, 'w+') as fFile:
- fFile.write('\n')
- if not followDMsActive:
- if os.path.isfile(followDMsFilename):
- os.remove(followDMsFilename)
+ if checkNameAndBio:
+ # initial default setting created via
+ # the welcome screen
+ with open(followDMsFilename, 'w+') as fFile:
+ fFile.write('\n')
+ else:
+ followDMsActive = False
+ if fields.get('followDMs'):
+ if fields['followDMs'] == 'on':
+ followDMsActive = True
+ with open(followDMsFilename, 'w+') as fFile:
+ fFile.write('\n')
+ if not followDMsActive:
+ if os.path.isfile(followDMsFilename):
+ os.remove(followDMsFilename)
# remove Twitter retweets
removeTwitterFilename = \
@@ -4822,16 +4833,21 @@ class PubServer(BaseHTTPRequestHandler):
os.remove(hideLikeButtonFile)
# notify about new Likes
- notifyLikesActive = False
- if fields.get('notifyLikes'):
- if fields['notifyLikes'] == 'on' and \
- not hideLikeButtonActive:
- notifyLikesActive = True
- with open(notifyLikesFilename, 'w+') as rFile:
- rFile.write('\n')
- if not notifyLikesActive:
- if os.path.isfile(notifyLikesFilename):
- os.remove(notifyLikesFilename)
+ if checkNameAndBio:
+ # default setting from welcome screen
+ with open(notifyLikesFilename, 'w+') as rFile:
+ rFile.write('\n')
+ else:
+ notifyLikesActive = False
+ if fields.get('notifyLikes'):
+ if fields['notifyLikes'] == 'on' and \
+ not hideLikeButtonActive:
+ notifyLikesActive = True
+ with open(notifyLikesFilename, 'w+') as rFile:
+ rFile.write('\n')
+ if not notifyLikesActive:
+ if os.path.isfile(notifyLikesFilename):
+ os.remove(notifyLikesFilename)
# this account is a bot
if fields.get('isBot'):
From 43e3a70d1ec916cbe75be261a26e17d6c5298b01 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 14:09:51 +0000
Subject: [PATCH 0100/1416] Preserve default after welcome screen
---
daemon.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/daemon.py b/daemon.py
index 81820505b..729b7eafd 100644
--- a/daemon.py
+++ b/daemon.py
@@ -4050,6 +4050,7 @@ class PubServer(BaseHTTPRequestHandler):
postBytesStr = postBytes.decode('utf-8')
redirectPath = ''
checkNameAndBio = False
+ onFinalWelcomeScreen = False
if 'name="previewAvatar"' in postBytesStr:
redirectPath = '/welcome_profile'
elif 'name="initialWelcomeScreen"' in postBytesStr:
@@ -4061,6 +4062,7 @@ class PubServer(BaseHTTPRequestHandler):
redirectPath = '/' + self.server.defaultTimeline
welcomeScreenIsComplete(self.server.baseDir, nickname,
self.server.domain)
+ onFinalWelcomeScreen = True
# extract all of the text fields into a dict
fields = \
@@ -4717,7 +4719,7 @@ class PubServer(BaseHTTPRequestHandler):
nickname, domain)
# approve followers
- if checkNameAndBio:
+ if onFinalWelcomeScreen:
# Default setting created via the welcome screen
actorJson['manuallyApprovesFollowers'] = True
actorChanged = True
@@ -4778,11 +4780,12 @@ class PubServer(BaseHTTPRequestHandler):
baseDir + '/accounts/' + \
nickname + '@' + domain + \
'/.followDMs'
- if checkNameAndBio:
+ if onFinalWelcomeScreen:
# initial default setting created via
# the welcome screen
with open(followDMsFilename, 'w+') as fFile:
fFile.write('\n')
+ actorChanged = True
else:
followDMsActive = False
if fields.get('followDMs'):
@@ -4833,10 +4836,11 @@ class PubServer(BaseHTTPRequestHandler):
os.remove(hideLikeButtonFile)
# notify about new Likes
- if checkNameAndBio:
+ if onFinalWelcomeScreen:
# default setting from welcome screen
with open(notifyLikesFilename, 'w+') as rFile:
rFile.write('\n')
+ actorChanged = True
else:
notifyLikesActive = False
if fields.get('notifyLikes'):
From 7dbaaa267acf51a1fbae79bfd30973053c3b7c0a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 15:20:43 +0000
Subject: [PATCH 0101/1416] Support for markdown images
---
tests.py | 6 ++++--
webapp_utils.py | 44 +++++++++++++++++++++++++++++++-------------
2 files changed, 35 insertions(+), 15 deletions(-)
diff --git a/tests.py b/tests.py
index ddab940d4..9fee74c7d 100644
--- a/tests.py
+++ b/tests.py
@@ -3306,14 +3306,16 @@ def testMarkdownToHtml():
markdown = \
'This is [a link](https://something.somewhere) to something.\n' + \
- 'And [something else](https://cat.pic).'
+ 'And [something else](https://cat.pic).\n' + \
+ 'Or .'
assert markdownToHtml(markdown) == \
'This is ' + \
'a link to something. ' + \
'And ' + \
- 'something else .'
+ 'something else. ' + \
+ 'Or .'
def runAllTests():
diff --git a/webapp_utils.py b/webapp_utils.py
index 5c3983bc2..b8519bb90 100644
--- a/webapp_utils.py
+++ b/webapp_utils.py
@@ -66,31 +66,49 @@ def _markdownEmphasisHtml(markdown: str) -> str:
return markdown
-def markdownToHtml(markdown: str) -> str:
- """Converts markdown formatted text to html
+def _markdownReplaceLinks(markdown: str, images=False) -> str:
+ """Replaces markdown links with html
"""
- markdown = _markdownEmphasisHtml(markdown)
- # replace markdown style links with html links
replaceLinks = {}
text = markdown
- while '[' in text:
+ startChars = '['
+ if images:
+ startChars = '!['
+ while startChars in text:
if ')' not in text:
break
- text = text.split('[', 1)[1]
- markdownLink = '[' + text.split(')')[0] + ')'
+ text = text.split(startChars, 1)[1]
+ markdownLink = startChars + text.split(')')[0] + ')'
if ']' not in markdownLink or \
'(' not in markdownLink:
text = text.split(')', 1)[1]
continue
- replaceLinks[markdownLink] = \
- '' + \
- markdownLink.split('[')[1].split(']')[0] + \
- ' '
+ if not images:
+ replaceLinks[markdownLink] = \
+ '' + \
+ markdownLink.split(startChars)[1].split(']')[0] + \
+ ' '
+ else:
+ replaceLinks[markdownLink] = \
+ ' '
text = text.split(')', 1)[1]
for mdLink, htmlLink in replaceLinks.items():
markdown = markdown.replace(mdLink, htmlLink)
+ return markdown
+
+
+def markdownToHtml(markdown: str) -> str:
+ """Converts markdown formatted text to html
+ """
+ markdown = _markdownEmphasisHtml(markdown)
+ markdown = _markdownReplaceLinks(markdown, True)
+ markdown = _markdownReplaceLinks(markdown)
# replace headers
linesList = markdown.split('\n')
From e751eecf1eaef98a28e59eedeafba56deea77221 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 16:02:31 +0000
Subject: [PATCH 0102/1416] Less indentation
---
daemon.py | 109 ++++++++++++++++++++++++++++--------------------------
1 file changed, 56 insertions(+), 53 deletions(-)
diff --git a/daemon.py b/daemon.py
index 729b7eafd..ad9626272 100644
--- a/daemon.py
+++ b/daemon.py
@@ -9776,59 +9776,62 @@ class PubServer(BaseHTTPRequestHandler):
GETstartTime, GETtimings: {}) -> bool:
"""Shows an avatar or banner or profile background image
"""
- if '/users/' in path:
- if self._pathIsImage(path):
- avatarStr = path.split('/users/')[1]
- if '/' in avatarStr and '.temp.' not in path:
- avatarNickname = avatarStr.split('/')[0]
- avatarFile = avatarStr.split('/')[1]
- avatarFileExt = avatarFile.split('.')[-1]
- # remove any numbers, eg. avatar123.png becomes avatar.png
- if avatarFile.startswith('avatar'):
- avatarFile = 'avatar.' + avatarFileExt
- elif avatarFile.startswith('banner'):
- avatarFile = 'banner.' + avatarFileExt
- elif avatarFile.startswith('search_banner'):
- avatarFile = 'search_banner.' + avatarFileExt
- elif avatarFile.startswith('image'):
- avatarFile = 'image.' + avatarFileExt
- elif avatarFile.startswith('left_col_image'):
- avatarFile = 'left_col_image.' + avatarFileExt
- elif avatarFile.startswith('right_col_image'):
- avatarFile = 'right_col_image.' + avatarFileExt
- avatarFilename = \
- baseDir + '/accounts/' + \
- avatarNickname + '@' + domain + '/' + avatarFile
- if os.path.isfile(avatarFilename):
- if self._etag_exists(avatarFilename):
- # The file has not changed
- self._304()
- return True
- mediaImageType = 'png'
- if avatarFile.endswith('.png'):
- mediaImageType = 'png'
- elif avatarFile.endswith('.jpg'):
- mediaImageType = 'jpeg'
- elif avatarFile.endswith('.gif'):
- mediaImageType = 'gif'
- elif avatarFile.endswith('.avif'):
- mediaImageType = 'avif'
- elif avatarFile.endswith('.svg'):
- mediaImageType = 'svg+xml'
- else:
- mediaImageType = 'webp'
- with open(avatarFilename, 'rb') as avFile:
- mediaBinary = avFile.read()
- self._set_headers_etag(avatarFilename,
- 'image/' + mediaImageType,
- mediaBinary, None,
- self.server.domainFull)
- self._write(mediaBinary)
- self._benchmarkGETtimings(GETstartTime, GETtimings,
- 'icon shown done',
- 'avatar background shown')
- return True
- return False
+ if '/users/' not in path:
+ return False
+ if not self._pathIsImage(path):
+ return False
+ avatarStr = path.split('/users/')[1]
+ if not ('/' in avatarStr and '.temp.' not in path):
+ return False
+ avatarNickname = avatarStr.split('/')[0]
+ avatarFile = avatarStr.split('/')[1]
+ avatarFileExt = avatarFile.split('.')[-1]
+ # remove any numbers, eg. avatar123.png becomes avatar.png
+ if avatarFile.startswith('avatar'):
+ avatarFile = 'avatar.' + avatarFileExt
+ elif avatarFile.startswith('banner'):
+ avatarFile = 'banner.' + avatarFileExt
+ elif avatarFile.startswith('search_banner'):
+ avatarFile = 'search_banner.' + avatarFileExt
+ elif avatarFile.startswith('image'):
+ avatarFile = 'image.' + avatarFileExt
+ elif avatarFile.startswith('left_col_image'):
+ avatarFile = 'left_col_image.' + avatarFileExt
+ elif avatarFile.startswith('right_col_image'):
+ avatarFile = 'right_col_image.' + avatarFileExt
+ avatarFilename = \
+ baseDir + '/accounts/' + \
+ avatarNickname + '@' + domain + '/' + avatarFile
+ if not os.path.isfile(avatarFilename):
+ return False
+ if self._etag_exists(avatarFilename):
+ # The file has not changed
+ self._304()
+ return True
+ mediaImageType = 'png'
+ if avatarFile.endswith('.png'):
+ mediaImageType = 'png'
+ elif avatarFile.endswith('.jpg'):
+ mediaImageType = 'jpeg'
+ elif avatarFile.endswith('.gif'):
+ mediaImageType = 'gif'
+ elif avatarFile.endswith('.avif'):
+ mediaImageType = 'avif'
+ elif avatarFile.endswith('.svg'):
+ mediaImageType = 'svg+xml'
+ else:
+ mediaImageType = 'webp'
+ with open(avatarFilename, 'rb') as avFile:
+ mediaBinary = avFile.read()
+ self._set_headers_etag(avatarFilename,
+ 'image/' + mediaImageType,
+ mediaBinary, None,
+ self.server.domainFull)
+ self._write(mediaBinary)
+ self._benchmarkGETtimings(GETstartTime, GETtimings,
+ 'icon shown done',
+ 'avatar background shown')
+ return True
def _confirmDeleteEvent(self, callingDomain: str, path: str,
baseDir: str, httpPrefix: str, cookie: str,
From f393e78b14e5260ac08942a57f3e3373255e881d Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 16:06:25 +0000
Subject: [PATCH 0103/1416] Less indentation
---
daemon.py | 72 +++++++++++++++++++++++++++++--------------------------
1 file changed, 38 insertions(+), 34 deletions(-)
diff --git a/daemon.py b/daemon.py
index ad9626272..8f961b01a 100644
--- a/daemon.py
+++ b/daemon.py
@@ -9734,41 +9734,45 @@ class PubServer(BaseHTTPRequestHandler):
GETstartTime, GETtimings: {}) -> bool:
"""Show a shared item image
"""
- if self._pathIsImage(path):
- mediaStr = path.split('/sharefiles/')[1]
- mediaFilename = \
- baseDir + '/sharefiles/' + mediaStr
- if os.path.isfile(mediaFilename):
- if self._etag_exists(mediaFilename):
- # The file has not changed
- self._304()
- return True
+ if not self._pathIsImage(path):
+ self._404()
+ return True
- mediaFileType = 'png'
- if mediaFilename.endswith('.png'):
- mediaFileType = 'png'
- elif mediaFilename.endswith('.jpg'):
- mediaFileType = 'jpeg'
- elif mediaFilename.endswith('.webp'):
- mediaFileType = 'webp'
- elif mediaFilename.endswith('.avif'):
- mediaFileType = 'avif'
- elif mediaFilename.endswith('.svg'):
- mediaFileType = 'svg+xml'
- else:
- mediaFileType = 'gif'
- with open(mediaFilename, 'rb') as avFile:
- mediaBinary = avFile.read()
- self._set_headers_etag(mediaFilename,
- 'image/' + mediaFileType,
- mediaBinary, None,
- self.server.domainFull)
- self._write(mediaBinary)
- self._benchmarkGETtimings(GETstartTime, GETtimings,
- 'show media done',
- 'share files shown')
- return True
- self._404()
+ mediaStr = path.split('/sharefiles/')[1]
+ mediaFilename = \
+ baseDir + '/sharefiles/' + mediaStr
+ if not os.path.isfile(mediaFilename):
+ self._404()
+ return True
+
+ if self._etag_exists(mediaFilename):
+ # The file has not changed
+ self._304()
+ return True
+
+ mediaFileType = 'png'
+ if mediaFilename.endswith('.png'):
+ mediaFileType = 'png'
+ elif mediaFilename.endswith('.jpg'):
+ mediaFileType = 'jpeg'
+ elif mediaFilename.endswith('.webp'):
+ mediaFileType = 'webp'
+ elif mediaFilename.endswith('.avif'):
+ mediaFileType = 'avif'
+ elif mediaFilename.endswith('.svg'):
+ mediaFileType = 'svg+xml'
+ else:
+ mediaFileType = 'gif'
+ with open(mediaFilename, 'rb') as avFile:
+ mediaBinary = avFile.read()
+ self._set_headers_etag(mediaFilename,
+ 'image/' + mediaFileType,
+ mediaBinary, None,
+ self.server.domainFull)
+ self._write(mediaBinary)
+ self._benchmarkGETtimings(GETstartTime, GETtimings,
+ 'show media done',
+ 'share files shown')
return True
def _showAvatarOrBanner(self, callingDomain: str, path: str,
From f75ca8fcaf62ce6ea2f777ad5b95dd0128ab5c41 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 16:07:18 +0000
Subject: [PATCH 0104/1416] Welcome screen background
---
daemon.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon.py b/daemon.py
index 8f961b01a..68b87e7eb 100644
--- a/daemon.py
+++ b/daemon.py
@@ -9689,7 +9689,7 @@ class PubServer(BaseHTTPRequestHandler):
"""
imageExtensions = getImageExtensions()
for ext in imageExtensions:
- for bg in ('follow', 'options', 'login'):
+ for bg in ('follow', 'options', 'login', 'welcome'):
# follow screen background image
if path.endswith('/' + bg + '-background.' + ext):
bgFilename = \
From f2824118a8ed572ff7227276a0c80ec2e58a0f54 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 16:59:38 +0000
Subject: [PATCH 0105/1416] Function to display help images
---
daemon.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
utils.py | 2 +-
2 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/daemon.py b/daemon.py
index 68b87e7eb..33a83a923 100644
--- a/daemon.py
+++ b/daemon.py
@@ -5771,6 +5771,48 @@ class PubServer(BaseHTTPRequestHandler):
return
self._404()
+ def _showHelpScreenImage(self, callingDomain: str, path: str,
+ baseDir: str,
+ GETstartTime, GETtimings: {}) -> None:
+ """Shows a help screen image
+ """
+ if not path.endswith('.jpg') and \
+ not path.endswith('.png') and \
+ not path.endswith('.webp') and \
+ not path.endswith('.avif') and \
+ not path.endswith('.gif'):
+ return
+ mediaStr = path.split('/helpimages/')[1]
+ if '/' not in mediaStr:
+ if not self.server.themeName:
+ theme = 'default'
+ else:
+ theme = self.server.themeName
+ iconFilename = mediaStr
+ else:
+ theme = mediaStr.split('/')[0]
+ iconFilename = mediaStr.split('/')[1]
+ mediaFilename = \
+ baseDir + '/theme/' + theme + '/helpimages/' + iconFilename
+ if self._etag_exists(mediaFilename):
+ # The file has not changed
+ self._304()
+ return
+ if os.path.isfile(mediaFilename):
+ with open(mediaFilename, 'rb') as avFile:
+ mediaBinary = avFile.read()
+ mimeType = mediaFileMimeType(mediaFilename)
+ self._set_headers_etag(mediaFilename,
+ mimeType,
+ mediaBinary, None,
+ self.server.domainFull)
+ self._write(mediaBinary)
+ self._benchmarkGETtimings(GETstartTime, GETtimings,
+ 'show files done',
+ 'help image shown')
+ return
+ self._404()
+
def _showCachedAvatar(self, callingDomain: str, path: str,
baseDir: str,
GETstartTime, GETtimings: {}) -> None:
@@ -11069,6 +11111,14 @@ class PubServer(BaseHTTPRequestHandler):
GETstartTime, GETtimings)
return
+ # help screen images
+ # Note that this comes before the busy flag to avoid conflicts
+ if self.path.startswith('/helpimages/'):
+ self._showHelpScreenImage(callingDomain, self.path,
+ self.server.baseDir,
+ GETstartTime, GETtimings)
+ return
+
self._benchmarkGETtimings(GETstartTime, GETtimings,
'show files done',
'icon shown done')
diff --git a/utils.py b/utils.py
index 25499145e..b0594c7ae 100644
--- a/utils.py
+++ b/utils.py
@@ -1274,7 +1274,7 @@ def _isReservedName(nickname: str) -> bool:
'accounts', 'channels', 'profile', 'u',
'updates', 'repeat', 'announce',
'shares', 'fonts', 'icons', 'avatars',
- 'welcome')
+ 'welcome', 'helpimages')
if nickname in reservedNames:
return True
return False
From ce4b415023c7c2dd488385cc71c1d3a13d4ca645 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 17:01:32 +0000
Subject: [PATCH 0106/1416] if there is no theme-specific help image then use
the default one
---
daemon.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/daemon.py b/daemon.py
index 33a83a923..f131949a5 100644
--- a/daemon.py
+++ b/daemon.py
@@ -5794,6 +5794,10 @@ class PubServer(BaseHTTPRequestHandler):
iconFilename = mediaStr.split('/')[1]
mediaFilename = \
baseDir + '/theme/' + theme + '/helpimages/' + iconFilename
+ # if there is no theme-specific help image then use the default one
+ if not os.path.isfile(mediaFilename):
+ mediaFilename = \
+ baseDir + '/theme/default/helpimages/' + iconFilename
if self._etag_exists(mediaFilename):
# The file has not changed
self._304()
From 4f0b73969479e454ccc6503b3dc2b5082e95b9c7 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 17:19:16 +0000
Subject: [PATCH 0107/1416] Welcome header image
---
defaultwelcome/welcome_en.md | 1 +
epicyon-profile.css | 4 ++++
theme/default/helpimages/welcome.jpg | Bin 0 -> 30044 bytes
3 files changed, 5 insertions(+)
create mode 100644 theme/default/helpimages/welcome.jpg
diff --git a/defaultwelcome/welcome_en.md b/defaultwelcome/welcome_en.md
index 5d942a9a5..1d1e8935f 100644
--- a/defaultwelcome/welcome_en.md
+++ b/defaultwelcome/welcome_en.md
@@ -1,3 +1,4 @@
+
### Welcome to INSTANCE
This is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops.
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 384c60893..7a8e15501 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -190,6 +190,10 @@ body, html {
color: var(--cw-color);
}
+.markdownImage {
+ width: 100%;
+}
+
.leftColIcons {
width: 100%;
background-color: var(--column-left-color);
diff --git a/theme/default/helpimages/welcome.jpg b/theme/default/helpimages/welcome.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..77e97a3a60f19ab36840ef51420cfd87c9944fe4
GIT binary patch
literal 30044
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
literal 0
HcmV?d00001
From 2ad10b07004d6bfa319a3e1f370faa436f26f97b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 17:38:25 +0000
Subject: [PATCH 0108/1416] Markdown image style
---
epicyon-profile.css | 4 ----
epicyon-welcome.css | 8 ++++++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 7a8e15501..384c60893 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -190,10 +190,6 @@ body, html {
color: var(--cw-color);
}
-.markdownImage {
- width: 100%;
-}
-
.leftColIcons {
width: 100%;
background-color: var(--column-left-color);
diff --git a/epicyon-welcome.css b/epicyon-welcome.css
index 21a2ec8a1..89ccadb2c 100644
--- a/epicyon-welcome.css
+++ b/epicyon-welcome.css
@@ -149,6 +149,10 @@ img.avatar {
width: var(--welcome-avatar-width);
}
+.container img.markdownImage {
+ width: 100%;
+}
+
.container.next {
float: right;
}
@@ -192,7 +196,7 @@ span.psw {
margin: 8px 0;
border: none;
cursor: pointer;
- width: var(--welcome-button-width);
+ width: var(--welcome-button-width);
font-size: var(--welcome-font-size);
font-family: Arial, Helvetica, sans-serif;
}
@@ -232,7 +236,7 @@ span.psw {
margin: 8px 0;
border: none;
cursor: pointer;
- width: var(--welcome-button-width);
+ width: var(--welcome-button-width);
font-size: var(--welcome-font-size-mobile);
font-family: Arial, Helvetica, sans-serif;
}
From 41b8ed8a4db2c45ab6aa452f7473ef8fa4e54e02 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 17:39:20 +0000
Subject: [PATCH 0109/1416] Markdown image style
---
epicyon-profile.css | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 384c60893..6ef938ec7 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -426,6 +426,10 @@ a:focus {
background-color: var(--timeline-posts-background-color);
}
+.container img.markdownImage {
+ width: 100%;
+}
+
.container img.timelineicon:hover {
filter: brightness(var(--icon-brightness-change));
}
From c10fcc4f40557f2de6ecceb1448e055f5caf9d7f Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 26 Feb 2021 20:30:51 +0000
Subject: [PATCH 0110/1416] Welcome screen header images
---
defaultwelcome/welcome_ar.md | 1 +
defaultwelcome/welcome_ca.md | 1 +
defaultwelcome/welcome_cy.md | 1 +
defaultwelcome/welcome_de.md | 1 +
defaultwelcome/welcome_es.md | 1 +
defaultwelcome/welcome_fr.md | 1 +
defaultwelcome/welcome_ga.md | 1 +
defaultwelcome/welcome_hi.md | 1 +
defaultwelcome/welcome_it.md | 1 +
defaultwelcome/welcome_ja.md | 1 +
defaultwelcome/welcome_oc.md | 3 ++-
defaultwelcome/welcome_pt.md | 3 ++-
defaultwelcome/welcome_ru.md | 1 +
defaultwelcome/welcome_zh.md | 1 +
theme/debian/helpimages/welcome.jpg | Bin 0 -> 11593 bytes
theme/hacker/helpimages/welcome.jpg | Bin 0 -> 15338 bytes
theme/henge/helpimages/welcome.jpg | Bin 0 -> 23376 bytes
theme/light/helpimages/welcome.jpg | Bin 0 -> 9607 bytes
theme/night/helpimages/welcome.jpg | Bin 0 -> 14025 bytes
theme/purple/helpimages/welcome.jpg | Bin 0 -> 36979 bytes
theme/solidaric/helpimages/welcome.jpg | Bin 0 -> 8453 bytes
theme/starlight/helpimages/welcome.jpg | Bin 0 -> 7885 bytes
theme/zen/helpimages/welcome.jpg | Bin 0 -> 31738 bytes
23 files changed, 16 insertions(+), 2 deletions(-)
create mode 100644 theme/debian/helpimages/welcome.jpg
create mode 100644 theme/hacker/helpimages/welcome.jpg
create mode 100644 theme/henge/helpimages/welcome.jpg
create mode 100644 theme/light/helpimages/welcome.jpg
create mode 100644 theme/night/helpimages/welcome.jpg
create mode 100644 theme/purple/helpimages/welcome.jpg
create mode 100644 theme/solidaric/helpimages/welcome.jpg
create mode 100644 theme/starlight/helpimages/welcome.jpg
create mode 100644 theme/zen/helpimages/welcome.jpg
diff --git a/defaultwelcome/welcome_ar.md b/defaultwelcome/welcome_ar.md
index 8e88deb0a..8d7170c4e 100644
--- a/defaultwelcome/welcome_ar.md
+++ b/defaultwelcome/welcome_ar.md
@@ -1,3 +1,4 @@
+
### مرحبًا بكم في INSTANCE
هذا خادم ActivityPub مصمم للاستضافة الذاتية السهلة لعدد قليل من الأشخاص على أنظمة منخفضة الطاقة ، مثل أجهزة الكمبيوتر ذات اللوحة الواحدة أو أجهزة الكمبيوتر المحمولة القديمة.
diff --git a/defaultwelcome/welcome_ca.md b/defaultwelcome/welcome_ca.md
index 0721e7e14..ada6129ed 100644
--- a/defaultwelcome/welcome_ca.md
+++ b/defaultwelcome/welcome_ca.md
@@ -1,3 +1,4 @@
+
### Benvingut a INSTANCE
Es tracta d’un servidor ActivityPub dissenyat per allotjar fàcilment algunes persones en sistemes de poca potència, com ara ordinadors de placa única o portàtils antics.
diff --git a/defaultwelcome/welcome_cy.md b/defaultwelcome/welcome_cy.md
index 7596a7927..cb4530faa 100644
--- a/defaultwelcome/welcome_cy.md
+++ b/defaultwelcome/welcome_cy.md
@@ -1,3 +1,4 @@
+
### Croeso i INSTANCE
Gweinydd ActivityPub yw hwn sydd wedi'i gynllunio ar gyfer hunan-letya ychydig o bobl ar systemau pŵer isel yn hawdd, fel cyfrifiaduron bwrdd sengl neu hen gliniaduron.
diff --git a/defaultwelcome/welcome_de.md b/defaultwelcome/welcome_de.md
index f1dedb95b..c6f8e1ac7 100644
--- a/defaultwelcome/welcome_de.md
+++ b/defaultwelcome/welcome_de.md
@@ -1,3 +1,4 @@
+
### Willkommen bei INSTANCE
Dies ist ein ActivityPub-Server, der für das einfache Selbsthosting einiger weniger Personen auf Systemen mit geringem Stromverbrauch wie Single-Board-Computern oder alten Laptops entwickelt wurde.
diff --git a/defaultwelcome/welcome_es.md b/defaultwelcome/welcome_es.md
index f9ba98454..0c1474dc1 100644
--- a/defaultwelcome/welcome_es.md
+++ b/defaultwelcome/welcome_es.md
@@ -1,3 +1,4 @@
+
### Bienvenido a INSTANCE
Este es un servidor ActivityPub diseñado para el autohospedaje sencillo de algunas personas en sistemas de bajo consumo de energía, como computadoras de placa única o laptops antiguas.
diff --git a/defaultwelcome/welcome_fr.md b/defaultwelcome/welcome_fr.md
index 9fd72437e..7f6610630 100644
--- a/defaultwelcome/welcome_fr.md
+++ b/defaultwelcome/welcome_fr.md
@@ -1,3 +1,4 @@
+
### Bienvenue à INSTANCE
Il s'agit d'un serveur ActivityPub conçu pour l'auto-hébergement facile de quelques personnes sur des systèmes à faible consommation d'énergie, tels que des ordinateurs monocarte ou d'anciens ordinateurs portables.
diff --git a/defaultwelcome/welcome_ga.md b/defaultwelcome/welcome_ga.md
index c9a11c680..91dc36d64 100644
--- a/defaultwelcome/welcome_ga.md
+++ b/defaultwelcome/welcome_ga.md
@@ -1,3 +1,4 @@
+
### Fáilte go INSTANCE
Is freastalaí ActivityPub é seo atá deartha chun féin-óstáil éasca a dhéanamh ar chúpla duine ar chórais ísealchumhachta, mar ríomhairí boird aonair nó sean ríomhairí glúine.
diff --git a/defaultwelcome/welcome_hi.md b/defaultwelcome/welcome_hi.md
index 13923d095..fcffdfabd 100644
--- a/defaultwelcome/welcome_hi.md
+++ b/defaultwelcome/welcome_hi.md
@@ -1,3 +1,4 @@
+
### INSTANCE पर आपका स्वागत है
यह एक एक्टिविटीपब सर्वर है जो कम पावर सिस्टम पर सिंगल बोर्ड कंप्यूटर या पुराने लैपटॉप जैसे कुछ लोगों की आसान सेल्फ-होस्टिंग के लिए बनाया गया है।
diff --git a/defaultwelcome/welcome_it.md b/defaultwelcome/welcome_it.md
index 498caf115..b74a1e053 100644
--- a/defaultwelcome/welcome_it.md
+++ b/defaultwelcome/welcome_it.md
@@ -1,3 +1,4 @@
+
### Benvenuto in INSTANCE
Questo è un server ActivityPub progettato per un facile self-hosting di poche persone su sistemi a basso consumo, come computer a scheda singola o vecchi laptop.
diff --git a/defaultwelcome/welcome_ja.md b/defaultwelcome/welcome_ja.md
index 7e21a1821..dd26aa2ba 100644
--- a/defaultwelcome/welcome_ja.md
+++ b/defaultwelcome/welcome_ja.md
@@ -1,3 +1,4 @@
+
### INSTANCEへようこそ
これは、シングルボードコンピューターや古いラップトップなどの低電力システムで数人を簡単にセルフホスティングするために設計されたActivityPubサーバーです。
diff --git a/defaultwelcome/welcome_oc.md b/defaultwelcome/welcome_oc.md
index 2a90b3a52..520d07387 100644
--- a/defaultwelcome/welcome_oc.md
+++ b/defaultwelcome/welcome_oc.md
@@ -1,4 +1,5 @@
-# Welcome
+
+### Welcome
Epicyon is an ActivityPub server designed for easy self-hosting of a few people on low power systems, such as single board computers or old laptops.
Run your own social network presence the way you want to, and say goodbye to Big Tech.
diff --git a/defaultwelcome/welcome_pt.md b/defaultwelcome/welcome_pt.md
index f302f5aec..e0193f6a2 100644
--- a/defaultwelcome/welcome_pt.md
+++ b/defaultwelcome/welcome_pt.md
@@ -1,4 +1,5 @@
-# Bem-vindo a INSTANCE
+
+### Bem-vindo a INSTANCE
Este é um servidor ActivityPub projetado para fácil auto-hospedagem de algumas pessoas em sistemas de baixo consumo de energia, como computadores de placa única ou laptops antigos.
Administre sua própria presença na rede social do jeito que você quiser e diga adeus à Big Tech.
diff --git a/defaultwelcome/welcome_ru.md b/defaultwelcome/welcome_ru.md
index 65c82400d..857581ef4 100644
--- a/defaultwelcome/welcome_ru.md
+++ b/defaultwelcome/welcome_ru.md
@@ -1,3 +1,4 @@
+
### Добро пожаловать в INSTANCE
Это сервер ActivityPub, предназначенный для простого самостоятельного размещения нескольких человек в системах с низким энергопотреблением, таких как одноплатные компьютеры или старые ноутбуки.
diff --git a/defaultwelcome/welcome_zh.md b/defaultwelcome/welcome_zh.md
index 978734e94..1f9a62db6 100644
--- a/defaultwelcome/welcome_zh.md
+++ b/defaultwelcome/welcome_zh.md
@@ -1,3 +1,4 @@
+
### 欢迎来到INSTANCE
这是一个ActivityPub服务器,设计用于在低功耗系统(例如单板计算机或旧笔记本电脑)上轻松实现一些人的自我托管。
diff --git a/theme/debian/helpimages/welcome.jpg b/theme/debian/helpimages/welcome.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2dca20d97c6fbccac09a6cff4d8885106d0687a6
GIT binary patch
literal 11593
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