diff --git a/daemon.py b/daemon.py index 7690f224f..b5b20c4e5 100644 --- a/daemon.py +++ b/daemon.py @@ -39,6 +39,7 @@ from person import removeAccount from person import canRemovePost from person import personSnooze from person import personUnsnooze +from posts import mutePost from posts import createQuestionPost from posts import outboxMessageCreateWrap from posts import savePostToBox @@ -2058,6 +2059,11 @@ class PubServer(BaseHTTPRequestHandler): deleteUrl=self.path.split('?delete=')[1] if '?' in deleteUrl: deleteUrl=deleteUrl.split('?')[0] + timelineStr=self.server.defaultTimeline + if '?tl=' in self.path: + timelineStr=self.path.split('?tl=')[1] + if '?' in timelineStr: + timelineStr=timelineStr.split('?')[0] actor= \ self.server.httpPrefix+'://'+ \ self.server.domainFull+self.path.split('?delete=')[0] @@ -2069,13 +2075,13 @@ class PubServer(BaseHTTPRequestHandler): if actor not in deleteUrl: # You can only delete your own posts self.server.GETbusy=False - self._redirect_headers(actor+'/'+self.server.defaultTimeline,cookie) + self._redirect_headers(actor+'/'+timelineStr,cookie) return self.postToNickname=getNicknameFromActor(actor) if not self.postToNickname: print('WARN: unable to find nickname in '+actor) self.server.GETbusy=False - self._redirect_headers(actor+'/'+self.server.defaultTimeline,cookie) + self._redirect_headers(actor+'/'+timelineStr,cookie) return if not self.server.session: self.server.session= \ @@ -2095,7 +2101,61 @@ class PubServer(BaseHTTPRequestHandler): self.server.GETbusy=False return self.server.GETbusy=False - self._redirect_headers(actor+'/'+self.server.defaultTimeline,cookie) + self._redirect_headers(actor+'/'+timelineStr,cookie) + return + + # mute a post from the web interface icon + if htmlGET and '?mute=' in self.path: + pageNumber=1 + if '?page=' in self.path: + pageNumberStr=self.path.split('?page=')[1] + if '?' in pageNumberStr: + pageNumberStr=pageNumberStr.split('?')[0] + if pageNumberStr.isdigit(): + pageNumber=int(pageNumberStr) + muteUrl=self.path.split('?mute=')[1] + if '?' in muteUrl: + muteUrl=muteUrl.split('?')[0] + timelineStr=self.server.defaultTimeline + if '?tl=' in self.path: + timelineStr=self.path.split('?tl=')[1] + if '?' in timelineStr: + timelineStr=timelineStr.split('?')[0] + actor= \ + self.server.httpPrefix+'://'+ \ + self.server.domainFull+self.path.split('?mute=')[0] + nickname=getNicknameFromActor(actor) + mutePost(self.server.baseDir,nickname,self.server.domain, \ + muteUrl,self.server.recentPostsCache) + self.server.GETbusy=False + self._redirect_headers(actor+'/'+timelineStr,cookie) + return + + # unmute a post from the web interface icon + if htmlGET and '?unmute=' in self.path: + pageNumber=1 + if '?page=' in self.path: + pageNumberStr=self.path.split('?page=')[1] + if '?' in pageNumberStr: + pageNumberStr=pageNumberStr.split('?')[0] + if pageNumberStr.isdigit(): + pageNumber=int(pageNumberStr) + muteUrl=self.path.split('?unmute=')[1] + if '?' in muteUrl: + muteUrl=muteUrl.split('?')[0] + timelineStr=self.server.defaultTimeline + if '?tl=' in self.path: + timelineStr=self.path.split('?tl=')[1] + if '?' in timelineStr: + timelineStr=timelineStr.split('?')[0] + actor= \ + self.server.httpPrefix+'://'+ \ + self.server.domainFull+self.path.split('?mute=')[0] + nickname=getNicknameFromActor(actor) + unmutePost(self.server.baseDir,nickname,self.server.domain, \ + muteUrl,self.server.recentPostsCache) + self.server.GETbusy=False + self._redirect_headers(actor+'/'+timelineStr,cookie) return # reply from the web interface icon diff --git a/img/icons/hacker/mute.png b/img/icons/hacker/mute.png new file mode 100644 index 000000000..6969e74d3 Binary files /dev/null and b/img/icons/hacker/mute.png differ diff --git a/img/icons/light/mute.png b/img/icons/light/mute.png new file mode 100644 index 000000000..5fe808e0f Binary files /dev/null and b/img/icons/light/mute.png differ diff --git a/img/icons/mute.png b/img/icons/mute.png new file mode 100644 index 000000000..2c36817c5 Binary files /dev/null and b/img/icons/mute.png differ diff --git a/img/icons/purple/mute.png b/img/icons/purple/mute.png new file mode 100644 index 000000000..d2626e8fc Binary files /dev/null and b/img/icons/purple/mute.png differ diff --git a/posts.py b/posts.py index 921f2819d..85a691b91 100644 --- a/posts.py +++ b/posts.py @@ -2635,3 +2635,49 @@ def downloadAnnounce(session,baseDir: str,httpPrefix: str,nickname: str,domain: if saveJson(postJsonObject,announceFilename): return postJsonObject return None + +def mutePost(baseDir: str,nickname: str,domain: str,postId: str, \ + recentPostsCache: {}) -> None: + """ Mutes the given post + """ + postFilename=locatePost(baseDir,nickname,domain,postId) + if not postFilename: + return + postJsonObject=loadJson(postFilename) + if not postJsonObject: + return + + muteFile=open(postFilename+'.muted', "w") + muteFile.write('\n') + muteFile.close() + + # remove cached posts so that the muted version gets created + cachedPostFilename= \ + getCachedPostFilename(baseDir,nickname,postJsonObject) + if cachedPostFilename: + if os.path.isfile(cachedPostFilename): + os.remove(cachedPostFilename) + removePostFromCache(postJsonObject,recentPostsCache) + +def unmutePost(baseDir: str,nickname: str,domain: str,postId: str, \ + recentPostsCache: {}) -> None: + """ Unmutes the given post + """ + postFilename=locatePost(baseDir,nickname,domain,postId) + if not postFilename: + return + postJsonObject=loadJson(postFilename) + if not postJsonObject: + return + + muteFilename=postFilename+'.muted' + if os.path.isfile(muteFilename): + os.remove(muteFilename) + + # remove cached posts so that it gets recreated + cachedPostFilename= \ + getCachedPostFilename(baseDir,nickname,postJsonObject) + if cachedPostFilename: + if os.path.isfile(cachedPostFilename): + os.remove(cachedPostFilename) + removePostFromCache(postJsonObject,recentPostsCache) diff --git a/translations/ar.json b/translations/ar.json index 65cf2a99c..086943258 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -198,5 +198,7 @@ "Previous month": "الشهر الماضى", "Next month": "الشهر القادم", "Get the source code": "الحصول على شفرة المصدر", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/ca.json b/translations/ca.json index e363d3ee8..ae52e43a1 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -198,5 +198,7 @@ "Previous month": "Mes anterior", "Next month": "El mes que ve", "Get the source code": "Obteniu el codi font", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/cy.json b/translations/cy.json index ea572c6be..97598567d 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -198,5 +198,7 @@ "Previous month": "Y mis blaenorol", "Next month": "Mis nesaf", "Get the source code": "Sicrhewch y cod ffynhonnell", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/de.json b/translations/de.json index 189eac6c0..b0973426a 100644 --- a/translations/de.json +++ b/translations/de.json @@ -198,5 +198,7 @@ "Previous month": "Vorheriger Monat", "Next month": "Nächsten Monat", "Get the source code": "Holen Sie sich den Quellcode", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/en.json b/translations/en.json index 970c3bf44..7b73e5cb8 100644 --- a/translations/en.json +++ b/translations/en.json @@ -198,5 +198,7 @@ "Previous month": "Previous month", "Next month": "Next month", "Get the source code": "Get the source code", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/es.json b/translations/es.json index f78f9a5ae..cb597a501 100644 --- a/translations/es.json +++ b/translations/es.json @@ -198,5 +198,7 @@ "Previous month": "Mes anterior", "Next month": "Próximo mes", "Get the source code": "Obtén el código fuente", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/fr.json b/translations/fr.json index 8f8c87fe1..65f1fc7a6 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -198,5 +198,7 @@ "Previous month": "Le mois précédent", "Next month": "Le mois prochain", "Get the source code": "Obtenir le code source", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/ga.json b/translations/ga.json index 5b4097c6f..ef2741f18 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -198,5 +198,7 @@ "Previous month": "An mhí roimhe seo", "Next month": "An mhí seo chugainn", "Get the source code": "Faigh an cód foinse", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/hi.json b/translations/hi.json index 61686e783..87cc706d6 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -198,5 +198,7 @@ "Previous month": "पिछ्ला महिना", "Next month": "अगले महीने", "Get the source code": "स्रोत कोड प्राप्त करें", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/it.json b/translations/it.json index 2700c3617..e06eae2f6 100644 --- a/translations/it.json +++ b/translations/it.json @@ -198,5 +198,7 @@ "Previous month": "Il mese scorso", "Next month": "Il prossimo mese", "Get the source code": "Ottieni il codice sorgente", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/ja.json b/translations/ja.json index 6c88672cb..7b17bc037 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -198,5 +198,7 @@ "Previous month": "前月", "Next month": "来月", "Get the source code": "ソースコードを入手する", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/oc.json b/translations/oc.json index fcd5ffacf..9e05e4d32 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -194,5 +194,7 @@ "Previous month": "Previous month", "Next month": "Next month", "Get the source code": "Get the source code", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/pt.json b/translations/pt.json index 04091833c..4fbb58ce6 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -198,5 +198,7 @@ "Previous month": "Mês anterior", "Next month": "Próximo mês", "Get the source code": "Obter o código fonte", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/ru.json b/translations/ru.json index 04e981e4d..325ca68cb 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -198,5 +198,7 @@ "Previous month": "Предыдущий месяц", "Next month": "В следующем месяце", "Get the source code": "Получить исходный код", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/translations/zh.json b/translations/zh.json index c0d02963f..4bd94c05d 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -198,5 +198,7 @@ "Previous month": "前一个月", "Next month": "下个月", "Get the source code": "获取源代码", - "This is a media instance": "This is a media instance" + "This is a media instance": "This is a media instance", + "Mute this post": "Mute this post", + "Undo mute": "Undo mute" } diff --git a/utils.py b/utils.py index e925aff4b..e7327c471 100644 --- a/utils.py +++ b/utils.py @@ -312,6 +312,19 @@ def deletePost(baseDir: str,httpPrefix: str,nickname: str,domain: str,postFilena # remove any attachment removeAttachment(baseDir,httpPrefix,domain,postJsonObject) + # remove any mute file + muteFilename=postFilename+'.muted' + if os.path.isfile(muteFilename): + os.remove(muteFilename) + + # remove cached html version of the post + cachedPostFilename= \ + getCachedPostFilename(baseDir,nickname,postJsonObject) + if cachedPostFilename: + if os.path.isfile(cachedPostFilename): + os.remove(cachedPostFilename) + #removePostFromCache(postJsonObject,recentPostsCache) + hasObject=False if postJsonObject.get('object'): hasObject=True diff --git a/webinterface.py b/webinterface.py index 2c9907d05..a6ebe5c10 100644 --- a/webinterface.py +++ b/webinterface.py @@ -1995,6 +1995,18 @@ def preparePostFromHtmlCache(postHtml: str,boxName: str,pageNumber: int) -> str: postHtml=postHtml.replace('?tl=inbox','?tl=tlbookmarks') return postHtml.replace(';-999;',';'+str(pageNumber)+';').replace('?page=-999','?page='+str(pageNumber)) +def postIsMuted(baseDir: str,nickname: str,domain: str, messageId: str) -> bool: + """ Returns true if the given post is muted + """ + postDir=baseDir+'/accounts/'+nickname+'@'+domain + muteFilename=postDir+'/inbox/'+messageId.replace('/','#')+'.json.muted' + if os.path.isfile(muteFilename): + return True + muteFilename=postDir+'/outbox/'+messageId.replace('/','#')+'.json.muted' + if os.path.isfile(muteFilename): + return True + return False + def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \ iconsDir: str,translate: {}, \ pageNumber: int,baseDir: str, \ @@ -2238,14 +2250,24 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \ '?tl='+boxName+'" title="'+bookmarkTitle+'">' bookmarkStr+=''+bookmarkTitle+' |' + isMuted=postIsMuted(baseDir,nickname,domain,messageId) + deleteStr='' + muteStr='' if allowDeletion or \ ('/'+fullDomain+'/' in postActor and \ postJsonObject['object']['id'].startswith(postActor)): if '/users/'+nickname+'/' in postJsonObject['object']['id']: deleteStr='' deleteStr+=''+translate['Delete this post']+'' - + else: + if not isMuted: + muteStr='' + muteStr+=''+translate['Mute this post']+'' + else: + muteStr='' + muteStr+=''+translate['Undo mute']+'' + replyAvatarImageInPost='' if showRepeatIcon: if isAnnounced: @@ -2468,7 +2490,7 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \ if showIcons: footerStr='
' - footerStr+=replyStr+announceStr+likeStr+bookmarkStr+deleteStr + footerStr+=replyStr+announceStr+likeStr+bookmarkStr+deleteStr+muteStr footerStr+=''+publishedStr+'' footerStr+='
' @@ -2503,12 +2525,10 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \ if postJsonObject['object'].get('tag'): contentStr=replaceEmojiFromTags(contentStr,postJsonObject['object']['tag'],'content') - # replace 's - contentStr=contentStr.replace("\ufffd\ufffd\ufffds","'s") - - contentStrMedia=contentStr - - contentStr='
'+contentStr+'
' + if isMuted: + contentStr='' + else: + contentStr='
'+contentStr+'
' postHtml='' if boxName!='tlmedia':