forked from indymedia/epicyon
Calendar module
parent
86b097f64d
commit
4a3a2c2319
|
@ -114,10 +114,11 @@ from blog import htmlBlogPage
|
||||||
from blog import htmlBlogPost
|
from blog import htmlBlogPost
|
||||||
from blog import htmlEditBlog
|
from blog import htmlEditBlog
|
||||||
from webapp_utils import setBlogAddress
|
from webapp_utils import setBlogAddress
|
||||||
|
from webapp_calendar import htmlCalendarDeleteConfirm
|
||||||
|
from webapp_calendar import htmlCalendar
|
||||||
from webapp import htmlCitations
|
from webapp import htmlCitations
|
||||||
from webapp import htmlFollowingList
|
from webapp import htmlFollowingList
|
||||||
from webapp import getBlogAddress
|
from webapp import getBlogAddress
|
||||||
from webapp import htmlCalendarDeleteConfirm
|
|
||||||
from webapp import htmlDeletePost
|
from webapp import htmlDeletePost
|
||||||
from webapp import htmlAbout
|
from webapp import htmlAbout
|
||||||
from webapp import htmlRemoveSharedItem
|
from webapp import htmlRemoveSharedItem
|
||||||
|
@ -142,7 +143,6 @@ from webapp import htmlSuspended
|
||||||
from webapp import htmlGetLoginCredentials
|
from webapp import htmlGetLoginCredentials
|
||||||
from webapp import htmlNewPost
|
from webapp import htmlNewPost
|
||||||
from webapp import htmlFollowConfirm
|
from webapp import htmlFollowConfirm
|
||||||
from webapp import htmlCalendar
|
|
||||||
from webapp import htmlNewswireMobile
|
from webapp import htmlNewswireMobile
|
||||||
from webapp import htmlLinksMobile
|
from webapp import htmlLinksMobile
|
||||||
from webapp import htmlUnfollowConfirm
|
from webapp import htmlUnfollowConfirm
|
||||||
|
|
2
utils.py
2
utils.py
|
@ -1500,5 +1500,5 @@ def weekDayOfMonthStart(monthNumber: int, year: int) -> int:
|
||||||
"""Gets the day number of the first day of the month
|
"""Gets the day number of the first day of the month
|
||||||
1=sun, 7=sat
|
1=sun, 7=sat
|
||||||
"""
|
"""
|
||||||
firstDayOfMonth = datetime(year, monthNumber, 1, 0, 0)
|
firstDayOfMonth = datetime.datetime(year, monthNumber, 1, 0, 0)
|
||||||
return int(firstDayOfMonth.strftime("%w")) + 1
|
return int(firstDayOfMonth.strftime("%w")) + 1
|
||||||
|
|
378
webapp.py
378
webapp.py
|
@ -9,7 +9,6 @@ __status__ = "Production"
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import date
|
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from person import personBoxJson
|
from person import personBoxJson
|
||||||
|
@ -22,7 +21,6 @@ from ssb import getSSBAddress
|
||||||
from tox import getToxAddress
|
from tox import getToxAddress
|
||||||
from matrix import getMatrixAddress
|
from matrix import getMatrixAddress
|
||||||
from donate import getDonationUrl
|
from donate import getDonationUrl
|
||||||
from utils import weekDayOfMonthStart
|
|
||||||
from utils import getCSS
|
from utils import getCSS
|
||||||
from utils import isSystemAccount
|
from utils import isSystemAccount
|
||||||
from utils import removeIdEnding
|
from utils import removeIdEnding
|
||||||
|
@ -51,8 +49,6 @@ from skills import getSkills
|
||||||
from shares import getValidSharedItemID
|
from shares import getValidSharedItemID
|
||||||
from happening import todaysEventsCheck
|
from happening import todaysEventsCheck
|
||||||
from happening import thisWeeksEventsCheck
|
from happening import thisWeeksEventsCheck
|
||||||
from happening import getCalendarEvents
|
|
||||||
from happening import getTodaysEvents
|
|
||||||
from theme import getThemesList
|
from theme import getThemesList
|
||||||
from petnames import getPetName
|
from petnames import getPetName
|
||||||
from followingCalendar import receivingCalendarEvents
|
from followingCalendar import receivingCalendarEvents
|
||||||
|
@ -5044,78 +5040,6 @@ def htmlDeletePost(cssCache: {},
|
||||||
return deletePostStr
|
return deletePostStr
|
||||||
|
|
||||||
|
|
||||||
def htmlCalendarDeleteConfirm(cssCache: {}, translate: {}, baseDir: str,
|
|
||||||
path: str, httpPrefix: str,
|
|
||||||
domainFull: str, postId: str, postTime: str,
|
|
||||||
year: int, monthNumber: int,
|
|
||||||
dayNumber: int, callingDomain: str) -> str:
|
|
||||||
"""Shows a screen asking to confirm the deletion of a calendar event
|
|
||||||
"""
|
|
||||||
nickname = getNicknameFromActor(path)
|
|
||||||
actor = httpPrefix + '://' + domainFull + '/users/' + nickname
|
|
||||||
domain, port = getDomainFromActor(actor)
|
|
||||||
messageId = actor + '/statuses/' + postId
|
|
||||||
|
|
||||||
postFilename = locatePost(baseDir, nickname, domain, messageId)
|
|
||||||
if not postFilename:
|
|
||||||
return None
|
|
||||||
|
|
||||||
postJsonObject = loadJson(postFilename)
|
|
||||||
if not postJsonObject:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if os.path.isfile(baseDir + '/img/delete-background.png'):
|
|
||||||
if not os.path.isfile(baseDir + '/accounts/delete-background.png'):
|
|
||||||
copyfile(baseDir + '/img/delete-background.png',
|
|
||||||
baseDir + '/accounts/delete-background.png')
|
|
||||||
|
|
||||||
deletePostStr = None
|
|
||||||
cssFilename = baseDir + '/epicyon-profile.css'
|
|
||||||
if os.path.isfile(baseDir + '/epicyon.css'):
|
|
||||||
cssFilename = baseDir + '/epicyon.css'
|
|
||||||
|
|
||||||
profileStyle = getCSS(baseDir, cssFilename, cssCache)
|
|
||||||
if profileStyle:
|
|
||||||
if httpPrefix != 'https':
|
|
||||||
profileStyle = profileStyle.replace('https://',
|
|
||||||
httpPrefix + '://')
|
|
||||||
deletePostStr = htmlHeader(cssFilename, profileStyle)
|
|
||||||
deletePostStr += \
|
|
||||||
'<center><h1>' + postTime + ' ' + str(year) + '/' + \
|
|
||||||
str(monthNumber) + \
|
|
||||||
'/' + str(dayNumber) + '</h1></center>'
|
|
||||||
deletePostStr += '<center>'
|
|
||||||
deletePostStr += ' <p class="followText">' + \
|
|
||||||
translate['Delete this event'] + '</p>'
|
|
||||||
|
|
||||||
postActor = getAltPath(actor, domainFull, callingDomain)
|
|
||||||
deletePostStr += \
|
|
||||||
' <form method="POST" action="' + postActor + '/rmpost">\n'
|
|
||||||
deletePostStr += ' <input type="hidden" name="year" value="' + \
|
|
||||||
str(year) + '">\n'
|
|
||||||
deletePostStr += ' <input type="hidden" name="month" value="' + \
|
|
||||||
str(monthNumber) + '">\n'
|
|
||||||
deletePostStr += ' <input type="hidden" name="day" value="' + \
|
|
||||||
str(dayNumber) + '">\n'
|
|
||||||
deletePostStr += \
|
|
||||||
' <input type="hidden" name="pageNumber" value="1">\n'
|
|
||||||
deletePostStr += \
|
|
||||||
' <input type="hidden" name="messageId" value="' + \
|
|
||||||
messageId + '">\n'
|
|
||||||
deletePostStr += \
|
|
||||||
' <button type="submit" class="button" name="submitYes">' + \
|
|
||||||
translate['Yes'] + '</button>\n'
|
|
||||||
deletePostStr += \
|
|
||||||
' <a href="' + actor + '/calendar?year=' + \
|
|
||||||
str(year) + '?month=' + \
|
|
||||||
str(monthNumber) + '"><button class="button">' + \
|
|
||||||
translate['No'] + '</button></a>\n'
|
|
||||||
deletePostStr += ' </form>\n'
|
|
||||||
deletePostStr += '</center>\n'
|
|
||||||
deletePostStr += htmlFooter()
|
|
||||||
return deletePostStr
|
|
||||||
|
|
||||||
|
|
||||||
def htmlFollowConfirm(cssCache: {}, translate: {}, baseDir: str,
|
def htmlFollowConfirm(cssCache: {}, translate: {}, baseDir: str,
|
||||||
originPathStr: str,
|
originPathStr: str,
|
||||||
followActor: str,
|
followActor: str,
|
||||||
|
@ -5484,308 +5408,6 @@ def htmlUnblockConfirm(cssCache: {}, translate: {}, baseDir: str,
|
||||||
return blockStr
|
return blockStr
|
||||||
|
|
||||||
|
|
||||||
def htmlCalendarDay(cssCache: {}, translate: {},
|
|
||||||
baseDir: str, path: str,
|
|
||||||
year: int, monthNumber: int, dayNumber: int,
|
|
||||||
nickname: str, domain: str, dayEvents: [],
|
|
||||||
monthName: str, actor: str) -> str:
|
|
||||||
"""Show a day within the calendar
|
|
||||||
"""
|
|
||||||
accountDir = baseDir + '/accounts/' + nickname + '@' + domain
|
|
||||||
calendarFile = accountDir + '/.newCalendar'
|
|
||||||
if os.path.isfile(calendarFile):
|
|
||||||
os.remove(calendarFile)
|
|
||||||
|
|
||||||
cssFilename = baseDir + '/epicyon-calendar.css'
|
|
||||||
if os.path.isfile(baseDir + '/calendar.css'):
|
|
||||||
cssFilename = baseDir + '/calendar.css'
|
|
||||||
|
|
||||||
calendarStyle = getCSS(baseDir, cssFilename, cssCache)
|
|
||||||
|
|
||||||
calActor = actor
|
|
||||||
if '/users/' in actor:
|
|
||||||
calActor = '/users/' + actor.split('/users/')[1]
|
|
||||||
|
|
||||||
calendarStr = htmlHeader(cssFilename, calendarStyle)
|
|
||||||
calendarStr += '<main><table class="calendar">\n'
|
|
||||||
calendarStr += '<caption class="calendar__banner--month">\n'
|
|
||||||
calendarStr += \
|
|
||||||
' <a href="' + calActor + '/calendar?year=' + str(year) + \
|
|
||||||
'?month=' + str(monthNumber) + '">\n'
|
|
||||||
calendarStr += \
|
|
||||||
' <h1>' + str(dayNumber) + ' ' + monthName + \
|
|
||||||
'</h1></a><br><span class="year">' + str(year) + '</span>\n'
|
|
||||||
calendarStr += '</caption>\n'
|
|
||||||
calendarStr += '<tbody>\n'
|
|
||||||
|
|
||||||
iconsDir = getIconsDir(baseDir)
|
|
||||||
|
|
||||||
if dayEvents:
|
|
||||||
for eventPost in dayEvents:
|
|
||||||
eventTime = None
|
|
||||||
eventDescription = None
|
|
||||||
eventPlace = None
|
|
||||||
postId = None
|
|
||||||
# get the time place and description
|
|
||||||
for ev in eventPost:
|
|
||||||
if ev['type'] == 'Event':
|
|
||||||
if ev.get('postId'):
|
|
||||||
postId = ev['postId']
|
|
||||||
if ev.get('startTime'):
|
|
||||||
eventDate = \
|
|
||||||
datetime.strptime(ev['startTime'],
|
|
||||||
"%Y-%m-%dT%H:%M:%S%z")
|
|
||||||
eventTime = eventDate.strftime("%H:%M").strip()
|
|
||||||
if ev.get('name'):
|
|
||||||
eventDescription = ev['name'].strip()
|
|
||||||
elif ev['type'] == 'Place':
|
|
||||||
if ev.get('name'):
|
|
||||||
eventPlace = ev['name']
|
|
||||||
|
|
||||||
deleteButtonStr = ''
|
|
||||||
if postId:
|
|
||||||
deleteButtonStr = \
|
|
||||||
'<td class="calendar__day__icons"><a href="' + calActor + \
|
|
||||||
'/eventdelete?id=' + postId + '?year=' + str(year) + \
|
|
||||||
'?month=' + str(monthNumber) + '?day=' + str(dayNumber) + \
|
|
||||||
'?time=' + eventTime + \
|
|
||||||
'">\n<img class="calendardayicon" loading="lazy" alt="' + \
|
|
||||||
translate['Delete this event'] + ' |" title="' + \
|
|
||||||
translate['Delete this event'] + '" src="/' + \
|
|
||||||
iconsDir + '/delete.png" /></a></td>\n'
|
|
||||||
|
|
||||||
if eventTime and eventDescription and eventPlace:
|
|
||||||
calendarStr += \
|
|
||||||
'<tr><td class="calendar__day__time"><b>' + eventTime + \
|
|
||||||
'</b></td><td class="calendar__day__event">' + \
|
|
||||||
'<span class="place">' + \
|
|
||||||
eventPlace + '</span><br>' + eventDescription + \
|
|
||||||
'</td>' + deleteButtonStr + '</tr>\n'
|
|
||||||
elif eventTime and eventDescription and not eventPlace:
|
|
||||||
calendarStr += \
|
|
||||||
'<tr><td class="calendar__day__time"><b>' + eventTime + \
|
|
||||||
'</b></td><td class="calendar__day__event">' + \
|
|
||||||
eventDescription + '</td>' + deleteButtonStr + '</tr>\n'
|
|
||||||
elif not eventTime and eventDescription and not eventPlace:
|
|
||||||
calendarStr += \
|
|
||||||
'<tr><td class="calendar__day__time">' + \
|
|
||||||
'</td><td class="calendar__day__event">' + \
|
|
||||||
eventDescription + '</td>' + deleteButtonStr + '</tr>\n'
|
|
||||||
elif not eventTime and eventDescription and eventPlace:
|
|
||||||
calendarStr += \
|
|
||||||
'<tr><td class="calendar__day__time"></td>' + \
|
|
||||||
'<td class="calendar__day__event"><span class="place">' + \
|
|
||||||
eventPlace + '</span><br>' + eventDescription + \
|
|
||||||
'</td>' + deleteButtonStr + '</tr>\n'
|
|
||||||
elif eventTime and not eventDescription and eventPlace:
|
|
||||||
calendarStr += \
|
|
||||||
'<tr><td class="calendar__day__time"><b>' + eventTime + \
|
|
||||||
'</b></td><td class="calendar__day__event">' + \
|
|
||||||
'<span class="place">' + \
|
|
||||||
eventPlace + '</span></td>' + \
|
|
||||||
deleteButtonStr + '</tr>\n'
|
|
||||||
|
|
||||||
calendarStr += '</tbody>\n'
|
|
||||||
calendarStr += '</table></main>\n'
|
|
||||||
calendarStr += htmlFooter()
|
|
||||||
|
|
||||||
return calendarStr
|
|
||||||
|
|
||||||
|
|
||||||
def htmlCalendar(cssCache: {}, translate: {},
|
|
||||||
baseDir: str, path: str,
|
|
||||||
httpPrefix: str, domainFull: str) -> str:
|
|
||||||
"""Show the calendar for a person
|
|
||||||
"""
|
|
||||||
iconsDir = getIconsDir(baseDir)
|
|
||||||
domain = domainFull
|
|
||||||
if ':' in domainFull:
|
|
||||||
domain = domainFull.split(':')[0]
|
|
||||||
|
|
||||||
monthNumber = 0
|
|
||||||
dayNumber = None
|
|
||||||
year = 1970
|
|
||||||
actor = httpPrefix + '://' + domainFull + path.replace('/calendar', '')
|
|
||||||
if '?' in actor:
|
|
||||||
first = True
|
|
||||||
for p in actor.split('?'):
|
|
||||||
if not first:
|
|
||||||
if '=' in p:
|
|
||||||
if p.split('=')[0] == 'year':
|
|
||||||
numStr = p.split('=')[1]
|
|
||||||
if numStr.isdigit():
|
|
||||||
year = int(numStr)
|
|
||||||
elif p.split('=')[0] == 'month':
|
|
||||||
numStr = p.split('=')[1]
|
|
||||||
if numStr.isdigit():
|
|
||||||
monthNumber = int(numStr)
|
|
||||||
elif p.split('=')[0] == 'day':
|
|
||||||
numStr = p.split('=')[1]
|
|
||||||
if numStr.isdigit():
|
|
||||||
dayNumber = int(numStr)
|
|
||||||
first = False
|
|
||||||
actor = actor.split('?')[0]
|
|
||||||
|
|
||||||
currDate = datetime.now()
|
|
||||||
if year == 1970 and monthNumber == 0:
|
|
||||||
year = currDate.year
|
|
||||||
monthNumber = currDate.month
|
|
||||||
|
|
||||||
nickname = getNicknameFromActor(actor)
|
|
||||||
|
|
||||||
if os.path.isfile(baseDir + '/img/calendar-background.png'):
|
|
||||||
if not os.path.isfile(baseDir + '/accounts/calendar-background.png'):
|
|
||||||
copyfile(baseDir + '/img/calendar-background.png',
|
|
||||||
baseDir + '/accounts/calendar-background.png')
|
|
||||||
|
|
||||||
months = ('January', 'February', 'March', 'April',
|
|
||||||
'May', 'June', 'July', 'August', 'September',
|
|
||||||
'October', 'November', 'December')
|
|
||||||
monthName = translate[months[monthNumber - 1]]
|
|
||||||
|
|
||||||
if dayNumber:
|
|
||||||
dayEvents = None
|
|
||||||
events = \
|
|
||||||
getTodaysEvents(baseDir, nickname, domain,
|
|
||||||
year, monthNumber, dayNumber)
|
|
||||||
if events:
|
|
||||||
if events.get(str(dayNumber)):
|
|
||||||
dayEvents = events[str(dayNumber)]
|
|
||||||
return htmlCalendarDay(cssCache, translate, baseDir, path,
|
|
||||||
year, monthNumber, dayNumber,
|
|
||||||
nickname, domain, dayEvents,
|
|
||||||
monthName, actor)
|
|
||||||
|
|
||||||
events = \
|
|
||||||
getCalendarEvents(baseDir, nickname, domain, year, monthNumber)
|
|
||||||
|
|
||||||
prevYear = year
|
|
||||||
prevMonthNumber = monthNumber - 1
|
|
||||||
if prevMonthNumber < 1:
|
|
||||||
prevMonthNumber = 12
|
|
||||||
prevYear = year - 1
|
|
||||||
|
|
||||||
nextYear = year
|
|
||||||
nextMonthNumber = monthNumber + 1
|
|
||||||
if nextMonthNumber > 12:
|
|
||||||
nextMonthNumber = 1
|
|
||||||
nextYear = year + 1
|
|
||||||
|
|
||||||
print('Calendar year=' + str(year) + ' month=' + str(monthNumber) +
|
|
||||||
' ' + str(weekDayOfMonthStart(monthNumber, year)))
|
|
||||||
|
|
||||||
if monthNumber < 12:
|
|
||||||
daysInMonth = \
|
|
||||||
(date(year, monthNumber + 1, 1) - date(year, monthNumber, 1)).days
|
|
||||||
else:
|
|
||||||
daysInMonth = \
|
|
||||||
(date(year + 1, 1, 1) - date(year, monthNumber, 1)).days
|
|
||||||
# print('daysInMonth ' + str(monthNumber) + ': ' + str(daysInMonth))
|
|
||||||
|
|
||||||
cssFilename = baseDir + '/epicyon-calendar.css'
|
|
||||||
if os.path.isfile(baseDir + '/calendar.css'):
|
|
||||||
cssFilename = baseDir + '/calendar.css'
|
|
||||||
|
|
||||||
calendarStyle = getCSS(baseDir, cssFilename, cssCache)
|
|
||||||
|
|
||||||
calActor = actor
|
|
||||||
if '/users/' in actor:
|
|
||||||
calActor = '/users/' + actor.split('/users/')[1]
|
|
||||||
|
|
||||||
calendarStr = htmlHeader(cssFilename, calendarStyle)
|
|
||||||
calendarStr += '<main><table class="calendar">\n'
|
|
||||||
calendarStr += '<caption class="calendar__banner--month">\n'
|
|
||||||
calendarStr += \
|
|
||||||
' <a href="' + calActor + '/calendar?year=' + str(prevYear) + \
|
|
||||||
'?month=' + str(prevMonthNumber) + '">'
|
|
||||||
calendarStr += \
|
|
||||||
' <img loading="lazy" alt="' + translate['Previous month'] + \
|
|
||||||
'" title="' + translate['Previous month'] + '" src="/' + iconsDir + \
|
|
||||||
'/prev.png" class="buttonprev"/></a>\n'
|
|
||||||
calendarStr += ' <a href="' + calActor + '/inbox" title="'
|
|
||||||
calendarStr += translate['Switch to timeline view'] + '">'
|
|
||||||
calendarStr += ' <h1>' + monthName + '</h1></a>\n'
|
|
||||||
calendarStr += \
|
|
||||||
' <a href="' + calActor + '/calendar?year=' + str(nextYear) + \
|
|
||||||
'?month=' + str(nextMonthNumber) + '">'
|
|
||||||
calendarStr += \
|
|
||||||
' <img loading="lazy" alt="' + translate['Next month'] + \
|
|
||||||
'" title="' + translate['Next month'] + '" src="/' + iconsDir + \
|
|
||||||
'/prev.png" class="buttonnext"/></a>\n'
|
|
||||||
calendarStr += '</caption>\n'
|
|
||||||
calendarStr += '<thead>\n'
|
|
||||||
calendarStr += '<tr>\n'
|
|
||||||
calendarStr += ' <th class="calendar__day__header">' + \
|
|
||||||
translate['Sun'] + '</th>\n'
|
|
||||||
calendarStr += ' <th class="calendar__day__header">' + \
|
|
||||||
translate['Mon'] + '</th>\n'
|
|
||||||
calendarStr += ' <th class="calendar__day__header">' + \
|
|
||||||
translate['Tue'] + '</th>\n'
|
|
||||||
calendarStr += ' <th class="calendar__day__header">' + \
|
|
||||||
translate['Wed'] + '</th>\n'
|
|
||||||
calendarStr += ' <th class="calendar__day__header">' + \
|
|
||||||
translate['Thu'] + '</th>\n'
|
|
||||||
calendarStr += ' <th class="calendar__day__header">' + \
|
|
||||||
translate['Fri'] + '</th>\n'
|
|
||||||
calendarStr += ' <th class="calendar__day__header">' + \
|
|
||||||
translate['Sat'] + '</th>\n'
|
|
||||||
calendarStr += '</tr>\n'
|
|
||||||
calendarStr += '</thead>\n'
|
|
||||||
calendarStr += '<tbody>\n'
|
|
||||||
|
|
||||||
dayOfMonth = 0
|
|
||||||
dow = weekDayOfMonthStart(monthNumber, year)
|
|
||||||
for weekOfMonth in range(1, 7):
|
|
||||||
if dayOfMonth == daysInMonth:
|
|
||||||
continue
|
|
||||||
calendarStr += ' <tr>\n'
|
|
||||||
for dayNumber in range(1, 8):
|
|
||||||
if (weekOfMonth > 1 and dayOfMonth < daysInMonth) or \
|
|
||||||
(weekOfMonth == 1 and dayNumber >= dow):
|
|
||||||
dayOfMonth += 1
|
|
||||||
|
|
||||||
isToday = False
|
|
||||||
if year == currDate.year:
|
|
||||||
if currDate.month == monthNumber:
|
|
||||||
if dayOfMonth == currDate.day:
|
|
||||||
isToday = True
|
|
||||||
if events.get(str(dayOfMonth)):
|
|
||||||
url = calActor + '/calendar?year=' + \
|
|
||||||
str(year) + '?month=' + \
|
|
||||||
str(monthNumber) + '?day=' + str(dayOfMonth)
|
|
||||||
dayLink = '<a href="' + url + '">' + \
|
|
||||||
str(dayOfMonth) + '</a>'
|
|
||||||
# there are events for this day
|
|
||||||
if not isToday:
|
|
||||||
calendarStr += \
|
|
||||||
' <td class="calendar__day__cell" ' + \
|
|
||||||
'data-event="">' + \
|
|
||||||
dayLink + '</td>\n'
|
|
||||||
else:
|
|
||||||
calendarStr += \
|
|
||||||
' <td class="calendar__day__cell" ' + \
|
|
||||||
'data-today-event="">' + \
|
|
||||||
dayLink + '</td>\n'
|
|
||||||
else:
|
|
||||||
# No events today
|
|
||||||
if not isToday:
|
|
||||||
calendarStr += \
|
|
||||||
' <td class="calendar__day__cell">' + \
|
|
||||||
str(dayOfMonth) + '</td>\n'
|
|
||||||
else:
|
|
||||||
calendarStr += \
|
|
||||||
' <td class="calendar__day__cell" ' + \
|
|
||||||
'data-today="">' + str(dayOfMonth) + '</td>\n'
|
|
||||||
else:
|
|
||||||
calendarStr += ' <td class="calendar__day__cell"></td>\n'
|
|
||||||
calendarStr += ' </tr>\n'
|
|
||||||
|
|
||||||
calendarStr += '</tbody>\n'
|
|
||||||
calendarStr += '</table></main>\n'
|
|
||||||
calendarStr += htmlFooter()
|
|
||||||
return calendarStr
|
|
||||||
|
|
||||||
|
|
||||||
def htmlProfileAfterSearch(cssCache: {},
|
def htmlProfileAfterSearch(cssCache: {},
|
||||||
recentPostsCache: {}, maxRecentPosts: int,
|
recentPostsCache: {}, maxRecentPosts: int,
|
||||||
translate: {},
|
translate: {},
|
||||||
|
|
|
@ -0,0 +1,398 @@
|
||||||
|
__filename__ = "webapp_calendar.py"
|
||||||
|
__author__ = "Bob Mottram"
|
||||||
|
__license__ = "AGPL3+"
|
||||||
|
__version__ = "1.1.0"
|
||||||
|
__maintainer__ = "Bob Mottram"
|
||||||
|
__email__ = "bob@freedombone.net"
|
||||||
|
__status__ = "Production"
|
||||||
|
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import date
|
||||||
|
from shutil import copyfile
|
||||||
|
from utils import getNicknameFromActor
|
||||||
|
from utils import getDomainFromActor
|
||||||
|
from utils import locatePost
|
||||||
|
from utils import loadJson
|
||||||
|
from utils import getCSS
|
||||||
|
from utils import weekDayOfMonthStart
|
||||||
|
from happening import getTodaysEvents
|
||||||
|
from happening import getCalendarEvents
|
||||||
|
from webapp_utils import htmlHeader
|
||||||
|
from webapp_utils import htmlFooter
|
||||||
|
from webapp_utils import getAltPath
|
||||||
|
from webapp_utils import getIconsDir
|
||||||
|
|
||||||
|
|
||||||
|
def htmlCalendarDeleteConfirm(cssCache: {}, translate: {}, baseDir: str,
|
||||||
|
path: str, httpPrefix: str,
|
||||||
|
domainFull: str, postId: str, postTime: str,
|
||||||
|
year: int, monthNumber: int,
|
||||||
|
dayNumber: int, callingDomain: str) -> str:
|
||||||
|
"""Shows a screen asking to confirm the deletion of a calendar event
|
||||||
|
"""
|
||||||
|
nickname = getNicknameFromActor(path)
|
||||||
|
actor = httpPrefix + '://' + domainFull + '/users/' + nickname
|
||||||
|
domain, port = getDomainFromActor(actor)
|
||||||
|
messageId = actor + '/statuses/' + postId
|
||||||
|
|
||||||
|
postFilename = locatePost(baseDir, nickname, domain, messageId)
|
||||||
|
if not postFilename:
|
||||||
|
return None
|
||||||
|
|
||||||
|
postJsonObject = loadJson(postFilename)
|
||||||
|
if not postJsonObject:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if os.path.isfile(baseDir + '/img/delete-background.png'):
|
||||||
|
if not os.path.isfile(baseDir + '/accounts/delete-background.png'):
|
||||||
|
copyfile(baseDir + '/img/delete-background.png',
|
||||||
|
baseDir + '/accounts/delete-background.png')
|
||||||
|
|
||||||
|
deletePostStr = None
|
||||||
|
cssFilename = baseDir + '/epicyon-profile.css'
|
||||||
|
if os.path.isfile(baseDir + '/epicyon.css'):
|
||||||
|
cssFilename = baseDir + '/epicyon.css'
|
||||||
|
|
||||||
|
profileStyle = getCSS(baseDir, cssFilename, cssCache)
|
||||||
|
if profileStyle:
|
||||||
|
if httpPrefix != 'https':
|
||||||
|
profileStyle = profileStyle.replace('https://',
|
||||||
|
httpPrefix + '://')
|
||||||
|
deletePostStr = htmlHeader(cssFilename, profileStyle)
|
||||||
|
deletePostStr += \
|
||||||
|
'<center><h1>' + postTime + ' ' + str(year) + '/' + \
|
||||||
|
str(monthNumber) + \
|
||||||
|
'/' + str(dayNumber) + '</h1></center>'
|
||||||
|
deletePostStr += '<center>'
|
||||||
|
deletePostStr += ' <p class="followText">' + \
|
||||||
|
translate['Delete this event'] + '</p>'
|
||||||
|
|
||||||
|
postActor = getAltPath(actor, domainFull, callingDomain)
|
||||||
|
deletePostStr += \
|
||||||
|
' <form method="POST" action="' + postActor + '/rmpost">\n'
|
||||||
|
deletePostStr += ' <input type="hidden" name="year" value="' + \
|
||||||
|
str(year) + '">\n'
|
||||||
|
deletePostStr += ' <input type="hidden" name="month" value="' + \
|
||||||
|
str(monthNumber) + '">\n'
|
||||||
|
deletePostStr += ' <input type="hidden" name="day" value="' + \
|
||||||
|
str(dayNumber) + '">\n'
|
||||||
|
deletePostStr += \
|
||||||
|
' <input type="hidden" name="pageNumber" value="1">\n'
|
||||||
|
deletePostStr += \
|
||||||
|
' <input type="hidden" name="messageId" value="' + \
|
||||||
|
messageId + '">\n'
|
||||||
|
deletePostStr += \
|
||||||
|
' <button type="submit" class="button" name="submitYes">' + \
|
||||||
|
translate['Yes'] + '</button>\n'
|
||||||
|
deletePostStr += \
|
||||||
|
' <a href="' + actor + '/calendar?year=' + \
|
||||||
|
str(year) + '?month=' + \
|
||||||
|
str(monthNumber) + '"><button class="button">' + \
|
||||||
|
translate['No'] + '</button></a>\n'
|
||||||
|
deletePostStr += ' </form>\n'
|
||||||
|
deletePostStr += '</center>\n'
|
||||||
|
deletePostStr += htmlFooter()
|
||||||
|
return deletePostStr
|
||||||
|
|
||||||
|
|
||||||
|
def htmlCalendarDay(cssCache: {}, translate: {},
|
||||||
|
baseDir: str, path: str,
|
||||||
|
year: int, monthNumber: int, dayNumber: int,
|
||||||
|
nickname: str, domain: str, dayEvents: [],
|
||||||
|
monthName: str, actor: str) -> str:
|
||||||
|
"""Show a day within the calendar
|
||||||
|
"""
|
||||||
|
accountDir = baseDir + '/accounts/' + nickname + '@' + domain
|
||||||
|
calendarFile = accountDir + '/.newCalendar'
|
||||||
|
if os.path.isfile(calendarFile):
|
||||||
|
os.remove(calendarFile)
|
||||||
|
|
||||||
|
cssFilename = baseDir + '/epicyon-calendar.css'
|
||||||
|
if os.path.isfile(baseDir + '/calendar.css'):
|
||||||
|
cssFilename = baseDir + '/calendar.css'
|
||||||
|
|
||||||
|
calendarStyle = getCSS(baseDir, cssFilename, cssCache)
|
||||||
|
|
||||||
|
calActor = actor
|
||||||
|
if '/users/' in actor:
|
||||||
|
calActor = '/users/' + actor.split('/users/')[1]
|
||||||
|
|
||||||
|
calendarStr = htmlHeader(cssFilename, calendarStyle)
|
||||||
|
calendarStr += '<main><table class="calendar">\n'
|
||||||
|
calendarStr += '<caption class="calendar__banner--month">\n'
|
||||||
|
calendarStr += \
|
||||||
|
' <a href="' + calActor + '/calendar?year=' + str(year) + \
|
||||||
|
'?month=' + str(monthNumber) + '">\n'
|
||||||
|
calendarStr += \
|
||||||
|
' <h1>' + str(dayNumber) + ' ' + monthName + \
|
||||||
|
'</h1></a><br><span class="year">' + str(year) + '</span>\n'
|
||||||
|
calendarStr += '</caption>\n'
|
||||||
|
calendarStr += '<tbody>\n'
|
||||||
|
|
||||||
|
iconsDir = getIconsDir(baseDir)
|
||||||
|
|
||||||
|
if dayEvents:
|
||||||
|
for eventPost in dayEvents:
|
||||||
|
eventTime = None
|
||||||
|
eventDescription = None
|
||||||
|
eventPlace = None
|
||||||
|
postId = None
|
||||||
|
# get the time place and description
|
||||||
|
for ev in eventPost:
|
||||||
|
if ev['type'] == 'Event':
|
||||||
|
if ev.get('postId'):
|
||||||
|
postId = ev['postId']
|
||||||
|
if ev.get('startTime'):
|
||||||
|
eventDate = \
|
||||||
|
datetime.strptime(ev['startTime'],
|
||||||
|
"%Y-%m-%dT%H:%M:%S%z")
|
||||||
|
eventTime = eventDate.strftime("%H:%M").strip()
|
||||||
|
if ev.get('name'):
|
||||||
|
eventDescription = ev['name'].strip()
|
||||||
|
elif ev['type'] == 'Place':
|
||||||
|
if ev.get('name'):
|
||||||
|
eventPlace = ev['name']
|
||||||
|
|
||||||
|
deleteButtonStr = ''
|
||||||
|
if postId:
|
||||||
|
deleteButtonStr = \
|
||||||
|
'<td class="calendar__day__icons"><a href="' + calActor + \
|
||||||
|
'/eventdelete?id=' + postId + '?year=' + str(year) + \
|
||||||
|
'?month=' + str(monthNumber) + '?day=' + str(dayNumber) + \
|
||||||
|
'?time=' + eventTime + \
|
||||||
|
'">\n<img class="calendardayicon" loading="lazy" alt="' + \
|
||||||
|
translate['Delete this event'] + ' |" title="' + \
|
||||||
|
translate['Delete this event'] + '" src="/' + \
|
||||||
|
iconsDir + '/delete.png" /></a></td>\n'
|
||||||
|
|
||||||
|
if eventTime and eventDescription and eventPlace:
|
||||||
|
calendarStr += \
|
||||||
|
'<tr><td class="calendar__day__time"><b>' + eventTime + \
|
||||||
|
'</b></td><td class="calendar__day__event">' + \
|
||||||
|
'<span class="place">' + \
|
||||||
|
eventPlace + '</span><br>' + eventDescription + \
|
||||||
|
'</td>' + deleteButtonStr + '</tr>\n'
|
||||||
|
elif eventTime and eventDescription and not eventPlace:
|
||||||
|
calendarStr += \
|
||||||
|
'<tr><td class="calendar__day__time"><b>' + eventTime + \
|
||||||
|
'</b></td><td class="calendar__day__event">' + \
|
||||||
|
eventDescription + '</td>' + deleteButtonStr + '</tr>\n'
|
||||||
|
elif not eventTime and eventDescription and not eventPlace:
|
||||||
|
calendarStr += \
|
||||||
|
'<tr><td class="calendar__day__time">' + \
|
||||||
|
'</td><td class="calendar__day__event">' + \
|
||||||
|
eventDescription + '</td>' + deleteButtonStr + '</tr>\n'
|
||||||
|
elif not eventTime and eventDescription and eventPlace:
|
||||||
|
calendarStr += \
|
||||||
|
'<tr><td class="calendar__day__time"></td>' + \
|
||||||
|
'<td class="calendar__day__event"><span class="place">' + \
|
||||||
|
eventPlace + '</span><br>' + eventDescription + \
|
||||||
|
'</td>' + deleteButtonStr + '</tr>\n'
|
||||||
|
elif eventTime and not eventDescription and eventPlace:
|
||||||
|
calendarStr += \
|
||||||
|
'<tr><td class="calendar__day__time"><b>' + eventTime + \
|
||||||
|
'</b></td><td class="calendar__day__event">' + \
|
||||||
|
'<span class="place">' + \
|
||||||
|
eventPlace + '</span></td>' + \
|
||||||
|
deleteButtonStr + '</tr>\n'
|
||||||
|
|
||||||
|
calendarStr += '</tbody>\n'
|
||||||
|
calendarStr += '</table></main>\n'
|
||||||
|
calendarStr += htmlFooter()
|
||||||
|
|
||||||
|
return calendarStr
|
||||||
|
|
||||||
|
|
||||||
|
def htmlCalendar(cssCache: {}, translate: {},
|
||||||
|
baseDir: str, path: str,
|
||||||
|
httpPrefix: str, domainFull: str) -> str:
|
||||||
|
"""Show the calendar for a person
|
||||||
|
"""
|
||||||
|
iconsDir = getIconsDir(baseDir)
|
||||||
|
domain = domainFull
|
||||||
|
if ':' in domainFull:
|
||||||
|
domain = domainFull.split(':')[0]
|
||||||
|
|
||||||
|
monthNumber = 0
|
||||||
|
dayNumber = None
|
||||||
|
year = 1970
|
||||||
|
actor = httpPrefix + '://' + domainFull + path.replace('/calendar', '')
|
||||||
|
if '?' in actor:
|
||||||
|
first = True
|
||||||
|
for p in actor.split('?'):
|
||||||
|
if not first:
|
||||||
|
if '=' in p:
|
||||||
|
if p.split('=')[0] == 'year':
|
||||||
|
numStr = p.split('=')[1]
|
||||||
|
if numStr.isdigit():
|
||||||
|
year = int(numStr)
|
||||||
|
elif p.split('=')[0] == 'month':
|
||||||
|
numStr = p.split('=')[1]
|
||||||
|
if numStr.isdigit():
|
||||||
|
monthNumber = int(numStr)
|
||||||
|
elif p.split('=')[0] == 'day':
|
||||||
|
numStr = p.split('=')[1]
|
||||||
|
if numStr.isdigit():
|
||||||
|
dayNumber = int(numStr)
|
||||||
|
first = False
|
||||||
|
actor = actor.split('?')[0]
|
||||||
|
|
||||||
|
currDate = datetime.now()
|
||||||
|
if year == 1970 and monthNumber == 0:
|
||||||
|
year = currDate.year
|
||||||
|
monthNumber = currDate.month
|
||||||
|
|
||||||
|
nickname = getNicknameFromActor(actor)
|
||||||
|
|
||||||
|
if os.path.isfile(baseDir + '/img/calendar-background.png'):
|
||||||
|
if not os.path.isfile(baseDir + '/accounts/calendar-background.png'):
|
||||||
|
copyfile(baseDir + '/img/calendar-background.png',
|
||||||
|
baseDir + '/accounts/calendar-background.png')
|
||||||
|
|
||||||
|
months = ('January', 'February', 'March', 'April',
|
||||||
|
'May', 'June', 'July', 'August', 'September',
|
||||||
|
'October', 'November', 'December')
|
||||||
|
monthName = translate[months[monthNumber - 1]]
|
||||||
|
|
||||||
|
if dayNumber:
|
||||||
|
dayEvents = None
|
||||||
|
events = \
|
||||||
|
getTodaysEvents(baseDir, nickname, domain,
|
||||||
|
year, monthNumber, dayNumber)
|
||||||
|
if events:
|
||||||
|
if events.get(str(dayNumber)):
|
||||||
|
dayEvents = events[str(dayNumber)]
|
||||||
|
return htmlCalendarDay(cssCache, translate, baseDir, path,
|
||||||
|
year, monthNumber, dayNumber,
|
||||||
|
nickname, domain, dayEvents,
|
||||||
|
monthName, actor)
|
||||||
|
|
||||||
|
events = \
|
||||||
|
getCalendarEvents(baseDir, nickname, domain, year, monthNumber)
|
||||||
|
|
||||||
|
prevYear = year
|
||||||
|
prevMonthNumber = monthNumber - 1
|
||||||
|
if prevMonthNumber < 1:
|
||||||
|
prevMonthNumber = 12
|
||||||
|
prevYear = year - 1
|
||||||
|
|
||||||
|
nextYear = year
|
||||||
|
nextMonthNumber = monthNumber + 1
|
||||||
|
if nextMonthNumber > 12:
|
||||||
|
nextMonthNumber = 1
|
||||||
|
nextYear = year + 1
|
||||||
|
|
||||||
|
print('Calendar year=' + str(year) + ' month=' + str(monthNumber) +
|
||||||
|
' ' + str(weekDayOfMonthStart(monthNumber, year)))
|
||||||
|
|
||||||
|
if monthNumber < 12:
|
||||||
|
daysInMonth = \
|
||||||
|
(date(year, monthNumber + 1, 1) - date(year, monthNumber, 1)).days
|
||||||
|
else:
|
||||||
|
daysInMonth = \
|
||||||
|
(date(year + 1, 1, 1) - date(year, monthNumber, 1)).days
|
||||||
|
# print('daysInMonth ' + str(monthNumber) + ': ' + str(daysInMonth))
|
||||||
|
|
||||||
|
cssFilename = baseDir + '/epicyon-calendar.css'
|
||||||
|
if os.path.isfile(baseDir + '/calendar.css'):
|
||||||
|
cssFilename = baseDir + '/calendar.css'
|
||||||
|
|
||||||
|
calendarStyle = getCSS(baseDir, cssFilename, cssCache)
|
||||||
|
|
||||||
|
calActor = actor
|
||||||
|
if '/users/' in actor:
|
||||||
|
calActor = '/users/' + actor.split('/users/')[1]
|
||||||
|
|
||||||
|
calendarStr = htmlHeader(cssFilename, calendarStyle)
|
||||||
|
calendarStr += '<main><table class="calendar">\n'
|
||||||
|
calendarStr += '<caption class="calendar__banner--month">\n'
|
||||||
|
calendarStr += \
|
||||||
|
' <a href="' + calActor + '/calendar?year=' + str(prevYear) + \
|
||||||
|
'?month=' + str(prevMonthNumber) + '">'
|
||||||
|
calendarStr += \
|
||||||
|
' <img loading="lazy" alt="' + translate['Previous month'] + \
|
||||||
|
'" title="' + translate['Previous month'] + '" src="/' + iconsDir + \
|
||||||
|
'/prev.png" class="buttonprev"/></a>\n'
|
||||||
|
calendarStr += ' <a href="' + calActor + '/inbox" title="'
|
||||||
|
calendarStr += translate['Switch to timeline view'] + '">'
|
||||||
|
calendarStr += ' <h1>' + monthName + '</h1></a>\n'
|
||||||
|
calendarStr += \
|
||||||
|
' <a href="' + calActor + '/calendar?year=' + str(nextYear) + \
|
||||||
|
'?month=' + str(nextMonthNumber) + '">'
|
||||||
|
calendarStr += \
|
||||||
|
' <img loading="lazy" alt="' + translate['Next month'] + \
|
||||||
|
'" title="' + translate['Next month'] + '" src="/' + iconsDir + \
|
||||||
|
'/prev.png" class="buttonnext"/></a>\n'
|
||||||
|
calendarStr += '</caption>\n'
|
||||||
|
calendarStr += '<thead>\n'
|
||||||
|
calendarStr += '<tr>\n'
|
||||||
|
calendarStr += ' <th class="calendar__day__header">' + \
|
||||||
|
translate['Sun'] + '</th>\n'
|
||||||
|
calendarStr += ' <th class="calendar__day__header">' + \
|
||||||
|
translate['Mon'] + '</th>\n'
|
||||||
|
calendarStr += ' <th class="calendar__day__header">' + \
|
||||||
|
translate['Tue'] + '</th>\n'
|
||||||
|
calendarStr += ' <th class="calendar__day__header">' + \
|
||||||
|
translate['Wed'] + '</th>\n'
|
||||||
|
calendarStr += ' <th class="calendar__day__header">' + \
|
||||||
|
translate['Thu'] + '</th>\n'
|
||||||
|
calendarStr += ' <th class="calendar__day__header">' + \
|
||||||
|
translate['Fri'] + '</th>\n'
|
||||||
|
calendarStr += ' <th class="calendar__day__header">' + \
|
||||||
|
translate['Sat'] + '</th>\n'
|
||||||
|
calendarStr += '</tr>\n'
|
||||||
|
calendarStr += '</thead>\n'
|
||||||
|
calendarStr += '<tbody>\n'
|
||||||
|
|
||||||
|
dayOfMonth = 0
|
||||||
|
dow = weekDayOfMonthStart(monthNumber, year)
|
||||||
|
for weekOfMonth in range(1, 7):
|
||||||
|
if dayOfMonth == daysInMonth:
|
||||||
|
continue
|
||||||
|
calendarStr += ' <tr>\n'
|
||||||
|
for dayNumber in range(1, 8):
|
||||||
|
if (weekOfMonth > 1 and dayOfMonth < daysInMonth) or \
|
||||||
|
(weekOfMonth == 1 and dayNumber >= dow):
|
||||||
|
dayOfMonth += 1
|
||||||
|
|
||||||
|
isToday = False
|
||||||
|
if year == currDate.year:
|
||||||
|
if currDate.month == monthNumber:
|
||||||
|
if dayOfMonth == currDate.day:
|
||||||
|
isToday = True
|
||||||
|
if events.get(str(dayOfMonth)):
|
||||||
|
url = calActor + '/calendar?year=' + \
|
||||||
|
str(year) + '?month=' + \
|
||||||
|
str(monthNumber) + '?day=' + str(dayOfMonth)
|
||||||
|
dayLink = '<a href="' + url + '">' + \
|
||||||
|
str(dayOfMonth) + '</a>'
|
||||||
|
# there are events for this day
|
||||||
|
if not isToday:
|
||||||
|
calendarStr += \
|
||||||
|
' <td class="calendar__day__cell" ' + \
|
||||||
|
'data-event="">' + \
|
||||||
|
dayLink + '</td>\n'
|
||||||
|
else:
|
||||||
|
calendarStr += \
|
||||||
|
' <td class="calendar__day__cell" ' + \
|
||||||
|
'data-today-event="">' + \
|
||||||
|
dayLink + '</td>\n'
|
||||||
|
else:
|
||||||
|
# No events today
|
||||||
|
if not isToday:
|
||||||
|
calendarStr += \
|
||||||
|
' <td class="calendar__day__cell">' + \
|
||||||
|
str(dayOfMonth) + '</td>\n'
|
||||||
|
else:
|
||||||
|
calendarStr += \
|
||||||
|
' <td class="calendar__day__cell" ' + \
|
||||||
|
'data-today="">' + str(dayOfMonth) + '</td>\n'
|
||||||
|
else:
|
||||||
|
calendarStr += ' <td class="calendar__day__cell"></td>\n'
|
||||||
|
calendarStr += ' </tr>\n'
|
||||||
|
|
||||||
|
calendarStr += '</tbody>\n'
|
||||||
|
calendarStr += '</table></main>\n'
|
||||||
|
calendarStr += htmlFooter()
|
||||||
|
return calendarStr
|
Loading…
Reference in New Issue