From 3067689faf3138fa3c9bc9a3bdc54c5482f2688a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Tue, 23 Feb 2021 22:29:14 +0000 Subject: [PATCH 01/59] 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 02/59] 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, '' # 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 03/59] 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 04/59] 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 05/59] 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 06/59] 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 07/59] 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 08/59] 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 09/59] 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 10/59] 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 11/59] 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 12/59] 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 13/59] 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 14/59] 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 += '\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 15/59] 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 16/59] 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 17/59] 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 18/59] 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 19/59] 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 20/59] 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 21/59] 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 22/59] 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 23/59] 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 24/59] 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
    underlined
' + + 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 25/59] 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 += '
\n' - profileForm += '\n' + profileForm += '
\n' + profileForm += ' \n' + profileForm += '
\n' profileForm += '
' + profileText + '
\n' profileForm += ' \n' profileForm += '\n' + + actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json' + actorJson = loadJson(actorFilename) + displayNickname = actorJson['name'] + profileForm += ' \n' + profileForm += '
\n' + + profileForm += '
\n' + bioStr = \ + actorJson['summary'].replace('

', '').replace('

', '') + profileForm += ' \n' + profileForm += ' \n' + + profileForm += '
\n' + 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 26/59] 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 += '
\n' + profileForm += '
\n' + + profileForm += '
\n' + bioStr = \ + actorJson['summary'].replace('

', '').replace('

', '') + profileForm += '
\n' + profileForm += ' \n' + + profileForm += '
\n' + profileForm += '
' + profileText + '
\n' profileForm += ' \n' profileForm += '\n' - actorFilename = baseDir + '/accounts/' + nickname + '@' + domain + '.json' - actorJson = loadJson(actorFilename) - displayNickname = actorJson['name'] - profileForm += ' \n' - profileForm += '
\n' - - profileForm += '
\n' - bioStr = \ - actorJson['summary'].replace('

', '').replace('

', '') - profileForm += ' \n' - profileForm += ' \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 27/59] 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 += '
\n' - profileForm += '
' + profileText + '
\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 29/59] 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 += '
\n' profileForm += ' ' + bioStr + '\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 30/59] 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 31/59] 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 32/59] 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 33/59] 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 += '
\n' profileForm += ' \n' + 'style="height:100px">' + bioStr + '\n' profileForm += '\n' profileForm += '\n' profileForm += '