'
+ dateAndLocation = '
\n'
- if not inReplyTo:
+ if endpoint == 'newevent':
+ # event status
+ dateAndLocation += '
\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '
\n'
+ # maximum attendees
+ dateAndLocation += '\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '
\n'
+ # event joining options
+ dateAndLocation += '
\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += \
+ ' \n'
dateAndLocation += '
\n'
dateAndLocation += '
\n'
dateAndLocation += '
\n'
dateAndLocation += '\n'
+ if endpoint == 'newevent':
+ dateAndLocation += '
\n'
+ dateAndLocation += '\n'
+ dateAndLocation += '
\n'
+ dateAndLocation += '\n'
dateAndLocation += '
\n'
newPostForm = htmlHeader(cssFilename, newPostCSS)
@@ -2093,6 +2236,7 @@ def htmlNewPost(mediaInstance: bool, translate: {},
dropdownUnlistedSuffix = '/newunlisted'
dropdownFollowersSuffix = '/newfollowers'
dropdownDMSuffix = '/newdm'
+ dropdownEventSuffix = '/newevent'
dropdownReminderSuffix = '/newreminder'
dropdownReportSuffix = '/newreport'
if inReplyTo or mentions:
@@ -2101,6 +2245,7 @@ def htmlNewPost(mediaInstance: bool, translate: {},
dropdownUnlistedSuffix = ''
dropdownFollowersSuffix = ''
dropdownDMSuffix = ''
+ dropdownEventSuffix = ''
dropdownReminderSuffix = ''
dropdownReportSuffix = ''
if inReplyTo:
@@ -2176,6 +2321,12 @@ def htmlNewPost(mediaInstance: bool, translate: {},
iconsDir + '/scope_reminder.png"/>
' + translate['Reminder'] + \
'' + translate['Scheduled note to yourself'] + \
'\n'
+ dropDownContent += " " \
+ '
' + translate['Event'] + \
+ '
' + translate['Create an event'] + \
+ '\n'
dropDownContent += " " \
'
' + placeholderMessage + ''
- messageBoxHeight = 400
if mediaInstance:
messageBoxHeight = 200
@@ -3186,7 +3336,7 @@ def insertQuestion(baseDir: str, translate: {},
return content
if len(postJsonObject['object']['oneOf']) == 0:
return content
- messageId = postJsonObject['id'].replace('/activity', '')
+ messageId = removeIdEnding(postJsonObject['id'])
if '#' in messageId:
messageId = messageId.split('#', 1)[0]
pageNumberStr = ''
@@ -3654,7 +3804,7 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
avatarPosition = ''
messageId = ''
if postJsonObject.get('id'):
- messageId = postJsonObject['id'].replace('/activity', '')
+ messageId = removeIdEnding(postJsonObject['id'])
messageIdStr = ''
if messageId:
@@ -3743,7 +3893,7 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
if boxName == 'tlbookmarks' or boxName == 'bookmarks':
return ''
- timelinePostBookmark = postJsonObject['id'].replace('/activity', '')
+ timelinePostBookmark = removeIdEnding(postJsonObject['id'])
timelinePostBookmark = timelinePostBookmark.replace('://', '-')
timelinePostBookmark = timelinePostBookmark.replace('/', '-')
@@ -3828,7 +3978,13 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
iconsDir + '/dm.png" class="DMicon"/>\n'
replyStr = ''
- if showIcons:
+ # check if replying is permitted
+ commentsEnabled = True
+ if 'commentsEnabled' in postJsonObject['object']:
+ if postJsonObject['object']['commentsEnabled'] is False:
+ commentsEnabled = False
+ if showIcons and commentsEnabled:
+ # reply is permitted - create reply icon
replyToLink = postJsonObject['object']['id']
if postJsonObject['object'].get('attributedTo'):
if isinstance(postJsonObject['object']['attributedTo'], str):
@@ -3872,20 +4028,35 @@ def individualPostAsHtml(recentPostsCache: {}, maxRecentPosts: int,
translate['Reply to this post'] + \
' |" src="/' + iconsDir + '/reply.png"/>\n'
+ isEvent = isEventPost(postJsonObject)
+
editStr = ''
if fullDomain + '/users/' + nickname in postJsonObject['actor']:
- if isBlogPost(postJsonObject):
- if '/statuses/' in postJsonObject['object']['id']:
+ if '/statuses/' in postJsonObject['object']['id']:
+ if isBlogPost(postJsonObject):
+ blogPostId = postJsonObject['object']['id']
editStr += \
'
' + \
'![' + \
translate['Edit blog post'] + ' ' + \
translate['Edit blog post'] + \
' |](/' + iconsDir + '/edit.png)
\n'
+ elif isEvent:
+ eventPostId = postJsonObject['object']['id']
+ editStr += \
+ '
' + \
+ '![' + \
+ translate['Edit event'] + ' ' + \
+ translate['Edit event'] + \
+ ' |](/' + iconsDir + '/edit.png)
\n'
announceStr = ''
if not isModerationPost and showRepeatIcon:
@@ -4448,7 +4619,7 @@ def htmlTimeline(defaultTimeline: str,
if boxName == 'tlshares':
os.remove(newShareFile)
- # should the Moderation button be highlighted?
+ # should the Moderation/reports button be highlighted?
newReport = False
newReportFile = accountDir + '/.newReport'
if os.path.isfile(newReportFile):
@@ -4456,11 +4627,16 @@ def htmlTimeline(defaultTimeline: str,
if boxName == 'moderation':
os.remove(newReportFile)
+ # directory where icons are found
+ # This changes depending upon theme
iconsDir = getIconsDir(baseDir)
+
+ # the css filename
cssFilename = baseDir + '/epicyon-profile.css'
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
+ # filename of the banner shown at the top
bannerFile = 'banner.png'
bannerFilename = baseDir + '/accounts/' + \
nickname + '@' + domain + '/' + bannerFile
@@ -4476,16 +4652,20 @@ def htmlTimeline(defaultTimeline: str,
bannerFile = 'banner.webp'
with open(cssFilename, 'r') as cssFile:
+ # load css
profileStyle = \
cssFile.read().replace('banner.png',
'/users/' + nickname + '/' + bannerFile)
+ # replace any https within the css with whatever prefix is needed
if httpPrefix != 'https':
profileStyle = \
profileStyle.replace('https://',
httpPrefix + '://')
+ # is the user a moderator?
moderator = isModerator(baseDir, nickname)
+ # the appearance of buttons - highlighted or not
inboxButton = 'button'
blogsButton = 'button'
dmButton = 'button'
@@ -4496,6 +4676,7 @@ def htmlTimeline(defaultTimeline: str,
repliesButton = 'buttonhighlighted'
mediaButton = 'button'
bookmarksButton = 'button'
+ eventsButton = 'button'
sentButton = 'button'
sharesButton = 'button'
if newShare:
@@ -4529,16 +4710,21 @@ def htmlTimeline(defaultTimeline: str,
sharesButton = 'buttonselectedhighlighted'
elif boxName == 'tlbookmarks' or boxName == 'bookmarks':
bookmarksButton = 'buttonselected'
+ elif boxName == 'tlevents':
+ eventsButton = 'buttonselected'
+ # get the full domain, including any port number
fullDomain = domain
if port != 80 and port != 443:
if ':' not in domain:
fullDomain = domain + ':' + str(port)
+
usersPath = '/users/' + nickname
actor = httpPrefix + '://' + fullDomain + usersPath
showIndividualPostIcons = True
+ # show an icon for new follow approvals
followApprovals = ''
followRequestsFilename = \
baseDir + '/accounts/' + \
@@ -4558,6 +4744,7 @@ def htmlTimeline(defaultTimeline: str,
'" src="/' + iconsDir + '/person.png"/>\n'
break
+ # moderation / reports button
moderationButtonStr = ''
if moderator and not minimal:
moderationButtonStr = \
@@ -4567,8 +4754,10 @@ def htmlTimeline(defaultTimeline: str,
htmlHighlightLabel(translate['Mod'], newReport) + \
' \n'
+ # shares, bookmarks and events buttons
sharesButtonStr = ''
bookmarksButtonStr = ''
+ eventsButtonStr = ''
if not minimal:
sharesButtonStr = \
'
\n'
+ eventsButtonStr = \
+ '
\n'
+
tlStr = htmlHeader(cssFilename, profileStyle)
- if boxName != 'dm':
- if boxName != 'tlblogs':
- if not manuallyApproveFollowers:
- newPostButtonStr = \
- '
![' + \
- translate['Create a new post'] + ' | ' + \
- translate['Create a new post'] + \
- '](/' + \
- iconsDir + '/newpost.png)
\n'
- else:
- newPostButtonStr = \
- '
![' + \
- translate['Create a new post'] + \
- ' | ' + translate['Create a new post'] + \
- '](/' + \
- iconsDir + '/newpost.png)
\n'
- else:
- newPostButtonStr = \
- '
![' + \
- translate['Create a new post'] + ' | ' + \
- translate['Create a new post'] + \
- '](/' + \
- iconsDir + '/newpost.png)
\n'
- else:
+ # what screen to go to when a new post is created
+ if boxName == 'dm':
newPostButtonStr = \
'
![| ' + translate['Create a new DM'] + \
'](/' + \
@@ -4617,6 +4786,39 @@ def htmlTimeline(defaultTimeline: str,
translate['Create a new DM'] + \
')
\n'
+ elif boxName == 'tlblogs':
+ newPostButtonStr = \
+ '
![' + \
+ translate['Create a new post'] + ' | ' + \
+ translate['Create a new post'] + \
+ '](/' + \
+ iconsDir + '/newpost.png)
\n'
+ elif boxName == 'tlevents':
+ newPostButtonStr = \
+ '
![' + \
+ translate['Create a new event'] + ' | ' + \
+ translate['Create a new event'] + \
+ '](/' + \
+ iconsDir + '/newpost.png)
\n'
+ else:
+ if not manuallyApproveFollowers:
+ newPostButtonStr = \
+ '
![' + \
+ translate['Create a new post'] + ' | ' + \
+ translate['Create a new post'] + \
+ '](/' + \
+ iconsDir + '/newpost.png)
\n'
+ else:
+ newPostButtonStr = \
+ '
![' + \
+ translate['Create a new post'] + \
+ ' | ' + translate['Create a new post'] + \
+ '](/' + \
+ iconsDir + '/newpost.png)
\n'
# This creates a link to the profile page when viewed
# in lynx, but should be invisible in a graphical web browser
@@ -4681,6 +4883,7 @@ def htmlTimeline(defaultTimeline: str,
'\n'
# typically the blogs button
+ # but may change if this is a blogging oriented instance
if defaultTimeline != 'tlblogs':
if not minimal:
tlStr += \
@@ -4696,14 +4899,19 @@ def htmlTimeline(defaultTimeline: str,
inboxButton + '">
' + translate['Inbox'] + \
'\n'
+ # button for the outbox
tlStr += \
'
\n'
+
+ # add other buttons
tlStr += \
- sharesButtonStr + bookmarksButtonStr + \
+ sharesButtonStr + bookmarksButtonStr + eventsButtonStr + \
moderationButtonStr + newPostButtonStr
+
+ # the search button
tlStr += \
'
![| ' + \
translate['Search and follow'] + '](/' + \
@@ -4711,6 +4919,7 @@ def htmlTimeline(defaultTimeline: str,
translate['Search and follow'] + ')
\n'
+ # the calendar button
calendarAltText = translate['Calendar']
if newCalendarEvent:
# indicate that the calendar icon is highlighted
@@ -4721,6 +4930,7 @@ def htmlTimeline(defaultTimeline: str,
calendarImage + '" title="' + translate['Calendar'] + \
'" alt="| ' + calendarAltText + '" class="timelineicon"/>\n'
+ # the show/hide button, for a simpler header appearance
tlStr += \
'
:
now = datetime.now()
+
+ # happening today button
tlStr += \
'<center>\n<a href=)
\n'
+
+ # happening this week button
if thisWeeksEventsCheck(baseDir, nickname, domain):
tlStr += \
'
1:
tlStr += '
'
tlStr += '\n'
+
+ # show each post in the timeline
for item in timelineJson['orderedItems']:
if item['type'] == 'Create' or \
item['type'] == 'Announce' or \
@@ -4830,7 +5048,7 @@ def htmlTimeline(defaultTimeline: str,
if boxName != 'tlmedia' and \
recentPostsCache.get('index'):
postId = \
- item['id'].replace('/activity', '').replace('/', '#')
+ removeIdEnding(item['id']).replace('/', '#')
if postId in recentPostsCache['index']:
if not item.get('muted'):
if recentPostsCache['html'].get(postId):
@@ -4942,6 +5160,28 @@ def htmlBookmarks(defaultTimeline: str,
minimal, YTReplacementDomain)
+def htmlEvents(defaultTimeline: str,
+ recentPostsCache: {}, maxRecentPosts: int,
+ translate: {}, pageNumber: int, itemsPerPage: int,
+ session, baseDir: str, wfRequest: {}, personCache: {},
+ nickname: str, domain: str, port: int, bookmarksJson: {},
+ allowDeletion: bool,
+ httpPrefix: str, projectVersion: str,
+ minimal: bool, YTReplacementDomain: str) -> str:
+ """Show the events as html
+ """
+ manuallyApproveFollowers = \
+ followerApprovalActive(baseDir, nickname, domain)
+
+ return htmlTimeline(defaultTimeline, recentPostsCache, maxRecentPosts,
+ translate, pageNumber,
+ itemsPerPage, session, baseDir, wfRequest, personCache,
+ nickname, domain, port, bookmarksJson,
+ 'tlevents', allowDeletion,
+ httpPrefix, projectVersion, manuallyApproveFollowers,
+ minimal, YTReplacementDomain)
+
+
def htmlInboxDMs(defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
@@ -5105,7 +5345,7 @@ def htmlIndividualPost(recentPostsCache: {}, maxRecentPosts: int,
httpPrefix, projectVersion, 'inbox',
YTReplacementDomain,
False, authorized, False, False, False)
- messageId = postJsonObject['id'].replace('/activity', '')
+ messageId = removeIdEnding(postJsonObject['id'])
# show the previous posts
if isinstance(postJsonObject['object'], dict):