mirror of https://gitlab.com/bashrc2/epicyon
Implement reply interval in hours
The time after publication of a post during which replies are permittedmerge-requests/30/head
parent
f84149cd3a
commit
9601220e66
32
daemon.py
32
daemon.py
|
|
@ -232,6 +232,7 @@ from categories import updateHashtagCategories
|
||||||
from languages import getActorLanguages
|
from languages import getActorLanguages
|
||||||
from languages import setActorLanguages
|
from languages import setActorLanguages
|
||||||
from like import updateLikesCollection
|
from like import updateLikesCollection
|
||||||
|
from utils import canReplyTo
|
||||||
from utils import isDM
|
from utils import isDM
|
||||||
from utils import replaceUsersWithAt
|
from utils import replaceUsersWithAt
|
||||||
from utils import localActorUrl
|
from utils import localActorUrl
|
||||||
|
|
@ -857,6 +858,14 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
'This is nothing less ' +
|
'This is nothing less ' +
|
||||||
'than an utter triumph')
|
'than an utter triumph')
|
||||||
|
|
||||||
|
def _403(self) -> None:
|
||||||
|
if self.server.translate:
|
||||||
|
self._httpReturnCode(403, self.server.translate['Forbidden'],
|
||||||
|
self.server.translate["You're not allowed"])
|
||||||
|
else:
|
||||||
|
self._httpReturnCode(403, 'Forbidden',
|
||||||
|
"You're not allowed")
|
||||||
|
|
||||||
def _404(self) -> None:
|
def _404(self) -> None:
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
self._httpReturnCode(404, self.server.translate['Not Found'],
|
self._httpReturnCode(404, self.server.translate['Not Found'],
|
||||||
|
|
@ -11287,6 +11296,18 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
if isNewPostEndpoint:
|
if isNewPostEndpoint:
|
||||||
nickname = getNicknameFromActor(path)
|
nickname = getNicknameFromActor(path)
|
||||||
|
|
||||||
|
if inReplyToUrl:
|
||||||
|
replyIntervalHours = self.server.defaultReplyIntervalHours
|
||||||
|
if not canReplyTo(baseDir, nickname, domain,
|
||||||
|
inReplyToUrl, replyIntervalHours):
|
||||||
|
print('Reply outside of time window ' + inReplyToUrl)
|
||||||
|
self._403()
|
||||||
|
self.server.GETbusy = False
|
||||||
|
return True
|
||||||
|
elif self.server.debug:
|
||||||
|
print('Reply is within time interval: ' +
|
||||||
|
str(replyIntervalHours) + ' hours')
|
||||||
|
|
||||||
accessKeys = self.server.accessKeys
|
accessKeys = self.server.accessKeys
|
||||||
if self.server.keyShortcuts.get(nickname):
|
if self.server.keyShortcuts.get(nickname):
|
||||||
accessKeys = self.server.keyShortcuts[nickname]
|
accessKeys = self.server.keyShortcuts[nickname]
|
||||||
|
|
@ -16245,7 +16266,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def runDaemon(lowBandwidth: bool,
|
def runDaemon(defaultReplyIntervalHours: int,
|
||||||
|
lowBandwidth: bool,
|
||||||
maxLikeCount: int,
|
maxLikeCount: int,
|
||||||
sharedItemsFederatedDomains: [],
|
sharedItemsFederatedDomains: [],
|
||||||
userAgentsBlocked: [],
|
userAgentsBlocked: [],
|
||||||
|
|
@ -16376,6 +16398,11 @@ def runDaemon(lowBandwidth: bool,
|
||||||
'Public': 'p',
|
'Public': 'p',
|
||||||
'Reminder': 'r'
|
'Reminder': 'r'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# how many hours after a post was publushed can a reply be made
|
||||||
|
defaultReplyIntervalHours = 9999999
|
||||||
|
httpd.defaultReplyIntervalHours = defaultReplyIntervalHours
|
||||||
|
|
||||||
httpd.keyShortcuts = {}
|
httpd.keyShortcuts = {}
|
||||||
loadAccessKeysForAccounts(baseDir, httpd.keyShortcuts, httpd.accessKeys)
|
loadAccessKeysForAccounts(baseDir, httpd.keyShortcuts, httpd.accessKeys)
|
||||||
|
|
||||||
|
|
@ -16704,7 +16731,8 @@ def runDaemon(lowBandwidth: bool,
|
||||||
httpd.themeName,
|
httpd.themeName,
|
||||||
httpd.systemLanguage,
|
httpd.systemLanguage,
|
||||||
httpd.maxLikeCount,
|
httpd.maxLikeCount,
|
||||||
httpd.signingPrivateKeyPem), daemon=True)
|
httpd.signingPrivateKeyPem,
|
||||||
|
httpd.defaultReplyIntervalHours), daemon=True)
|
||||||
|
|
||||||
print('Creating scheduled post thread')
|
print('Creating scheduled post thread')
|
||||||
httpd.thrPostSchedule = \
|
httpd.thrPostSchedule = \
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,11 @@ parser.add_argument('--dormantMonths',
|
||||||
default=3,
|
default=3,
|
||||||
help='How many months does a followed account need to ' +
|
help='How many months does a followed account need to ' +
|
||||||
'be unseen for before being considered dormant')
|
'be unseen for before being considered dormant')
|
||||||
|
parser.add_argument('--defaultReplyIntervalHours',
|
||||||
|
dest='defaultReplyIntervalHours', type=int,
|
||||||
|
default=9999999999,
|
||||||
|
help='How many hours after publication of a post ' +
|
||||||
|
'are replies to it permitted')
|
||||||
parser.add_argument('--sendThreadsTimeoutMins',
|
parser.add_argument('--sendThreadsTimeoutMins',
|
||||||
dest='sendThreadsTimeoutMins', type=int,
|
dest='sendThreadsTimeoutMins', type=int,
|
||||||
default=30,
|
default=30,
|
||||||
|
|
@ -3031,7 +3036,8 @@ if args.defaultCurrency:
|
||||||
print('Default currency set to ' + args.defaultCurrency)
|
print('Default currency set to ' + args.defaultCurrency)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
runDaemon(args.lowBandwidth, args.maxLikeCount,
|
runDaemon(args.defaultReplyIntervalHours,
|
||||||
|
args.lowBandwidth, args.maxLikeCount,
|
||||||
sharedItemsFederatedDomains,
|
sharedItemsFederatedDomains,
|
||||||
userAgentsBlocked,
|
userAgentsBlocked,
|
||||||
args.logLoginFailures,
|
args.logLoginFailures,
|
||||||
|
|
|
||||||
39
inbox.py
39
inbox.py
|
|
@ -15,6 +15,8 @@ import random
|
||||||
from linked_data_sig import verifyJsonSignature
|
from linked_data_sig import verifyJsonSignature
|
||||||
from languages import understoodPostLanguage
|
from languages import understoodPostLanguage
|
||||||
from like import updateLikesCollection
|
from like import updateLikesCollection
|
||||||
|
from utils import getReplyIntervalHours
|
||||||
|
from utils import canReplyTo
|
||||||
from utils import getUserPaths
|
from utils import getUserPaths
|
||||||
from utils import getBaseContentFromPost
|
from utils import getBaseContentFromPost
|
||||||
from utils import acctDir
|
from utils import acctDir
|
||||||
|
|
@ -2484,7 +2486,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
lastBounceMessage: [],
|
lastBounceMessage: [],
|
||||||
themeName: str, systemLanguage: str,
|
themeName: str, systemLanguage: str,
|
||||||
maxLikeCount: int,
|
maxLikeCount: int,
|
||||||
signingPrivateKeyPem: str) -> bool:
|
signingPrivateKeyPem: str,
|
||||||
|
defaultReplyIntervalHours: int) -> bool:
|
||||||
""" Anything which needs to be done after initial checks have passed
|
""" Anything which needs to be done after initial checks have passed
|
||||||
"""
|
"""
|
||||||
actor = keyId
|
actor = keyId
|
||||||
|
|
@ -2765,11 +2768,29 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
if isinstance(inReplyTo, str):
|
if isinstance(inReplyTo, str):
|
||||||
if not isMuted(baseDir, nickname, domain,
|
if not isMuted(baseDir, nickname, domain,
|
||||||
inReplyTo, conversationId):
|
inReplyTo, conversationId):
|
||||||
actUrl = \
|
# check if the reply is within the allowed
|
||||||
localActorUrl(httpPrefix,
|
# time period after publication
|
||||||
nickname, domain)
|
hrs = defaultReplyIntervalHours
|
||||||
_replyNotify(baseDir, handle,
|
replyIntervalHours = \
|
||||||
actUrl + '/tlreplies')
|
getReplyIntervalHours(baseDir,
|
||||||
|
nickname,
|
||||||
|
domain, hrs)
|
||||||
|
if canReplyTo(baseDir, nickname, domain,
|
||||||
|
inReplyTo,
|
||||||
|
replyIntervalHours):
|
||||||
|
actUrl = \
|
||||||
|
localActorUrl(httpPrefix,
|
||||||
|
nickname, domain)
|
||||||
|
_replyNotify(baseDir, handle,
|
||||||
|
actUrl + '/tlreplies')
|
||||||
|
else:
|
||||||
|
if debug:
|
||||||
|
print('Reply to ' + inReplyTo +
|
||||||
|
' is outside of the ' +
|
||||||
|
'permitted interval of ' +
|
||||||
|
str(replyIntervalHours) +
|
||||||
|
' hours')
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
isReplyToMutedPost = True
|
isReplyToMutedPost = True
|
||||||
|
|
||||||
|
|
@ -3119,7 +3140,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
peertubeInstances: [],
|
peertubeInstances: [],
|
||||||
verifyAllSignatures: bool,
|
verifyAllSignatures: bool,
|
||||||
themeName: str, systemLanguage: str,
|
themeName: str, systemLanguage: str,
|
||||||
maxLikeCount: int, signingPrivateKeyPem: str) -> None:
|
maxLikeCount: int, signingPrivateKeyPem: str,
|
||||||
|
defaultReplyIntervalHours: int) -> None:
|
||||||
"""Processes received items and moves them to the appropriate
|
"""Processes received items and moves them to the appropriate
|
||||||
directories
|
directories
|
||||||
"""
|
"""
|
||||||
|
|
@ -3534,7 +3556,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
lastBounceMessage,
|
lastBounceMessage,
|
||||||
themeName, systemLanguage,
|
themeName, systemLanguage,
|
||||||
maxLikeCount,
|
maxLikeCount,
|
||||||
signingPrivateKeyPem)
|
signingPrivateKeyPem,
|
||||||
|
defaultReplyIntervalHours)
|
||||||
if debug:
|
if debug:
|
||||||
pprint(queueJson['post'])
|
pprint(queueJson['post'])
|
||||||
print('Queue: Queue post accepted')
|
print('Queue: Queue post accepted')
|
||||||
|
|
|
||||||
16
tests.py
16
tests.py
|
|
@ -649,8 +649,10 @@ def createServerAlice(path: str, domain: str, port: int,
|
||||||
logLoginFailures = False
|
logLoginFailures = False
|
||||||
userAgentsBlocked = []
|
userAgentsBlocked = []
|
||||||
maxLikeCount = 10
|
maxLikeCount = 10
|
||||||
|
defaultReplyIntervalHours = 9999999999
|
||||||
print('Server running: Alice')
|
print('Server running: Alice')
|
||||||
runDaemon(lowBandwidth, maxLikeCount,
|
runDaemon(defaultReplyIntervalHours,
|
||||||
|
lowBandwidth, maxLikeCount,
|
||||||
sharedItemsFederatedDomains,
|
sharedItemsFederatedDomains,
|
||||||
userAgentsBlocked,
|
userAgentsBlocked,
|
||||||
logLoginFailures, city,
|
logLoginFailures, city,
|
||||||
|
|
@ -785,8 +787,10 @@ def createServerBob(path: str, domain: str, port: int,
|
||||||
logLoginFailures = False
|
logLoginFailures = False
|
||||||
userAgentsBlocked = []
|
userAgentsBlocked = []
|
||||||
maxLikeCount = 10
|
maxLikeCount = 10
|
||||||
|
defaultReplyIntervalHours = 9999999999
|
||||||
print('Server running: Bob')
|
print('Server running: Bob')
|
||||||
runDaemon(lowBandwidth, maxLikeCount,
|
runDaemon(defaultReplyIntervalHours,
|
||||||
|
lowBandwidth, maxLikeCount,
|
||||||
sharedItemsFederatedDomains,
|
sharedItemsFederatedDomains,
|
||||||
userAgentsBlocked,
|
userAgentsBlocked,
|
||||||
logLoginFailures, city,
|
logLoginFailures, city,
|
||||||
|
|
@ -850,8 +854,10 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
|
||||||
userAgentsBlocked = []
|
userAgentsBlocked = []
|
||||||
maxLikeCount = 10
|
maxLikeCount = 10
|
||||||
lowBandwidth = True
|
lowBandwidth = True
|
||||||
|
defaultReplyIntervalHours = 9999999999
|
||||||
print('Server running: Eve')
|
print('Server running: Eve')
|
||||||
runDaemon(lowBandwidth, maxLikeCount,
|
runDaemon(defaultReplyIntervalHours,
|
||||||
|
lowBandwidth, maxLikeCount,
|
||||||
sharedItemsFederatedDomains,
|
sharedItemsFederatedDomains,
|
||||||
userAgentsBlocked,
|
userAgentsBlocked,
|
||||||
logLoginFailures, city,
|
logLoginFailures, city,
|
||||||
|
|
@ -917,8 +923,10 @@ def createServerGroup(path: str, domain: str, port: int,
|
||||||
userAgentsBlocked = []
|
userAgentsBlocked = []
|
||||||
maxLikeCount = 10
|
maxLikeCount = 10
|
||||||
lowBandwidth = True
|
lowBandwidth = True
|
||||||
|
defaultReplyIntervalHours = 9999999999
|
||||||
print('Server running: Group')
|
print('Server running: Group')
|
||||||
runDaemon(lowBandwidth, maxLikeCount,
|
runDaemon(defaultReplyIntervalHours,
|
||||||
|
lowBandwidth, maxLikeCount,
|
||||||
sharedItemsFederatedDomains,
|
sharedItemsFederatedDomains,
|
||||||
userAgentsBlocked,
|
userAgentsBlocked,
|
||||||
logLoginFailures, city,
|
logLoginFailures, city,
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "البحث عن العناصر المطلوبة",
|
"Wanted Items Search": "البحث عن العناصر المطلوبة",
|
||||||
"Website": "موقع إلكتروني",
|
"Website": "موقع إلكتروني",
|
||||||
"Low Bandwidth": "انخفاض النطاق الترددي",
|
"Low Bandwidth": "انخفاض النطاق الترددي",
|
||||||
"accommodation": "الإقامة"
|
"accommodation": "الإقامة",
|
||||||
|
"Forbidden": "محرم",
|
||||||
|
"You're not allowed": "كنت لا يسمح"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Cerca d'articles desitjats",
|
"Wanted Items Search": "Cerca d'articles desitjats",
|
||||||
"Website": "Lloc web",
|
"Website": "Lloc web",
|
||||||
"Low Bandwidth": "Ample de banda baixa",
|
"Low Bandwidth": "Ample de banda baixa",
|
||||||
"accommodation": "allotjament"
|
"accommodation": "allotjament",
|
||||||
|
"Forbidden": "Prohibit",
|
||||||
|
"You're not allowed": "No està permès"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Chwilio Eitemau Eisiau",
|
"Wanted Items Search": "Chwilio Eitemau Eisiau",
|
||||||
"Website": "Gwefan",
|
"Website": "Gwefan",
|
||||||
"Low Bandwidth": "Lled band isel",
|
"Low Bandwidth": "Lled band isel",
|
||||||
"accommodation": "llety"
|
"accommodation": "llety",
|
||||||
|
"Forbidden": "Wedi'i wahardd",
|
||||||
|
"You're not allowed": "Ni chaniateir i chi"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Gesuchte Artikel suchen",
|
"Wanted Items Search": "Gesuchte Artikel suchen",
|
||||||
"Website": "Webseite",
|
"Website": "Webseite",
|
||||||
"Low Bandwidth": "Niedrige Bandbreite",
|
"Low Bandwidth": "Niedrige Bandbreite",
|
||||||
"accommodation": "unterkunft"
|
"accommodation": "unterkunft",
|
||||||
|
"Forbidden": "Verboten",
|
||||||
|
"You're not allowed": "Du darfst nicht"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Wanted Items Search",
|
"Wanted Items Search": "Wanted Items Search",
|
||||||
"Website": "Website",
|
"Website": "Website",
|
||||||
"Low Bandwidth": "Low Bandwidth",
|
"Low Bandwidth": "Low Bandwidth",
|
||||||
"accommodation": "accommodation"
|
"accommodation": "accommodation",
|
||||||
|
"Forbidden": "Forbidden",
|
||||||
|
"You're not allowed": "You're not allowed"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Búsqueda de artículos deseados",
|
"Wanted Items Search": "Búsqueda de artículos deseados",
|
||||||
"Website": "Sitio web",
|
"Website": "Sitio web",
|
||||||
"Low Bandwidth": "Ancho de banda bajo",
|
"Low Bandwidth": "Ancho de banda bajo",
|
||||||
"accommodation": "alojamiento"
|
"accommodation": "alojamiento",
|
||||||
|
"Forbidden": "Prohibida",
|
||||||
|
"You're not allowed": "No tienes permiso"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Recherche d'objets recherchés",
|
"Wanted Items Search": "Recherche d'objets recherchés",
|
||||||
"Website": "Site Internet",
|
"Website": "Site Internet",
|
||||||
"Low Bandwidth": "Bas débit",
|
"Low Bandwidth": "Bas débit",
|
||||||
"accommodation": "hébergement"
|
"accommodation": "hébergement",
|
||||||
|
"Forbidden": "Interdite",
|
||||||
|
"You're not allowed": "Tu n'as pas le droit"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Cuardaigh Míreanna Teastaíonn",
|
"Wanted Items Search": "Cuardaigh Míreanna Teastaíonn",
|
||||||
"Website": "Suíomh gréasáin",
|
"Website": "Suíomh gréasáin",
|
||||||
"Low Bandwidth": "Bandaleithead íseal",
|
"Low Bandwidth": "Bandaleithead íseal",
|
||||||
"accommodation": "lóistín"
|
"accommodation": "lóistín",
|
||||||
|
"Forbidden": "Toirmiscthe",
|
||||||
|
"You're not allowed": "Níl cead agat"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "वांटेड आइटम सर्च",
|
"Wanted Items Search": "वांटेड आइटम सर्च",
|
||||||
"Website": "वेबसाइट",
|
"Website": "वेबसाइट",
|
||||||
"Low Bandwidth": "कम बैंडविड्थ",
|
"Low Bandwidth": "कम बैंडविड्थ",
|
||||||
"accommodation": "निवास स्थान"
|
"accommodation": "निवास स्थान",
|
||||||
|
"Forbidden": "निषिद्ध",
|
||||||
|
"You're not allowed": "आपको अनुमति नहीं है"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Ricerca articoli ricercati",
|
"Wanted Items Search": "Ricerca articoli ricercati",
|
||||||
"Website": "Sito web",
|
"Website": "Sito web",
|
||||||
"Low Bandwidth": "Bassa larghezza di banda",
|
"Low Bandwidth": "Bassa larghezza di banda",
|
||||||
"accommodation": "struttura ricettiva"
|
"accommodation": "struttura ricettiva",
|
||||||
|
"Forbidden": "Proibita",
|
||||||
|
"You're not allowed": "Non ti è permesso"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "欲しいアイテム検索",
|
"Wanted Items Search": "欲しいアイテム検索",
|
||||||
"Website": "Webサイト",
|
"Website": "Webサイト",
|
||||||
"Low Bandwidth": "低帯域幅",
|
"Low Bandwidth": "低帯域幅",
|
||||||
"accommodation": "宿泊施設"
|
"accommodation": "宿泊施設",
|
||||||
|
"Forbidden": "禁断",
|
||||||
|
"You're not allowed": "あなたは許可されていません"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Wanted Items Search",
|
"Wanted Items Search": "Wanted Items Search",
|
||||||
"Website": "Malper",
|
"Website": "Malper",
|
||||||
"Low Bandwidth": "Bandwidth kêm",
|
"Low Bandwidth": "Bandwidth kêm",
|
||||||
"accommodation": "cih"
|
"accommodation": "cih",
|
||||||
|
"Forbidden": "Qedexekirî",
|
||||||
|
"You're not allowed": "Destûrê nadin te"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -471,5 +471,7 @@
|
||||||
"Wanted Items Search": "Wanted Items Search",
|
"Wanted Items Search": "Wanted Items Search",
|
||||||
"Website": "Website",
|
"Website": "Website",
|
||||||
"Low Bandwidth": "Low Bandwidth",
|
"Low Bandwidth": "Low Bandwidth",
|
||||||
"accommodation": "accommodation"
|
"accommodation": "accommodation",
|
||||||
|
"Forbidden": "Forbidden",
|
||||||
|
"You're not allowed": "You're not allowed"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Pesquisa de Itens Desejados",
|
"Wanted Items Search": "Pesquisa de Itens Desejados",
|
||||||
"Website": "Local na rede Internet",
|
"Website": "Local na rede Internet",
|
||||||
"Low Bandwidth": "Baixa largura de banda",
|
"Low Bandwidth": "Baixa largura de banda",
|
||||||
"accommodation": "alojamento"
|
"accommodation": "alojamento",
|
||||||
|
"Forbidden": "Proibida",
|
||||||
|
"You're not allowed": "Você não tem permissão"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Поиск требуемых предметов",
|
"Wanted Items Search": "Поиск требуемых предметов",
|
||||||
"Website": "Интернет сайт",
|
"Website": "Интернет сайт",
|
||||||
"Low Bandwidth": "Низкая пропускная способность",
|
"Low Bandwidth": "Низкая пропускная способность",
|
||||||
"accommodation": "размещение"
|
"accommodation": "размещение",
|
||||||
|
"Forbidden": "Запрещенный",
|
||||||
|
"You're not allowed": "Вам не разрешено"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "Utafutaji wa Vitu vinavyotafutwa",
|
"Wanted Items Search": "Utafutaji wa Vitu vinavyotafutwa",
|
||||||
"Website": "Tovuti",
|
"Website": "Tovuti",
|
||||||
"Low Bandwidth": "Bandwidth ya chini",
|
"Low Bandwidth": "Bandwidth ya chini",
|
||||||
"accommodation": "malazi"
|
"accommodation": "malazi",
|
||||||
|
"Forbidden": "Imekatazwa",
|
||||||
|
"You're not allowed": "Hauruhusiwi"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -475,5 +475,7 @@
|
||||||
"Wanted Items Search": "通缉物品搜索",
|
"Wanted Items Search": "通缉物品搜索",
|
||||||
"Website": "网站",
|
"Website": "网站",
|
||||||
"Low Bandwidth": "低带宽",
|
"Low Bandwidth": "低带宽",
|
||||||
"accommodation": "住所"
|
"accommodation": "住所",
|
||||||
|
"Forbidden": "禁止的",
|
||||||
|
"You're not allowed": "你不被允许"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
68
utils.py
68
utils.py
|
|
@ -1317,6 +1317,74 @@ def locatePost(baseDir: str, nickname: str, domain: str,
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _getPublishedDate(postJsonObject: {}) -> str:
|
||||||
|
"""Returns the published date on the given post
|
||||||
|
"""
|
||||||
|
published = None
|
||||||
|
if postJsonObject.get('published'):
|
||||||
|
published = postJsonObject['published']
|
||||||
|
elif postJsonObject.get('object'):
|
||||||
|
if isinstance(postJsonObject['object'], dict):
|
||||||
|
if postJsonObject['object'].get('published'):
|
||||||
|
published = postJsonObject['object']['published']
|
||||||
|
if not published:
|
||||||
|
return None
|
||||||
|
if not isinstance(published, str):
|
||||||
|
return None
|
||||||
|
return published
|
||||||
|
|
||||||
|
|
||||||
|
def getReplyIntervalHours(baseDir: str, nickname: str, domain: str,
|
||||||
|
defaultReplyIntervalHours: int) -> int:
|
||||||
|
"""Returns the reply interval for the given account.
|
||||||
|
The reply interval is the number of hours after a post being made
|
||||||
|
during which replies are allowed
|
||||||
|
"""
|
||||||
|
replyIntervalFilename = \
|
||||||
|
acctDir(baseDir, nickname, domain) + '/.replyIntervalHours'
|
||||||
|
if os.path.isfile(replyIntervalFilename):
|
||||||
|
with open(replyIntervalFilename, 'r') as fp:
|
||||||
|
hoursStr = fp.read()
|
||||||
|
if hoursStr.isdigit():
|
||||||
|
return int(hoursStr)
|
||||||
|
return defaultReplyIntervalHours
|
||||||
|
|
||||||
|
|
||||||
|
def canReplyTo(baseDir: str, nickname: str, domain: str,
|
||||||
|
postUrl: str, replyIntervalHours: int,
|
||||||
|
currDateStr: str = None) -> bool:
|
||||||
|
"""Is replying to the given post permitted?
|
||||||
|
This is a spam mitigation feature, so that spammers can't
|
||||||
|
add a lot of replies to old post which you don't notice.
|
||||||
|
"""
|
||||||
|
postFilename = locatePost(baseDir, nickname, domain, postUrl)
|
||||||
|
if not postFilename:
|
||||||
|
return False
|
||||||
|
postJsonObject = loadJson(postFilename)
|
||||||
|
if not postJsonObject:
|
||||||
|
return False
|
||||||
|
published = _getPublishedDate(postJsonObject)
|
||||||
|
if not published:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
pubDate = datetime.datetime.strptime(published, '%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
except BaseException:
|
||||||
|
return False
|
||||||
|
if not currDateStr:
|
||||||
|
currDate = datetime.datetime.utcnow()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
currDate = datetime.datetime.strptime(currDateStr,
|
||||||
|
'%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
except BaseException:
|
||||||
|
return False
|
||||||
|
hoursSincePublication = int((currDate - pubDate).total_seconds() / 3600)
|
||||||
|
if hoursSincePublication < 0 or \
|
||||||
|
hoursSincePublication > replyIntervalHours:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _removeAttachment(baseDir: str, httpPrefix: str, domain: str,
|
def _removeAttachment(baseDir: str, httpPrefix: str, domain: str,
|
||||||
postJson: {}):
|
postJson: {}):
|
||||||
if not postJson.get('attachment'):
|
if not postJson.get('attachment'):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue