mirror of https://gitlab.com/bashrc2/epicyon
				
				
				
			Snake case
							parent
							
								
									63334f8250
								
							
						
					
					
						commit
						2099cad0ac
					
				| 
						 | 
				
			
			@ -282,14 +282,14 @@ def _desktop_clear_screen() -> None:
 | 
			
		|||
def _desktop_show_banner() -> None:
 | 
			
		||||
    """Shows the banner at the top
 | 
			
		||||
    """
 | 
			
		||||
    bannerFilename = 'banner.txt'
 | 
			
		||||
    if not os.path.isfile(bannerFilename):
 | 
			
		||||
    banner_filename = 'banner.txt'
 | 
			
		||||
    if not os.path.isfile(banner_filename):
 | 
			
		||||
        bannerTheme = 'starlight'
 | 
			
		||||
        bannerFilename = 'theme/' + bannerTheme + '/banner.txt'
 | 
			
		||||
        if not os.path.isfile(bannerFilename):
 | 
			
		||||
        banner_filename = 'theme/' + bannerTheme + '/banner.txt'
 | 
			
		||||
        if not os.path.isfile(banner_filename):
 | 
			
		||||
            return
 | 
			
		||||
    with open(bannerFilename, 'r') as bannerFile:
 | 
			
		||||
        banner = bannerFile.read()
 | 
			
		||||
    with open(banner_filename, 'r') as banner_file:
 | 
			
		||||
        banner = banner_file.read()
 | 
			
		||||
        if banner:
 | 
			
		||||
            print(banner + '\n')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,33 +16,33 @@ from utils import save_json
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def fitness_performance(startTime, fitnessState: {},
 | 
			
		||||
                        fitnessId: str, watchPoint: str, debug: bool) -> None:
 | 
			
		||||
                        fitnessId: str, watch_point: str, debug: bool) -> None:
 | 
			
		||||
    """Log a performance watchpoint
 | 
			
		||||
    """
 | 
			
		||||
    if 'performance' not in fitnessState:
 | 
			
		||||
        fitnessState['performance'] = {}
 | 
			
		||||
    if fitnessId not in fitnessState['performance']:
 | 
			
		||||
        fitnessState['performance'][fitnessId] = {}
 | 
			
		||||
    if watchPoint not in fitnessState['performance'][fitnessId]:
 | 
			
		||||
        fitnessState['performance'][fitnessId][watchPoint] = {
 | 
			
		||||
    if watch_point not in fitnessState['performance'][fitnessId]:
 | 
			
		||||
        fitnessState['performance'][fitnessId][watch_point] = {
 | 
			
		||||
            "total": float(0),
 | 
			
		||||
            "ctr": int(0)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    timeDiff = float(time.time() - startTime)
 | 
			
		||||
    time_diff = float(time.time() - startTime)
 | 
			
		||||
 | 
			
		||||
    fitnessState['performance'][fitnessId][watchPoint]['total'] += timeDiff
 | 
			
		||||
    fitnessState['performance'][fitnessId][watchPoint]['ctr'] += 1
 | 
			
		||||
    if fitnessState['performance'][fitnessId][watchPoint]['ctr'] >= 1024:
 | 
			
		||||
        fitnessState['performance'][fitnessId][watchPoint]['total'] /= 2
 | 
			
		||||
        fitnessState['performance'][fitnessId][watchPoint]['ctr'] = \
 | 
			
		||||
            int(fitnessState['performance'][fitnessId][watchPoint]['ctr'] / 2)
 | 
			
		||||
    fitnessState['performance'][fitnessId][watch_point]['total'] += time_diff
 | 
			
		||||
    fitnessState['performance'][fitnessId][watch_point]['ctr'] += 1
 | 
			
		||||
    if fitnessState['performance'][fitnessId][watch_point]['ctr'] >= 1024:
 | 
			
		||||
        fitnessState['performance'][fitnessId][watch_point]['total'] /= 2
 | 
			
		||||
        fitnessState['performance'][fitnessId][watch_point]['ctr'] = \
 | 
			
		||||
            int(fitnessState['performance'][fitnessId][watch_point]['ctr'] / 2)
 | 
			
		||||
 | 
			
		||||
    if debug:
 | 
			
		||||
        ctr = fitnessState['performance'][fitnessId][watchPoint]['ctr']
 | 
			
		||||
        total = fitnessState['performance'][fitnessId][watchPoint]['total']
 | 
			
		||||
        ctr = fitnessState['performance'][fitnessId][watch_point]['ctr']
 | 
			
		||||
        total = fitnessState['performance'][fitnessId][watch_point]['total']
 | 
			
		||||
        print('FITNESS: performance/' + fitnessId + '/' +
 | 
			
		||||
              watchPoint + '/' + str(total * 1000 / ctr))
 | 
			
		||||
              watch_point + '/' + str(total * 1000 / ctr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def sorted_watch_points(fitness: {}, fitnessId: str) -> []:
 | 
			
		||||
| 
						 | 
				
			
			@ -54,12 +54,12 @@ def sorted_watch_points(fitness: {}, fitnessId: str) -> []:
 | 
			
		|||
    if not fitness['performance'].get(fitnessId):
 | 
			
		||||
        return []
 | 
			
		||||
    result = []
 | 
			
		||||
    for watchPoint, item in fitness['performance'][fitnessId].items():
 | 
			
		||||
    for watch_point, item in fitness['performance'][fitnessId].items():
 | 
			
		||||
        if not item.get('total'):
 | 
			
		||||
            continue
 | 
			
		||||
        averageTime = item['total'] * 1000 / item['ctr']
 | 
			
		||||
        averageTimeStr = str(averageTime).zfill(8)
 | 
			
		||||
        result.append(averageTimeStr + ' ' + watchPoint)
 | 
			
		||||
        average_time = item['total'] * 1000 / item['ctr']
 | 
			
		||||
        average_time_str = str(average_time).zfill(8)
 | 
			
		||||
        result.append(average_time_str + ' ' + watch_point)
 | 
			
		||||
    result.sort(reverse=True)
 | 
			
		||||
    return result
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,16 +68,17 @@ def html_watch_points_graph(base_dir: str, fitness: {}, fitnessId: str,
 | 
			
		|||
                            maxEntries: int) -> str:
 | 
			
		||||
    """Returns the html for a graph of watchpoints
 | 
			
		||||
    """
 | 
			
		||||
    watchPointsList = sorted_watch_points(fitness, fitnessId)
 | 
			
		||||
    watch_points_list = sorted_watch_points(fitness, fitnessId)
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-graph.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-graph.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/graph.css'):
 | 
			
		||||
        cssFilename = base_dir + '/graph.css'
 | 
			
		||||
        css_filename = base_dir + '/graph.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
    instance_title = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    htmlStr = html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
    html_str = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instance_title, None)
 | 
			
		||||
    html_str += \
 | 
			
		||||
        '<table class="graph">\n' + \
 | 
			
		||||
        '<caption>Watchpoints for ' + fitnessId + '</caption>\n' + \
 | 
			
		||||
        '<thead>\n' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -88,23 +89,23 @@ def html_watch_points_graph(base_dir: str, fitness: {}, fitnessId: str,
 | 
			
		|||
        '</thead><tbody>\n'
 | 
			
		||||
 | 
			
		||||
    # get the maximum time
 | 
			
		||||
    maxAverageTime = float(1)
 | 
			
		||||
    if len(watchPointsList) > 0:
 | 
			
		||||
        maxAverageTime = float(watchPointsList[0].split(' ')[0])
 | 
			
		||||
    for watchPoint in watchPointsList:
 | 
			
		||||
        averageTime = float(watchPoint.split(' ')[0])
 | 
			
		||||
        if averageTime > maxAverageTime:
 | 
			
		||||
            maxAverageTime = averageTime
 | 
			
		||||
    max_average_time = float(1)
 | 
			
		||||
    if len(watch_points_list) > 0:
 | 
			
		||||
        max_average_time = float(watch_points_list[0].split(' ')[0])
 | 
			
		||||
    for watch_point in watch_points_list:
 | 
			
		||||
        average_time = float(watch_point.split(' ')[0])
 | 
			
		||||
        if average_time > max_average_time:
 | 
			
		||||
            max_average_time = average_time
 | 
			
		||||
 | 
			
		||||
    ctr = 0
 | 
			
		||||
    for watchPoint in watchPointsList:
 | 
			
		||||
        name = watchPoint.split(' ', 1)[1]
 | 
			
		||||
        averageTime = float(watchPoint.split(' ')[0])
 | 
			
		||||
        heightPercent = int(averageTime * 100 / maxAverageTime)
 | 
			
		||||
        timeMS = int(averageTime)
 | 
			
		||||
    for watch_point in watch_points_list:
 | 
			
		||||
        name = watch_point.split(' ', 1)[1]
 | 
			
		||||
        average_time = float(watch_point.split(' ')[0])
 | 
			
		||||
        heightPercent = int(average_time * 100 / max_average_time)
 | 
			
		||||
        timeMS = int(average_time)
 | 
			
		||||
        if heightPercent == 0:
 | 
			
		||||
            continue
 | 
			
		||||
        htmlStr += \
 | 
			
		||||
        html_str += \
 | 
			
		||||
            '<tr style="height:' + str(heightPercent) + '%">\n' + \
 | 
			
		||||
            '  <th scope="row">' + name + '</th>\n' + \
 | 
			
		||||
            '  <td><span>' + str(timeMS) + '</span></td>\n' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -113,8 +114,8 @@ def html_watch_points_graph(base_dir: str, fitness: {}, fitnessId: str,
 | 
			
		|||
        if ctr >= maxEntries:
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
    htmlStr += '</tbody></table>\n' + html_footer()
 | 
			
		||||
    return htmlStr
 | 
			
		||||
    html_str += '</tbody></table>\n' + html_footer()
 | 
			
		||||
    return html_str
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def fitness_thread(base_dir: str, fitness: {}):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								httpsig.py
								
								
								
								
							
							
						
						
									
										10
									
								
								httpsig.py
								
								
								
								
							| 
						 | 
				
			
			@ -301,15 +301,15 @@ def _verify_recent_signature(signedDateStr: str) -> bool:
 | 
			
		|||
    currDate = datetime.datetime.utcnow()
 | 
			
		||||
    dateFormat = "%a, %d %b %Y %H:%M:%S %Z"
 | 
			
		||||
    signedDate = datetime.datetime.strptime(signedDateStr, dateFormat)
 | 
			
		||||
    timeDiffSec = (currDate - signedDate).seconds
 | 
			
		||||
    time_diffSec = (currDate - signedDate).seconds
 | 
			
		||||
    # 12 hours tollerance
 | 
			
		||||
    if timeDiffSec > 43200:
 | 
			
		||||
    if time_diffSec > 43200:
 | 
			
		||||
        print('WARN: Header signed too long ago: ' + signedDateStr)
 | 
			
		||||
        print(str(timeDiffSec / (60 * 60)) + ' hours')
 | 
			
		||||
        print(str(time_diffSec / (60 * 60)) + ' hours')
 | 
			
		||||
        return False
 | 
			
		||||
    if timeDiffSec < 0:
 | 
			
		||||
    if time_diffSec < 0:
 | 
			
		||||
        print('WARN: Header signed in the future! ' + signedDateStr)
 | 
			
		||||
        print(str(timeDiffSec / (60 * 60)) + ' hours')
 | 
			
		||||
        print(str(time_diffSec / (60 * 60)) + ' hours')
 | 
			
		||||
        return False
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								inbox.py
								
								
								
								
							
							
						
						
									
										16
									
								
								inbox.py
								
								
								
								
							| 
						 | 
				
			
			@ -174,8 +174,8 @@ def _update_cached_hashtag_swarm(base_dir: str, nickname: str, domain: str,
 | 
			
		|||
            pass
 | 
			
		||||
        if modifiedDate:
 | 
			
		||||
            currDate = datetime.datetime.utcnow()
 | 
			
		||||
            timeDiff = currDate - modifiedDate
 | 
			
		||||
            diffMins = int(timeDiff.total_seconds() / 60)
 | 
			
		||||
            time_diff = currDate - modifiedDate
 | 
			
		||||
            diffMins = int(time_diff.total_seconds() / 60)
 | 
			
		||||
            if diffMins < 10:
 | 
			
		||||
                # was saved recently, so don't save again
 | 
			
		||||
                # This avoids too much disk I/O
 | 
			
		||||
| 
						 | 
				
			
			@ -566,11 +566,11 @@ def save_post_to_inbox_queue(base_dir: str, http_prefix: str,
 | 
			
		|||
    digestStartTime = time.time()
 | 
			
		||||
    digestAlgorithm = get_digest_algorithm_from_headers(httpHeaders)
 | 
			
		||||
    digest = message_content_digest(messageBytes, digestAlgorithm)
 | 
			
		||||
    timeDiffStr = str(int((time.time() - digestStartTime) * 1000))
 | 
			
		||||
    time_diffStr = str(int((time.time() - digestStartTime) * 1000))
 | 
			
		||||
    if debug:
 | 
			
		||||
        while len(timeDiffStr) < 6:
 | 
			
		||||
            timeDiffStr = '0' + timeDiffStr
 | 
			
		||||
        print('DIGEST|' + timeDiffStr + '|' + filename)
 | 
			
		||||
        while len(time_diffStr) < 6:
 | 
			
		||||
            time_diffStr = '0' + time_diffStr
 | 
			
		||||
        print('DIGEST|' + time_diffStr + '|' + filename)
 | 
			
		||||
 | 
			
		||||
    newQueueItem = {
 | 
			
		||||
        'originalId': originalPostId,
 | 
			
		||||
| 
						 | 
				
			
			@ -3602,12 +3602,12 @@ def _inbox_after_initial(recent_posts_cache: {}, max_recent_posts: int,
 | 
			
		|||
                                                        cw_lists,
 | 
			
		||||
                                                        lists_enabled)
 | 
			
		||||
                        if debug:
 | 
			
		||||
                            timeDiff = \
 | 
			
		||||
                            time_diff = \
 | 
			
		||||
                                str(int((time.time() - htmlCacheStartTime) *
 | 
			
		||||
                                        1000))
 | 
			
		||||
                            print('Saved ' + boxname +
 | 
			
		||||
                                  ' post as html to cache in ' +
 | 
			
		||||
                                  timeDiff + ' mS')
 | 
			
		||||
                                  time_diff + ' mS')
 | 
			
		||||
 | 
			
		||||
            handleName = handle.split('@')[0]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -196,8 +196,8 @@ def masto_api_v1_response(path: str, calling_domain: str,
 | 
			
		|||
        sendJsonStr = \
 | 
			
		||||
            'masto API custom emojis sent ' + path + callingInfo
 | 
			
		||||
 | 
			
		||||
    adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if adminNickname and path == '/api/v1/instance':
 | 
			
		||||
    admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if admin_nickname and path == '/api/v1/instance':
 | 
			
		||||
        instanceDescriptionShort = \
 | 
			
		||||
            get_config_param(base_dir, 'instanceDescriptionShort')
 | 
			
		||||
        if not instanceDescriptionShort:
 | 
			
		||||
| 
						 | 
				
			
			@ -224,7 +224,7 @@ def masto_api_v1_response(path: str, calling_domain: str,
 | 
			
		|||
                               instanceDescription,
 | 
			
		||||
                               http_prefix,
 | 
			
		||||
                               base_dir,
 | 
			
		||||
                               adminNickname,
 | 
			
		||||
                               admin_nickname,
 | 
			
		||||
                               domain,
 | 
			
		||||
                               domain_full,
 | 
			
		||||
                               registration,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,13 +86,13 @@ def meta_data_instance(showAccounts: bool,
 | 
			
		|||
                       instanceDescriptionShort: str,
 | 
			
		||||
                       instanceDescription: str,
 | 
			
		||||
                       http_prefix: str, base_dir: str,
 | 
			
		||||
                       adminNickname: str, domain: str, domain_full: str,
 | 
			
		||||
                       admin_nickname: str, domain: str, domain_full: str,
 | 
			
		||||
                       registration: bool, system_language: str,
 | 
			
		||||
                       version: str) -> {}:
 | 
			
		||||
    """ /api/v1/instance endpoint
 | 
			
		||||
    """
 | 
			
		||||
    adminActorFilename = \
 | 
			
		||||
        base_dir + '/accounts/' + adminNickname + '@' + domain + '.json'
 | 
			
		||||
        base_dir + '/accounts/' + admin_nickname + '@' + domain + '.json'
 | 
			
		||||
    if not os.path.isfile(adminActorFilename):
 | 
			
		||||
        return {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								person.py
								
								
								
								
							
							
						
						
									
										18
									
								
								person.py
								
								
								
								
							| 
						 | 
				
			
			@ -1060,10 +1060,10 @@ def suspend_account(base_dir: str, nickname: str, domain: str) -> None:
 | 
			
		|||
    """Suspends the given account
 | 
			
		||||
    """
 | 
			
		||||
    # Don't suspend the admin
 | 
			
		||||
    adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if not adminNickname:
 | 
			
		||||
    admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if not admin_nickname:
 | 
			
		||||
        return
 | 
			
		||||
    if nickname == adminNickname:
 | 
			
		||||
    if nickname == admin_nickname:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    # Don't suspend moderators
 | 
			
		||||
| 
						 | 
				
			
			@ -1118,10 +1118,10 @@ def can_remove_post(base_dir: str, nickname: str,
 | 
			
		|||
    domain_full = get_full_domain(domain, port)
 | 
			
		||||
 | 
			
		||||
    # is the post by the admin?
 | 
			
		||||
    adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if not adminNickname:
 | 
			
		||||
    admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if not admin_nickname:
 | 
			
		||||
        return False
 | 
			
		||||
    if domain_full + '/users/' + adminNickname + '/' in post_id:
 | 
			
		||||
    if domain_full + '/users/' + admin_nickname + '/' in post_id:
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    # is the post by a moderator?
 | 
			
		||||
| 
						 | 
				
			
			@ -1177,10 +1177,10 @@ def remove_account(base_dir: str, nickname: str,
 | 
			
		|||
    """Removes an account
 | 
			
		||||
    """
 | 
			
		||||
    # Don't remove the admin
 | 
			
		||||
    adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if not adminNickname:
 | 
			
		||||
    admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if not admin_nickname:
 | 
			
		||||
        return False
 | 
			
		||||
    if nickname == adminNickname:
 | 
			
		||||
    if nickname == admin_nickname:
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    # Don't remove moderators
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								tests.py
								
								
								
								
							
							
						
						
									
										8
									
								
								tests.py
								
								
								
								
							| 
						 | 
				
			
			@ -3937,9 +3937,9 @@ def _test_constant_time_string():
 | 
			
		|||
        constant_time_string_check(test_str, test_str)
 | 
			
		||||
    end = time.time()
 | 
			
		||||
    avTime2 = ((end - start) * 1000000 / itterations)
 | 
			
		||||
    timeDiffMicroseconds = abs(avTime2 - avTime1)
 | 
			
		||||
    time_diffMicroseconds = abs(avTime2 - avTime1)
 | 
			
		||||
    # time difference should be less than 10uS
 | 
			
		||||
    assert int(timeDiffMicroseconds) < 10
 | 
			
		||||
    assert int(time_diffMicroseconds) < 10
 | 
			
		||||
 | 
			
		||||
    # change multiple characters and observe timing difference
 | 
			
		||||
    start = time.time()
 | 
			
		||||
| 
						 | 
				
			
			@ -3948,9 +3948,9 @@ def _test_constant_time_string():
 | 
			
		|||
        constant_time_string_check(test_str, test_str2)
 | 
			
		||||
    end = time.time()
 | 
			
		||||
    avTime2 = ((end - start) * 1000000 / itterations)
 | 
			
		||||
    timeDiffMicroseconds = abs(avTime2 - avTime1)
 | 
			
		||||
    time_diffMicroseconds = abs(avTime2 - avTime1)
 | 
			
		||||
    # time difference should be less than 10uS
 | 
			
		||||
    assert int(timeDiffMicroseconds) < 10
 | 
			
		||||
    assert int(time_diffMicroseconds) < 10
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _test_replace_email_quote():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										30
									
								
								theme.py
								
								
								
								
							
							
						
						
									
										30
									
								
								theme.py
								
								
								
								
							| 
						 | 
				
			
			@ -397,13 +397,13 @@ def _set_background_format(base_dir: str, name: str,
 | 
			
		|||
    """
 | 
			
		||||
    if extension == 'jpg':
 | 
			
		||||
        return
 | 
			
		||||
    cssFilename = base_dir + '/' + backgroundType + '.css'
 | 
			
		||||
    if not os.path.isfile(cssFilename):
 | 
			
		||||
    css_filename = base_dir + '/' + backgroundType + '.css'
 | 
			
		||||
    if not os.path.isfile(css_filename):
 | 
			
		||||
        return
 | 
			
		||||
    with open(cssFilename, 'r') as cssfile:
 | 
			
		||||
    with open(css_filename, 'r') as cssfile:
 | 
			
		||||
        css = cssfile.read()
 | 
			
		||||
        css = css.replace('background.jpg', 'background.' + extension)
 | 
			
		||||
        with open(cssFilename, 'w+') as cssfile2:
 | 
			
		||||
        with open(css_filename, 'w+') as cssfile2:
 | 
			
		||||
            cssfile2.write(css)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -594,9 +594,9 @@ def _set_theme_fonts(base_dir: str, theme_name: str) -> None:
 | 
			
		|||
def get_text_mode_banner(base_dir: str) -> str:
 | 
			
		||||
    """Returns the banner used for shell browsers, like Lynx
 | 
			
		||||
    """
 | 
			
		||||
    text_mode_bannerFilename = base_dir + '/accounts/banner.txt'
 | 
			
		||||
    if os.path.isfile(text_mode_bannerFilename):
 | 
			
		||||
        with open(text_mode_bannerFilename, 'r') as fp:
 | 
			
		||||
    text_mode_banner_filename = base_dir + '/accounts/banner.txt'
 | 
			
		||||
    if os.path.isfile(text_mode_banner_filename):
 | 
			
		||||
        with open(text_mode_banner_filename, 'r') as fp:
 | 
			
		||||
            bannerStr = fp.read()
 | 
			
		||||
            if bannerStr:
 | 
			
		||||
                return bannerStr.replace('\n', '<br>')
 | 
			
		||||
| 
						 | 
				
			
			@ -640,7 +640,7 @@ def _set_text_mode_theme(base_dir: str, name: str) -> None:
 | 
			
		|||
                  base_dir + '/accounts/logo.txt')
 | 
			
		||||
 | 
			
		||||
    # set the text mode banner which appears in browsers such as Lynx
 | 
			
		||||
    text_mode_bannerFilename = \
 | 
			
		||||
    text_mode_banner_filename = \
 | 
			
		||||
        base_dir + '/theme/' + name + '/banner.txt'
 | 
			
		||||
    if os.path.isfile(base_dir + '/accounts/banner.txt'):
 | 
			
		||||
        try:
 | 
			
		||||
| 
						 | 
				
			
			@ -648,13 +648,13 @@ def _set_text_mode_theme(base_dir: str, name: str) -> None:
 | 
			
		|||
        except OSError:
 | 
			
		||||
            print('EX: _set_text_mode_theme unable to delete ' +
 | 
			
		||||
                  base_dir + '/accounts/banner.txt')
 | 
			
		||||
    if os.path.isfile(text_mode_bannerFilename):
 | 
			
		||||
    if os.path.isfile(text_mode_banner_filename):
 | 
			
		||||
        try:
 | 
			
		||||
            copyfile(text_mode_bannerFilename,
 | 
			
		||||
            copyfile(text_mode_banner_filename,
 | 
			
		||||
                     base_dir + '/accounts/banner.txt')
 | 
			
		||||
        except OSError:
 | 
			
		||||
            print('EX: _set_text_mode_theme unable to copy ' +
 | 
			
		||||
                  text_mode_bannerFilename + ' ' +
 | 
			
		||||
                  text_mode_banner_filename + ' ' +
 | 
			
		||||
                  base_dir + '/accounts/banner.txt')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -666,7 +666,7 @@ def _set_theme_images(base_dir: str, name: str) -> None:
 | 
			
		|||
 | 
			
		||||
    profileImageFilename = \
 | 
			
		||||
        base_dir + '/theme/' + theme_name_lower + '/image.png'
 | 
			
		||||
    bannerFilename = \
 | 
			
		||||
    banner_filename = \
 | 
			
		||||
        base_dir + '/theme/' + theme_name_lower + '/banner.png'
 | 
			
		||||
    searchBannerFilename = \
 | 
			
		||||
        base_dir + '/theme/' + theme_name_lower + '/search_banner.png'
 | 
			
		||||
| 
						 | 
				
			
			@ -721,7 +721,7 @@ def _set_theme_images(base_dir: str, name: str) -> None:
 | 
			
		|||
                                  backgroundType + '-background.' + ext)
 | 
			
		||||
 | 
			
		||||
            if os.path.isfile(profileImageFilename) and \
 | 
			
		||||
               os.path.isfile(bannerFilename):
 | 
			
		||||
               os.path.isfile(banner_filename):
 | 
			
		||||
                try:
 | 
			
		||||
                    copyfile(profileImageFilename,
 | 
			
		||||
                             accountDir + '/image.png')
 | 
			
		||||
| 
						 | 
				
			
			@ -730,11 +730,11 @@ def _set_theme_images(base_dir: str, name: str) -> None:
 | 
			
		|||
                          profileImageFilename)
 | 
			
		||||
 | 
			
		||||
                try:
 | 
			
		||||
                    copyfile(bannerFilename,
 | 
			
		||||
                    copyfile(banner_filename,
 | 
			
		||||
                             accountDir + '/banner.png')
 | 
			
		||||
                except OSError:
 | 
			
		||||
                    print('EX: _set_theme_images unable to copy ' +
 | 
			
		||||
                          bannerFilename)
 | 
			
		||||
                          banner_filename)
 | 
			
		||||
 | 
			
		||||
                try:
 | 
			
		||||
                    if os.path.isfile(searchBannerFilename):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ def html_about(css_cache: {}, base_dir: str, http_prefix: str,
 | 
			
		|||
               system_language: str) -> str:
 | 
			
		||||
    """Show the about screen
 | 
			
		||||
    """
 | 
			
		||||
    adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if not os.path.isfile(base_dir + '/accounts/about.md'):
 | 
			
		||||
        copyfile(base_dir + '/default_about.md',
 | 
			
		||||
                 base_dir + '/accounts/about.md')
 | 
			
		||||
| 
						 | 
				
			
			@ -36,14 +36,14 @@ def html_about(css_cache: {}, base_dir: str, http_prefix: str,
 | 
			
		|||
            aboutText = markdown_to_html(aboutFile.read())
 | 
			
		||||
 | 
			
		||||
    aboutForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    aboutForm = \
 | 
			
		||||
        html_header_with_website_markup(cssFilename, instanceTitle,
 | 
			
		||||
        html_header_with_website_markup(css_filename, instanceTitle,
 | 
			
		||||
                                        http_prefix, domain_full,
 | 
			
		||||
                                        system_language)
 | 
			
		||||
    aboutForm += '<div class="container">' + aboutText + '</div>'
 | 
			
		||||
| 
						 | 
				
			
			@ -52,13 +52,13 @@ def html_about(css_cache: {}, base_dir: str, http_prefix: str,
 | 
			
		|||
            '<div class="container"><center>\n' + \
 | 
			
		||||
            '<p class="administeredby">' + \
 | 
			
		||||
            'http://' + onion_domain + '</p>\n</center></div>\n'
 | 
			
		||||
    if adminNickname:
 | 
			
		||||
        adminActor = '/users/' + adminNickname
 | 
			
		||||
    if admin_nickname:
 | 
			
		||||
        adminActor = '/users/' + admin_nickname
 | 
			
		||||
        aboutForm += \
 | 
			
		||||
            '<div class="container"><center>\n' + \
 | 
			
		||||
            '<p class="administeredby">' + \
 | 
			
		||||
            translate['Administered by'] + ' <a href="' + \
 | 
			
		||||
            adminActor + '">' + adminNickname + '</a>. ' + \
 | 
			
		||||
            adminActor + '">' + admin_nickname + '</a>. ' + \
 | 
			
		||||
            translate['Version'] + ' ' + __version__ + \
 | 
			
		||||
            '</p>\n</center></div>\n'
 | 
			
		||||
    aboutForm += html_footer()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ from webapp_utils import html_footer
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def load_access_keys_for_accounts(base_dir: str, keyShortcuts: {},
 | 
			
		||||
                                  accessKeysTemplate: {}) -> None:
 | 
			
		||||
                                  access_keysTemplate: {}) -> None:
 | 
			
		||||
    """Loads key shortcuts for each account
 | 
			
		||||
    """
 | 
			
		||||
    for subdir, dirs, files in os.walk(base_dir + '/accounts'):
 | 
			
		||||
| 
						 | 
				
			
			@ -25,57 +25,57 @@ def load_access_keys_for_accounts(base_dir: str, keyShortcuts: {},
 | 
			
		|||
            if not is_account_dir(acct):
 | 
			
		||||
                continue
 | 
			
		||||
            accountDir = os.path.join(base_dir + '/accounts', acct)
 | 
			
		||||
            accessKeysFilename = accountDir + '/accessKeys.json'
 | 
			
		||||
            if not os.path.isfile(accessKeysFilename):
 | 
			
		||||
            access_keysFilename = accountDir + '/access_keys.json'
 | 
			
		||||
            if not os.path.isfile(access_keysFilename):
 | 
			
		||||
                continue
 | 
			
		||||
            nickname = acct.split('@')[0]
 | 
			
		||||
            accessKeys = load_json(accessKeysFilename)
 | 
			
		||||
            if accessKeys:
 | 
			
		||||
                keyShortcuts[nickname] = accessKeysTemplate.copy()
 | 
			
		||||
                for variableName, key in accessKeysTemplate.items():
 | 
			
		||||
                    if accessKeys.get(variableName):
 | 
			
		||||
            access_keys = load_json(access_keysFilename)
 | 
			
		||||
            if access_keys:
 | 
			
		||||
                keyShortcuts[nickname] = access_keysTemplate.copy()
 | 
			
		||||
                for variableName, key in access_keysTemplate.items():
 | 
			
		||||
                    if access_keys.get(variableName):
 | 
			
		||||
                        keyShortcuts[nickname][variableName] = \
 | 
			
		||||
                            accessKeys[variableName]
 | 
			
		||||
                            access_keys[variableName]
 | 
			
		||||
        break
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def html_access_keys(css_cache: {}, base_dir: str,
 | 
			
		||||
                     nickname: str, domain: str,
 | 
			
		||||
                     translate: {}, accessKeys: {},
 | 
			
		||||
                     translate: {}, access_keys: {},
 | 
			
		||||
                     defaultAccessKeys: {},
 | 
			
		||||
                     defaultTimeline: str) -> str:
 | 
			
		||||
    """Show and edit key shortcuts
 | 
			
		||||
    """
 | 
			
		||||
    accessKeysFilename = \
 | 
			
		||||
        acct_dir(base_dir, nickname, domain) + '/accessKeys.json'
 | 
			
		||||
    if os.path.isfile(accessKeysFilename):
 | 
			
		||||
        accessKeysFromFile = load_json(accessKeysFilename)
 | 
			
		||||
        if accessKeysFromFile:
 | 
			
		||||
            accessKeys = accessKeysFromFile
 | 
			
		||||
    access_keysFilename = \
 | 
			
		||||
        acct_dir(base_dir, nickname, domain) + '/access_keys.json'
 | 
			
		||||
    if os.path.isfile(access_keysFilename):
 | 
			
		||||
        access_keysFromFile = load_json(access_keysFilename)
 | 
			
		||||
        if access_keysFromFile:
 | 
			
		||||
            access_keys = access_keysFromFile
 | 
			
		||||
 | 
			
		||||
    accessKeysForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    access_keysForm = ''
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    accessKeysForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    accessKeysForm += '<div class="container">\n'
 | 
			
		||||
    access_keysForm = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    access_keysForm += '<div class="container">\n'
 | 
			
		||||
 | 
			
		||||
    accessKeysForm += \
 | 
			
		||||
    access_keysForm += \
 | 
			
		||||
        '    <h1>' + translate['Key Shortcuts'] + '</h1>\n'
 | 
			
		||||
    accessKeysForm += \
 | 
			
		||||
    access_keysForm += \
 | 
			
		||||
        '<p>' + translate['These access keys may be used'] + \
 | 
			
		||||
        '<label class="labels"></label></p>'
 | 
			
		||||
 | 
			
		||||
    accessKeysForm += '  <form method="POST" action="' + \
 | 
			
		||||
    access_keysForm += '  <form method="POST" action="' + \
 | 
			
		||||
        '/users/' + nickname + '/changeAccessKeys">\n'
 | 
			
		||||
 | 
			
		||||
    timelineKey = accessKeys['menuTimeline']
 | 
			
		||||
    submitKey = accessKeys['submitButton']
 | 
			
		||||
    accessKeysForm += \
 | 
			
		||||
    timelineKey = access_keys['menuTimeline']
 | 
			
		||||
    submitKey = access_keys['submitButton']
 | 
			
		||||
    access_keysForm += \
 | 
			
		||||
        '    <center>\n' + \
 | 
			
		||||
        '    <button type="submit" class="button" ' + \
 | 
			
		||||
        'name="submitAccessKeysCancel" accesskey="' + timelineKey + '">' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -84,12 +84,12 @@ def html_access_keys(css_cache: {}, base_dir: str,
 | 
			
		|||
        'name="submitAccessKeys" accesskey="' + submitKey + '">' + \
 | 
			
		||||
        translate['Submit'] + '</button>\n    </center>\n'
 | 
			
		||||
 | 
			
		||||
    accessKeysForm += '    <table class="accesskeys">\n'
 | 
			
		||||
    accessKeysForm += '      <colgroup>\n'
 | 
			
		||||
    accessKeysForm += '        <col span="1" class="accesskeys-left">\n'
 | 
			
		||||
    accessKeysForm += '        <col span="1" class="accesskeys-center">\n'
 | 
			
		||||
    accessKeysForm += '      </colgroup>\n'
 | 
			
		||||
    accessKeysForm += '      <tbody>\n'
 | 
			
		||||
    access_keysForm += '    <table class="accesskeys">\n'
 | 
			
		||||
    access_keysForm += '      <colgroup>\n'
 | 
			
		||||
    access_keysForm += '        <col span="1" class="accesskeys-left">\n'
 | 
			
		||||
    access_keysForm += '        <col span="1" class="accesskeys-center">\n'
 | 
			
		||||
    access_keysForm += '      </colgroup>\n'
 | 
			
		||||
    access_keysForm += '      <tbody>\n'
 | 
			
		||||
 | 
			
		||||
    for variableName, key in defaultAccessKeys.items():
 | 
			
		||||
        if not translate.get(variableName):
 | 
			
		||||
| 
						 | 
				
			
			@ -98,8 +98,8 @@ def html_access_keys(css_cache: {}, base_dir: str,
 | 
			
		|||
        keyStr += \
 | 
			
		||||
            '<td><label class="labels">' + \
 | 
			
		||||
            translate[variableName] + '</label></td>'
 | 
			
		||||
        if accessKeys.get(variableName):
 | 
			
		||||
            key = accessKeys[variableName]
 | 
			
		||||
        if access_keys.get(variableName):
 | 
			
		||||
            key = access_keys[variableName]
 | 
			
		||||
        if len(key) > 1:
 | 
			
		||||
            key = key[0]
 | 
			
		||||
        keyStr += \
 | 
			
		||||
| 
						 | 
				
			
			@ -107,11 +107,11 @@ def html_access_keys(css_cache: {}, base_dir: str,
 | 
			
		|||
            'name="' + variableName.replace(' ', '_') + '" ' + \
 | 
			
		||||
            'value="' + key + '">'
 | 
			
		||||
        keyStr += '</td></tr>\n'
 | 
			
		||||
        accessKeysForm += keyStr
 | 
			
		||||
        access_keysForm += keyStr
 | 
			
		||||
 | 
			
		||||
    accessKeysForm += '      </tbody>\n'
 | 
			
		||||
    accessKeysForm += '    </table>\n'
 | 
			
		||||
    accessKeysForm += '  </form>\n'
 | 
			
		||||
    accessKeysForm += '</div>\n'
 | 
			
		||||
    accessKeysForm += html_footer()
 | 
			
		||||
    return accessKeysForm
 | 
			
		||||
    access_keysForm += '      </tbody>\n'
 | 
			
		||||
    access_keysForm += '    </table>\n'
 | 
			
		||||
    access_keysForm += '  </form>\n'
 | 
			
		||||
    access_keysForm += '</div>\n'
 | 
			
		||||
    access_keysForm += html_footer()
 | 
			
		||||
    return access_keysForm
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,14 +52,14 @@ def html_calendar_delete_confirm(css_cache: {}, translate: {}, base_dir: str,
 | 
			
		|||
        return None
 | 
			
		||||
 | 
			
		||||
    delete_postStr = None
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    delete_postStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    delete_postStr += \
 | 
			
		||||
        '<center><h1>' + postTime + ' ' + str(year) + '/' + \
 | 
			
		||||
        str(monthNumber) + \
 | 
			
		||||
| 
						 | 
				
			
			@ -111,9 +111,9 @@ def _html_calendar_day(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
        except OSError:
 | 
			
		||||
            print('EX: _html_calendar_day unable to delete ' + calendarFile)
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-calendar.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-calendar.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/calendar.css'):
 | 
			
		||||
        cssFilename = base_dir + '/calendar.css'
 | 
			
		||||
        css_filename = base_dir + '/calendar.css'
 | 
			
		||||
 | 
			
		||||
    calActor = actor
 | 
			
		||||
    if '/users/' in actor:
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +121,7 @@ def _html_calendar_day(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    calendarStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    calendarStr += '<main><table class="calendar">\n'
 | 
			
		||||
    calendarStr += '<caption class="calendar__banner--month">\n'
 | 
			
		||||
    calendarStr += \
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +249,7 @@ def _html_calendar_day(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
def html_calendar(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		||||
                  base_dir: str, path: str,
 | 
			
		||||
                  http_prefix: str, domain_full: str,
 | 
			
		||||
                  text_mode_banner: str, accessKeys: {}) -> str:
 | 
			
		||||
                  text_mode_banner: str, access_keys: {}) -> str:
 | 
			
		||||
    """Show the calendar for a person
 | 
			
		||||
    """
 | 
			
		||||
    domain = remove_domain_port(domain_full)
 | 
			
		||||
| 
						 | 
				
			
			@ -334,9 +334,9 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
            (date(year + 1, 1, 1) - date(year, monthNumber, 1)).days
 | 
			
		||||
    # print('daysInMonth ' + str(monthNumber) + ': ' + str(daysInMonth))
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-calendar.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-calendar.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/calendar.css'):
 | 
			
		||||
        cssFilename = base_dir + '/calendar.css'
 | 
			
		||||
        css_filename = base_dir + '/calendar.css'
 | 
			
		||||
 | 
			
		||||
    calActor = actor
 | 
			
		||||
    if '/users/' in actor:
 | 
			
		||||
| 
						 | 
				
			
			@ -345,7 +345,7 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    headerStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    # the main graphical calendar as a table
 | 
			
		||||
    calendarStr = '<main><table class="calendar">\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -353,19 +353,19 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
    calendarStr += \
 | 
			
		||||
        '  <a href="' + calActor + '/calendar?year=' + str(prevYear) + \
 | 
			
		||||
        '?month=' + str(prevMonthNumber) + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['Page up'] + '">'
 | 
			
		||||
        'accesskey="' + access_keys['Page up'] + '">'
 | 
			
		||||
    calendarStr += \
 | 
			
		||||
        '  <img loading="lazy" alt="' + translate['Previous month'] + \
 | 
			
		||||
        '" title="' + translate['Previous month'] + '" src="/icons' + \
 | 
			
		||||
        '/prev.png" class="buttonprev"/></a>\n'
 | 
			
		||||
    calendarStr += '  <a href="' + calActor + '/inbox" title="'
 | 
			
		||||
    calendarStr += translate['Switch to timeline view'] + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['menuTimeline'] + '">'
 | 
			
		||||
        'accesskey="' + access_keys['menuTimeline'] + '">'
 | 
			
		||||
    calendarStr += '  <h1>' + monthName + '</h1></a>\n'
 | 
			
		||||
    calendarStr += \
 | 
			
		||||
        '  <a href="' + calActor + '/calendar?year=' + str(nextYear) + \
 | 
			
		||||
        '?month=' + str(nextMonthNumber) + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['Page down'] + '">'
 | 
			
		||||
        'accesskey="' + access_keys['Page down'] + '">'
 | 
			
		||||
    calendarStr += \
 | 
			
		||||
        '  <img loading="lazy" alt="' + translate['Next month'] + \
 | 
			
		||||
        '" title="' + translate['Next month'] + '" src="/icons' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -382,10 +382,10 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
    calendarStr += '<tbody>\n'
 | 
			
		||||
 | 
			
		||||
    # beginning of the links used for accessibility
 | 
			
		||||
    navLinks = {}
 | 
			
		||||
    nav_links = {}
 | 
			
		||||
    timelineLinkStr = html_hide_from_screen_reader('🏠') + ' ' + \
 | 
			
		||||
        translate['Switch to timeline view']
 | 
			
		||||
    navLinks[timelineLinkStr] = calActor + '/inbox'
 | 
			
		||||
    nav_links[timelineLinkStr] = calActor + '/inbox'
 | 
			
		||||
 | 
			
		||||
    dayOfMonth = 0
 | 
			
		||||
    dow = week_day_of_month_start(monthNumber, year)
 | 
			
		||||
| 
						 | 
				
			
			@ -415,7 +415,7 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
                    menuOptionStr = \
 | 
			
		||||
                        html_hide_from_screen_reader('📅') + ' ' + \
 | 
			
		||||
                        dayDescription
 | 
			
		||||
                    navLinks[menuOptionStr] = url
 | 
			
		||||
                    nav_links[menuOptionStr] = url
 | 
			
		||||
                    # there are events for this day
 | 
			
		||||
                    if not isToday:
 | 
			
		||||
                        calendarStr += \
 | 
			
		||||
| 
						 | 
				
			
			@ -447,16 +447,16 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
 | 
			
		|||
    # end of the links used for accessibility
 | 
			
		||||
    nextMonthStr = \
 | 
			
		||||
        html_hide_from_screen_reader('→') + ' ' + translate['Next month']
 | 
			
		||||
    navLinks[nextMonthStr] = calActor + '/calendar?year=' + str(nextYear) + \
 | 
			
		||||
    nav_links[nextMonthStr] = calActor + '/calendar?year=' + str(nextYear) + \
 | 
			
		||||
        '?month=' + str(nextMonthNumber)
 | 
			
		||||
    prevMonthStr = \
 | 
			
		||||
        html_hide_from_screen_reader('←') + ' ' + translate['Previous month']
 | 
			
		||||
    navLinks[prevMonthStr] = calActor + '/calendar?year=' + str(prevYear) + \
 | 
			
		||||
    nav_links[prevMonthStr] = calActor + '/calendar?year=' + str(prevYear) + \
 | 
			
		||||
        '?month=' + str(prevMonthNumber)
 | 
			
		||||
    navAccessKeys = {
 | 
			
		||||
    nav_access_keys = {
 | 
			
		||||
    }
 | 
			
		||||
    screenReaderCal = \
 | 
			
		||||
        html_keyboard_navigation(text_mode_banner, navLinks, navAccessKeys,
 | 
			
		||||
        html_keyboard_navigation(text_mode_banner, nav_links, nav_access_keys,
 | 
			
		||||
                                 monthName)
 | 
			
		||||
 | 
			
		||||
    newEventStr = \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,88 +28,90 @@ from shares import share_category_icon
 | 
			
		|||
def _links_exist(base_dir: str) -> bool:
 | 
			
		||||
    """Returns true if links have been created
 | 
			
		||||
    """
 | 
			
		||||
    linksFilename = base_dir + '/accounts/links.txt'
 | 
			
		||||
    return os.path.isfile(linksFilename)
 | 
			
		||||
    links_filename = base_dir + '/accounts/links.txt'
 | 
			
		||||
    return os.path.isfile(links_filename)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_left_column_shares(base_dir: str,
 | 
			
		||||
                            http_prefix: str, domain: str, domain_full: str,
 | 
			
		||||
                            nickname: str,
 | 
			
		||||
                            maxSharesInLeftColumn: int,
 | 
			
		||||
                            max_shares_in_left_column: int,
 | 
			
		||||
                            translate: {},
 | 
			
		||||
                            shared_items_federated_domains: []) -> []:
 | 
			
		||||
    """get any shares and turn them into the left column links format
 | 
			
		||||
    """
 | 
			
		||||
    pageNumber = 1
 | 
			
		||||
    page_number = 1
 | 
			
		||||
    actor = local_actor_url(http_prefix, nickname, domain_full)
 | 
			
		||||
    # NOTE: this could potentially be slow if the number of federated
 | 
			
		||||
    # shared items is large
 | 
			
		||||
    sharesJson, lastPage = \
 | 
			
		||||
        shares_timeline_json(actor, pageNumber, maxSharesInLeftColumn,
 | 
			
		||||
                             base_dir, domain, nickname, maxSharesInLeftColumn,
 | 
			
		||||
    shares_json, last_page = \
 | 
			
		||||
        shares_timeline_json(actor, page_number, max_shares_in_left_column,
 | 
			
		||||
                             base_dir, domain, nickname,
 | 
			
		||||
                             max_shares_in_left_column,
 | 
			
		||||
                             shared_items_federated_domains, 'shares')
 | 
			
		||||
    if not sharesJson:
 | 
			
		||||
    if not shares_json:
 | 
			
		||||
        return []
 | 
			
		||||
 | 
			
		||||
    linksList = []
 | 
			
		||||
    links_list = []
 | 
			
		||||
    ctr = 0
 | 
			
		||||
    for published, item in sharesJson.items():
 | 
			
		||||
    for published, item in shares_json.items():
 | 
			
		||||
        sharedesc = item['displayName']
 | 
			
		||||
        if '<' in sharedesc or '?' in sharedesc:
 | 
			
		||||
            continue
 | 
			
		||||
        shareId = item['shareId']
 | 
			
		||||
        share_id = item['shareId']
 | 
			
		||||
        # selecting this link calls html_show_share
 | 
			
		||||
        shareLink = actor + '?showshare=' + shareId
 | 
			
		||||
        share_link = actor + '?showshare=' + share_id
 | 
			
		||||
        if item.get('category'):
 | 
			
		||||
            shareLink += '?category=' + item['category']
 | 
			
		||||
            share_link += '?category=' + item['category']
 | 
			
		||||
            shareCategory = share_category_icon(item['category'])
 | 
			
		||||
 | 
			
		||||
        linksList.append(shareCategory + sharedesc + ' ' + shareLink)
 | 
			
		||||
        links_list.append(shareCategory + sharedesc + ' ' + share_link)
 | 
			
		||||
        ctr += 1
 | 
			
		||||
        if ctr >= maxSharesInLeftColumn:
 | 
			
		||||
        if ctr >= max_shares_in_left_column:
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
    if linksList:
 | 
			
		||||
        linksList = ['* ' + translate['Shares']] + linksList
 | 
			
		||||
    return linksList
 | 
			
		||||
    if links_list:
 | 
			
		||||
        links_list = ['* ' + translate['Shares']] + links_list
 | 
			
		||||
    return links_list
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_left_column_wanted(base_dir: str,
 | 
			
		||||
                            http_prefix: str, domain: str, domain_full: str,
 | 
			
		||||
                            nickname: str,
 | 
			
		||||
                            maxSharesInLeftColumn: int,
 | 
			
		||||
                            max_shares_in_left_column: int,
 | 
			
		||||
                            translate: {},
 | 
			
		||||
                            shared_items_federated_domains: []) -> []:
 | 
			
		||||
    """get any wanted items and turn them into the left column links format
 | 
			
		||||
    """
 | 
			
		||||
    pageNumber = 1
 | 
			
		||||
    page_number = 1
 | 
			
		||||
    actor = local_actor_url(http_prefix, nickname, domain_full)
 | 
			
		||||
    # NOTE: this could potentially be slow if the number of federated
 | 
			
		||||
    # wanted items is large
 | 
			
		||||
    sharesJson, lastPage = \
 | 
			
		||||
        shares_timeline_json(actor, pageNumber, maxSharesInLeftColumn,
 | 
			
		||||
                             base_dir, domain, nickname, maxSharesInLeftColumn,
 | 
			
		||||
    shares_json, last_page = \
 | 
			
		||||
        shares_timeline_json(actor, page_number, max_shares_in_left_column,
 | 
			
		||||
                             base_dir, domain, nickname,
 | 
			
		||||
                             max_shares_in_left_column,
 | 
			
		||||
                             shared_items_federated_domains, 'wanted')
 | 
			
		||||
    if not sharesJson:
 | 
			
		||||
    if not shares_json:
 | 
			
		||||
        return []
 | 
			
		||||
 | 
			
		||||
    linksList = []
 | 
			
		||||
    links_list = []
 | 
			
		||||
    ctr = 0
 | 
			
		||||
    for published, item in sharesJson.items():
 | 
			
		||||
    for published, item in shares_json.items():
 | 
			
		||||
        sharedesc = item['displayName']
 | 
			
		||||
        if '<' in sharedesc or ';' in sharedesc:
 | 
			
		||||
            continue
 | 
			
		||||
        shareId = item['shareId']
 | 
			
		||||
        share_id = item['shareId']
 | 
			
		||||
        # selecting this link calls html_show_share
 | 
			
		||||
        shareLink = actor + '?showwanted=' + shareId
 | 
			
		||||
        linksList.append(sharedesc + ' ' + shareLink)
 | 
			
		||||
        share_link = actor + '?showwanted=' + share_id
 | 
			
		||||
        links_list.append(sharedesc + ' ' + share_link)
 | 
			
		||||
        ctr += 1
 | 
			
		||||
        if ctr >= maxSharesInLeftColumn:
 | 
			
		||||
        if ctr >= max_shares_in_left_column:
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
    if linksList:
 | 
			
		||||
        linksList = ['* ' + translate['Wanted']] + linksList
 | 
			
		||||
    return linksList
 | 
			
		||||
    if links_list:
 | 
			
		||||
        links_list = ['* ' + translate['Wanted']] + links_list
 | 
			
		||||
    return links_list
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_left_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		||||
| 
						 | 
				
			
			@ -118,13 +120,13 @@ def get_left_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
                            showBackButton: bool, timelinePath: str,
 | 
			
		||||
                            rss_icon_at_top: bool, showHeaderImage: bool,
 | 
			
		||||
                            frontPage: bool, theme: str,
 | 
			
		||||
                            accessKeys: {},
 | 
			
		||||
                            access_keys: {},
 | 
			
		||||
                            shared_items_federated_domains: []) -> str:
 | 
			
		||||
    """Returns html content for the left column
 | 
			
		||||
    """
 | 
			
		||||
    htmlStr = ''
 | 
			
		||||
    html_str = ''
 | 
			
		||||
 | 
			
		||||
    separatorStr = html_post_separator(base_dir, 'left')
 | 
			
		||||
    separator_str = html_post_separator(base_dir, 'left')
 | 
			
		||||
    domain = remove_domain_port(domain_full)
 | 
			
		||||
 | 
			
		||||
    editImageClass = ''
 | 
			
		||||
| 
						 | 
				
			
			@ -136,40 +138,40 @@ def get_left_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
        editImageClass = 'leftColEdit'
 | 
			
		||||
        if os.path.isfile(leftColumnImageFilename):
 | 
			
		||||
            editImageClass = 'leftColEditImage'
 | 
			
		||||
            htmlStr += \
 | 
			
		||||
            html_str += \
 | 
			
		||||
                '\n      <center>\n        <img class="leftColImg" ' + \
 | 
			
		||||
                'alt="" loading="lazy" src="/users/' + \
 | 
			
		||||
                nickname + '/' + leftImageFile + '" />\n' + \
 | 
			
		||||
                '      </center>\n'
 | 
			
		||||
 | 
			
		||||
    if showBackButton:
 | 
			
		||||
        htmlStr += \
 | 
			
		||||
        html_str += \
 | 
			
		||||
            '      <div>      <a href="' + timelinePath + '">' + \
 | 
			
		||||
            '<button class="cancelbtn">' + \
 | 
			
		||||
            translate['Go Back'] + '</button></a>\n'
 | 
			
		||||
 | 
			
		||||
    if (editor or rss_icon_at_top) and not showHeaderImage:
 | 
			
		||||
        htmlStr += '<div class="columnIcons">'
 | 
			
		||||
        html_str += '<div class="columnIcons">'
 | 
			
		||||
 | 
			
		||||
    if editImageClass == 'leftColEdit':
 | 
			
		||||
        htmlStr += '\n      <center>\n'
 | 
			
		||||
        html_str += '\n      <center>\n'
 | 
			
		||||
 | 
			
		||||
    htmlStr += '      <div class="leftColIcons">\n'
 | 
			
		||||
    html_str += '      <div class="leftColIcons">\n'
 | 
			
		||||
 | 
			
		||||
    if editor:
 | 
			
		||||
        # show the edit icon
 | 
			
		||||
        htmlStr += \
 | 
			
		||||
        html_str += \
 | 
			
		||||
            '      <a href="/users/' + nickname + '/editlinks" ' + \
 | 
			
		||||
            'accesskey="' + accessKeys['menuEdit'] + '">' + \
 | 
			
		||||
            'accesskey="' + access_keys['menuEdit'] + '">' + \
 | 
			
		||||
            '<img class="' + editImageClass + '" loading="lazy" alt="' + \
 | 
			
		||||
            translate['Edit Links'] + ' | " title="' + \
 | 
			
		||||
            translate['Edit Links'] + '" src="/icons/edit.png" /></a>\n'
 | 
			
		||||
 | 
			
		||||
    if artist:
 | 
			
		||||
        # show the theme designer icon
 | 
			
		||||
        htmlStr += \
 | 
			
		||||
        html_str += \
 | 
			
		||||
            '      <a href="/users/' + nickname + '/themedesigner" ' + \
 | 
			
		||||
            'accesskey="' + accessKeys['menuThemeDesigner'] + '">' + \
 | 
			
		||||
            'accesskey="' + access_keys['menuThemeDesigner'] + '">' + \
 | 
			
		||||
            '<img class="' + editImageClass + '" loading="lazy" alt="' + \
 | 
			
		||||
            translate['Theme Designer'] + ' | " title="' + \
 | 
			
		||||
            translate['Theme Designer'] + '" src="/icons/theme.png" /></a>\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -191,51 +193,51 @@ def get_left_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
        '" loading="lazy" alt="' + rssTitle + '" title="' + rssTitle + \
 | 
			
		||||
        '" src="/icons/logorss.png" /></a>\n'
 | 
			
		||||
    if rss_icon_at_top:
 | 
			
		||||
        htmlStr += rssIconStr
 | 
			
		||||
    htmlStr += '      </div>\n'
 | 
			
		||||
        html_str += rssIconStr
 | 
			
		||||
    html_str += '      </div>\n'
 | 
			
		||||
 | 
			
		||||
    if editImageClass == 'leftColEdit':
 | 
			
		||||
        htmlStr += '      </center>\n'
 | 
			
		||||
        html_str += '      </center>\n'
 | 
			
		||||
 | 
			
		||||
    if (editor or rss_icon_at_top) and not showHeaderImage:
 | 
			
		||||
        htmlStr += '</div><br>'
 | 
			
		||||
        html_str += '</div><br>'
 | 
			
		||||
 | 
			
		||||
    # if showHeaderImage:
 | 
			
		||||
    #     htmlStr += '<br>'
 | 
			
		||||
    #     html_str += '<br>'
 | 
			
		||||
 | 
			
		||||
    # flag used not to show the first separator
 | 
			
		||||
    firstSeparatorAdded = False
 | 
			
		||||
    first_separator_added = False
 | 
			
		||||
 | 
			
		||||
    linksFilename = base_dir + '/accounts/links.txt'
 | 
			
		||||
    links_filename = base_dir + '/accounts/links.txt'
 | 
			
		||||
    linksFileContainsEntries = False
 | 
			
		||||
    linksList = None
 | 
			
		||||
    if os.path.isfile(linksFilename):
 | 
			
		||||
        with open(linksFilename, 'r') as f:
 | 
			
		||||
            linksList = f.readlines()
 | 
			
		||||
    links_list = None
 | 
			
		||||
    if os.path.isfile(links_filename):
 | 
			
		||||
        with open(links_filename, 'r') as f:
 | 
			
		||||
            links_list = f.readlines()
 | 
			
		||||
 | 
			
		||||
    if not frontPage:
 | 
			
		||||
        # show a number of shares
 | 
			
		||||
        maxSharesInLeftColumn = 3
 | 
			
		||||
        max_shares_in_left_column = 3
 | 
			
		||||
        sharesList = \
 | 
			
		||||
            _get_left_column_shares(base_dir,
 | 
			
		||||
                                    http_prefix, domain, domain_full, nickname,
 | 
			
		||||
                                    maxSharesInLeftColumn, translate,
 | 
			
		||||
                                    max_shares_in_left_column, translate,
 | 
			
		||||
                                    shared_items_federated_domains)
 | 
			
		||||
        if linksList and sharesList:
 | 
			
		||||
            linksList = sharesList + linksList
 | 
			
		||||
        if links_list and sharesList:
 | 
			
		||||
            links_list = sharesList + links_list
 | 
			
		||||
 | 
			
		||||
        wantedList = \
 | 
			
		||||
            _get_left_column_wanted(base_dir,
 | 
			
		||||
                                    http_prefix, domain, domain_full, nickname,
 | 
			
		||||
                                    maxSharesInLeftColumn, translate,
 | 
			
		||||
                                    max_shares_in_left_column, translate,
 | 
			
		||||
                                    shared_items_federated_domains)
 | 
			
		||||
        if linksList and wantedList:
 | 
			
		||||
            linksList = wantedList + linksList
 | 
			
		||||
        if links_list and wantedList:
 | 
			
		||||
            links_list = wantedList + links_list
 | 
			
		||||
 | 
			
		||||
    newTabStr = ' target="_blank" rel="nofollow noopener noreferrer"'
 | 
			
		||||
    if linksList:
 | 
			
		||||
        htmlStr += '<nav>\n'
 | 
			
		||||
        for lineStr in linksList:
 | 
			
		||||
    if links_list:
 | 
			
		||||
        html_str += '<nav>\n'
 | 
			
		||||
        for lineStr in links_list:
 | 
			
		||||
            if ' ' not in lineStr:
 | 
			
		||||
                if '#' not in lineStr:
 | 
			
		||||
                    if '*' not in lineStr:
 | 
			
		||||
| 
						 | 
				
			
			@ -285,12 +287,12 @@ def get_left_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
                    # add link to the returned html
 | 
			
		||||
                    if '?showshare=' not in linkStr and \
 | 
			
		||||
                       '?showwarning=' not in linkStr:
 | 
			
		||||
                        htmlStr += \
 | 
			
		||||
                        html_str += \
 | 
			
		||||
                            '      <p><a href="' + linkStr + \
 | 
			
		||||
                            '"' + newTabStr + '>' + \
 | 
			
		||||
                            lineStr + '</a></p>\n'
 | 
			
		||||
                    else:
 | 
			
		||||
                        htmlStr += \
 | 
			
		||||
                        html_str += \
 | 
			
		||||
                            '      <p><a href="' + linkStr + \
 | 
			
		||||
                            '">' + lineStr + '</a></p>\n'
 | 
			
		||||
                    linksFileContainsEntries = True
 | 
			
		||||
| 
						 | 
				
			
			@ -301,51 +303,51 @@ def get_left_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
                    # add link to the returned html
 | 
			
		||||
                    if '?showshare=' not in linkStr and \
 | 
			
		||||
                       '?showwarning=' not in linkStr:
 | 
			
		||||
                        htmlStr += \
 | 
			
		||||
                        html_str += \
 | 
			
		||||
                            '      <p><a href="' + linkStr + \
 | 
			
		||||
                            '"' + newTabStr + '>' + \
 | 
			
		||||
                            lineStr.strip() + '</a></p>\n'
 | 
			
		||||
                    else:
 | 
			
		||||
                        htmlStr += \
 | 
			
		||||
                        html_str += \
 | 
			
		||||
                            '      <p><a href="' + linkStr + \
 | 
			
		||||
                            '">' + lineStr.strip() + '</a></p>\n'
 | 
			
		||||
                    linksFileContainsEntries = True
 | 
			
		||||
            else:
 | 
			
		||||
                if lineStr.startswith('#') or lineStr.startswith('*'):
 | 
			
		||||
                    lineStr = lineStr[1:].strip()
 | 
			
		||||
                    if firstSeparatorAdded:
 | 
			
		||||
                        htmlStr += separatorStr
 | 
			
		||||
                    firstSeparatorAdded = True
 | 
			
		||||
                    htmlStr += \
 | 
			
		||||
                    if first_separator_added:
 | 
			
		||||
                        html_str += separator_str
 | 
			
		||||
                    first_separator_added = True
 | 
			
		||||
                    html_str += \
 | 
			
		||||
                        '      <h3 class="linksHeader">' + \
 | 
			
		||||
                        lineStr + '</h3>\n'
 | 
			
		||||
                else:
 | 
			
		||||
                    htmlStr += \
 | 
			
		||||
                    html_str += \
 | 
			
		||||
                        '      <p>' + lineStr + '</p>\n'
 | 
			
		||||
                linksFileContainsEntries = True
 | 
			
		||||
        htmlStr += '</nav>\n'
 | 
			
		||||
        html_str += '</nav>\n'
 | 
			
		||||
 | 
			
		||||
    if firstSeparatorAdded:
 | 
			
		||||
        htmlStr += separatorStr
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
    if first_separator_added:
 | 
			
		||||
        html_str += separator_str
 | 
			
		||||
    html_str += \
 | 
			
		||||
        '<p class="login-text"><a href="/users/' + nickname + \
 | 
			
		||||
        '/catalog.csv">' + translate['Shares Catalog'] + '</a></p>'
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
    html_str += \
 | 
			
		||||
        '<p class="login-text"><a href="/users/' + \
 | 
			
		||||
        nickname + '/accesskeys" accesskey="' + \
 | 
			
		||||
        accessKeys['menuKeys'] + '">' + \
 | 
			
		||||
        access_keys['menuKeys'] + '">' + \
 | 
			
		||||
        translate['Key Shortcuts'] + '</a></p>'
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
    html_str += \
 | 
			
		||||
        '<p class="login-text"><a href="/about">' + \
 | 
			
		||||
        translate['About this Instance'] + '</a></p>'
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
    html_str += \
 | 
			
		||||
        '<p class="login-text"><a href="/terms">' + \
 | 
			
		||||
        translate['Terms of Service'] + '</a></p>'
 | 
			
		||||
 | 
			
		||||
    if linksFileContainsEntries and not rss_icon_at_top:
 | 
			
		||||
        htmlStr += '<br><div class="columnIcons">' + rssIconStr + '</div>'
 | 
			
		||||
        html_str += '<br><div class="columnIcons">' + rssIconStr + '</div>'
 | 
			
		||||
 | 
			
		||||
    return htmlStr
 | 
			
		||||
    return html_str
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def html_links_mobile(css_cache: {}, base_dir: str,
 | 
			
		||||
| 
						 | 
				
			
			@ -355,16 +357,16 @@ def html_links_mobile(css_cache: {}, base_dir: str,
 | 
			
		|||
                      rss_icon_at_top: bool,
 | 
			
		||||
                      icons_as_buttons: bool,
 | 
			
		||||
                      defaultTimeline: str,
 | 
			
		||||
                      theme: str, accessKeys: {},
 | 
			
		||||
                      theme: str, access_keys: {},
 | 
			
		||||
                      shared_items_federated_domains: []) -> str:
 | 
			
		||||
    """Show the left column links within mobile view
 | 
			
		||||
    """
 | 
			
		||||
    htmlStr = ''
 | 
			
		||||
    html_str = ''
 | 
			
		||||
 | 
			
		||||
    # the css filename
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    # is the user a site editor?
 | 
			
		||||
    if nickname == 'news':
 | 
			
		||||
| 
						 | 
				
			
			@ -376,47 +378,48 @@ def html_links_mobile(css_cache: {}, base_dir: str,
 | 
			
		|||
 | 
			
		||||
    domain = remove_domain_port(domain_full)
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
    instance_title = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    htmlStr = html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    html_str = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instance_title, None)
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
    html_str += \
 | 
			
		||||
        '<a href="/users/' + nickname + '/' + defaultTimeline + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['menuTimeline'] + '">' + \
 | 
			
		||||
        'accesskey="' + access_keys['menuTimeline'] + '">' + \
 | 
			
		||||
        '<img loading="lazy" class="timeline-banner" ' + \
 | 
			
		||||
        'alt="' + translate['Switch to timeline view'] + '" ' + \
 | 
			
		||||
        'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'
 | 
			
		||||
        'src="/users/' + nickname + '/' + banner_file + '" /></a>\n'
 | 
			
		||||
 | 
			
		||||
    htmlStr += '<div class="col-left-mobile">\n'
 | 
			
		||||
    htmlStr += '<center>' + \
 | 
			
		||||
    html_str += '<div class="col-left-mobile">\n'
 | 
			
		||||
    html_str += '<center>' + \
 | 
			
		||||
        header_buttons_front_screen(translate, nickname,
 | 
			
		||||
                                    'links', authorized,
 | 
			
		||||
                                    icons_as_buttons) + '</center>'
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
    html_str += \
 | 
			
		||||
        get_left_column_content(base_dir, nickname, domain_full,
 | 
			
		||||
                                http_prefix, translate,
 | 
			
		||||
                                editor, artist,
 | 
			
		||||
                                False, timelinePath,
 | 
			
		||||
                                rss_icon_at_top, False, False,
 | 
			
		||||
                                theme, accessKeys,
 | 
			
		||||
                                theme, access_keys,
 | 
			
		||||
                                shared_items_federated_domains)
 | 
			
		||||
    if editor and not _links_exist(base_dir):
 | 
			
		||||
        htmlStr += '<br><br><br>\n<center>\n  '
 | 
			
		||||
        htmlStr += translate['Select the edit icon to add web links']
 | 
			
		||||
        htmlStr += '\n</center>\n'
 | 
			
		||||
        html_str += '<br><br><br>\n<center>\n  '
 | 
			
		||||
        html_str += translate['Select the edit icon to add web links']
 | 
			
		||||
        html_str += '\n</center>\n'
 | 
			
		||||
 | 
			
		||||
    # end of col-left-mobile
 | 
			
		||||
    htmlStr += '</div>\n'
 | 
			
		||||
    html_str += '</div>\n'
 | 
			
		||||
 | 
			
		||||
    htmlStr += '</div>\n' + html_footer()
 | 
			
		||||
    return htmlStr
 | 
			
		||||
    html_str += '</div>\n' + html_footer()
 | 
			
		||||
    return html_str
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def html_edit_links(css_cache: {}, translate: {}, base_dir: str, path: str,
 | 
			
		||||
                    domain: str, port: int, http_prefix: str,
 | 
			
		||||
                    defaultTimeline: str, theme: str,
 | 
			
		||||
                    accessKeys: {}) -> str:
 | 
			
		||||
                    access_keys: {}) -> str:
 | 
			
		||||
    """Shows the edit links screen
 | 
			
		||||
    """
 | 
			
		||||
    if '/users/' not in path:
 | 
			
		||||
| 
						 | 
				
			
			@ -432,109 +435,110 @@ def html_edit_links(css_cache: {}, translate: {}, base_dir: str, path: str,
 | 
			
		|||
    if not is_editor(base_dir, nickname):
 | 
			
		||||
        return ''
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-links.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-links.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/links.css'):
 | 
			
		||||
        cssFilename = base_dir + '/links.css'
 | 
			
		||||
        css_filename = base_dir + '/links.css'
 | 
			
		||||
 | 
			
		||||
    # filename of the banner shown at the top
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    banner_file, _ = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
    instance_title = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    editLinksForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    edit_links_form = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instance_title, None)
 | 
			
		||||
 | 
			
		||||
    # top banner
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '<header>\n' + \
 | 
			
		||||
        '<a href="/users/' + nickname + '/' + defaultTimeline + '" title="' + \
 | 
			
		||||
        translate['Switch to timeline view'] + '" alt="' + \
 | 
			
		||||
        translate['Switch to timeline view'] + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['menuTimeline'] + '">\n'
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
        'accesskey="' + access_keys['menuTimeline'] + '">\n'
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '<img loading="lazy" class="timeline-banner" ' + \
 | 
			
		||||
        'alt = "" src="' + \
 | 
			
		||||
        '/users/' + nickname + '/' + bannerFile + '" /></a>\n' + \
 | 
			
		||||
        '/users/' + nickname + '/' + banner_file + '" /></a>\n' + \
 | 
			
		||||
        '</header>\n'
 | 
			
		||||
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '<form enctype="multipart/form-data" method="POST" ' + \
 | 
			
		||||
        'accept-charset="UTF-8" action="' + path + '/linksdata">\n'
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '  <div class="vertical-center">\n'
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '    <div class="containerSubmitNewPost">\n'
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '      <h1>' + translate['Edit Links'] + '</h1>'
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '      <input type="submit" name="submitLinks" value="' + \
 | 
			
		||||
        translate['Submit'] + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['submitButton'] + '">\n'
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
        'accesskey="' + access_keys['submitButton'] + '">\n'
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '    </div>\n'
 | 
			
		||||
 | 
			
		||||
    linksFilename = base_dir + '/accounts/links.txt'
 | 
			
		||||
    linksStr = ''
 | 
			
		||||
    if os.path.isfile(linksFilename):
 | 
			
		||||
        with open(linksFilename, 'r') as fp:
 | 
			
		||||
            linksStr = fp.read()
 | 
			
		||||
    links_filename = base_dir + '/accounts/links.txt'
 | 
			
		||||
    links_str = ''
 | 
			
		||||
    if os.path.isfile(links_filename):
 | 
			
		||||
        with open(links_filename, 'r') as fp_links:
 | 
			
		||||
            links_str = fp_links.read()
 | 
			
		||||
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '<div class="container">'
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '  ' + \
 | 
			
		||||
        translate['One link per line. Description followed by the link.'] + \
 | 
			
		||||
        '<br>'
 | 
			
		||||
    newColLinkStr = translate['New link title and URL']
 | 
			
		||||
    editLinksForm += edit_text_field(None, 'newColLink', '', newColLinkStr)
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
    new_col_link_str = translate['New link title and URL']
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        edit_text_field(None, 'newColLink', '', new_col_link_str)
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '  <textarea id="message" name="editedLinks" ' + \
 | 
			
		||||
        'style="height:80vh" spellcheck="false">' + linksStr + '</textarea>'
 | 
			
		||||
    editLinksForm += \
 | 
			
		||||
        'style="height:80vh" spellcheck="false">' + links_str + '</textarea>'
 | 
			
		||||
    edit_links_form += \
 | 
			
		||||
        '</div>'
 | 
			
		||||
 | 
			
		||||
    # the admin can edit terms of service and about text
 | 
			
		||||
    adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if adminNickname:
 | 
			
		||||
        if nickname == adminNickname:
 | 
			
		||||
            aboutFilename = base_dir + '/accounts/about.md'
 | 
			
		||||
            aboutStr = ''
 | 
			
		||||
            if os.path.isfile(aboutFilename):
 | 
			
		||||
                with open(aboutFilename, 'r') as fp:
 | 
			
		||||
                    aboutStr = fp.read()
 | 
			
		||||
    admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if admin_nickname:
 | 
			
		||||
        if nickname == admin_nickname:
 | 
			
		||||
            about_filename = base_dir + '/accounts/about.md'
 | 
			
		||||
            about_str = ''
 | 
			
		||||
            if os.path.isfile(about_filename):
 | 
			
		||||
                with open(about_filename, 'r') as fp_about:
 | 
			
		||||
                    about_str = fp_about.read()
 | 
			
		||||
 | 
			
		||||
            editLinksForm += \
 | 
			
		||||
            edit_links_form += \
 | 
			
		||||
                '<div class="container">'
 | 
			
		||||
            editLinksForm += \
 | 
			
		||||
            edit_links_form += \
 | 
			
		||||
                '  ' + \
 | 
			
		||||
                translate['About this Instance'] + \
 | 
			
		||||
                '<br>'
 | 
			
		||||
            editLinksForm += \
 | 
			
		||||
            edit_links_form += \
 | 
			
		||||
                '  <textarea id="message" name="editedAbout" ' + \
 | 
			
		||||
                'style="height:100vh" spellcheck="true" autocomplete="on">' + \
 | 
			
		||||
                aboutStr + '</textarea>'
 | 
			
		||||
            editLinksForm += \
 | 
			
		||||
                about_str + '</textarea>'
 | 
			
		||||
            edit_links_form += \
 | 
			
		||||
                '</div>'
 | 
			
		||||
 | 
			
		||||
            TOSFilename = base_dir + '/accounts/tos.md'
 | 
			
		||||
            TOSStr = ''
 | 
			
		||||
            if os.path.isfile(TOSFilename):
 | 
			
		||||
                with open(TOSFilename, 'r') as fp:
 | 
			
		||||
                    TOSStr = fp.read()
 | 
			
		||||
            tos_filename = base_dir + '/accounts/tos.md'
 | 
			
		||||
            tos_str = ''
 | 
			
		||||
            if os.path.isfile(tos_filename):
 | 
			
		||||
                with open(tos_filename, 'r') as fp:
 | 
			
		||||
                    tos_str = fp.read()
 | 
			
		||||
 | 
			
		||||
            editLinksForm += \
 | 
			
		||||
            edit_links_form += \
 | 
			
		||||
                '<div class="container">'
 | 
			
		||||
            editLinksForm += \
 | 
			
		||||
            edit_links_form += \
 | 
			
		||||
                '  ' + \
 | 
			
		||||
                translate['Terms of Service'] + \
 | 
			
		||||
                '<br>'
 | 
			
		||||
            editLinksForm += \
 | 
			
		||||
            edit_links_form += \
 | 
			
		||||
                '  <textarea id="message" name="editedTOS" ' + \
 | 
			
		||||
                'style="height:100vh" spellcheck="true" autocomplete="on">' + \
 | 
			
		||||
                TOSStr + '</textarea>'
 | 
			
		||||
            editLinksForm += \
 | 
			
		||||
                tos_str + '</textarea>'
 | 
			
		||||
            edit_links_form += \
 | 
			
		||||
                '</div>'
 | 
			
		||||
 | 
			
		||||
    editLinksForm += html_footer()
 | 
			
		||||
    return editLinksForm
 | 
			
		||||
    edit_links_form += html_footer()
 | 
			
		||||
    return edit_links_form
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,7 +60,7 @@ def get_right_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
                             showHeaderImage: bool,
 | 
			
		||||
                             theme: str,
 | 
			
		||||
                             defaultTimeline: str,
 | 
			
		||||
                             accessKeys: {}) -> str:
 | 
			
		||||
                             access_keys: {}) -> str:
 | 
			
		||||
    """Returns html content for the right column
 | 
			
		||||
    """
 | 
			
		||||
    htmlStr = ''
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ def get_right_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
            '        <a href="' + \
 | 
			
		||||
            '/users/' + nickname + '/newblog?nodropdown" ' + \
 | 
			
		||||
            'title="' + titleStr + '" ' + \
 | 
			
		||||
            'accesskey="' + accessKeys['menuNewPost'] + '">' + \
 | 
			
		||||
            'accesskey="' + access_keys['menuNewPost'] + '">' + \
 | 
			
		||||
            '<button class="publishbtn">' + \
 | 
			
		||||
            translate['Publish'] + '</button></a>\n'
 | 
			
		||||
    else:
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +134,7 @@ def get_right_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
            htmlStr += \
 | 
			
		||||
                '        <a href="' + \
 | 
			
		||||
                '/users/' + nickname + '/editnewswire" ' + \
 | 
			
		||||
                'accesskey="' + accessKeys['menuEdit'] + '">' + \
 | 
			
		||||
                'accesskey="' + access_keys['menuEdit'] + '">' + \
 | 
			
		||||
                '<img class="' + editImageClass + \
 | 
			
		||||
                '" loading="lazy" alt="' + \
 | 
			
		||||
                translate['Edit newswire'] + ' | " title="' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +145,7 @@ def get_right_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
            htmlStr += \
 | 
			
		||||
                '        <a href="' + \
 | 
			
		||||
                '/users/' + nickname + '/editnewswire" ' + \
 | 
			
		||||
                'accesskey="' + accessKeys['menuEdit'] + '">' + \
 | 
			
		||||
                'accesskey="' + access_keys['menuEdit'] + '">' + \
 | 
			
		||||
                '<img class="' + editImageClass + \
 | 
			
		||||
                '" loading="lazy" alt="' + \
 | 
			
		||||
                translate['Edit newswire'] + ' | " title="' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +179,7 @@ def get_right_column_content(base_dir: str, nickname: str, domain_full: str,
 | 
			
		|||
            htmlStr += \
 | 
			
		||||
                '        <a href="' + \
 | 
			
		||||
                '/users/' + nickname + '/newblog?nodropdown" ' + \
 | 
			
		||||
                'accesskey="' + accessKeys['menuNewPost'] + '">' + \
 | 
			
		||||
                'accesskey="' + access_keys['menuNewPost'] + '">' + \
 | 
			
		||||
                '<img class="' + editImageClass + \
 | 
			
		||||
                '" loading="lazy" alt="' + \
 | 
			
		||||
                titleStr + '" title="' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -360,16 +360,17 @@ def html_citations(base_dir: str, nickname: str, domain: str,
 | 
			
		|||
                citationsSelected.append(dateStr)
 | 
			
		||||
 | 
			
		||||
    # the css filename
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
    instance_title = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    htmlStr = html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    htmlStr = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instance_title, None)
 | 
			
		||||
 | 
			
		||||
    # top banner
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
        '<a href="/users/' + nickname + '/newblog" title="' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -377,7 +378,7 @@ def html_citations(base_dir: str, nickname: str, domain: str,
 | 
			
		|||
        translate['Go Back'] + '">\n'
 | 
			
		||||
    htmlStr += '<img loading="lazy" class="timeline-banner" ' + \
 | 
			
		||||
        'alt="" src="' + \
 | 
			
		||||
        '/users/' + nickname + '/' + bannerFile + '" /></a>\n'
 | 
			
		||||
        '/users/' + nickname + '/' + banner_file + '" /></a>\n'
 | 
			
		||||
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
        '<form enctype="multipart/form-data" method="POST" ' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -457,15 +458,15 @@ def html_newswire_mobile(css_cache: {}, base_dir: str, nickname: str,
 | 
			
		|||
                         icons_as_buttons: bool,
 | 
			
		||||
                         defaultTimeline: str,
 | 
			
		||||
                         theme: str,
 | 
			
		||||
                         accessKeys: {}) -> str:
 | 
			
		||||
                         access_keys: {}) -> str:
 | 
			
		||||
    """Shows the mobile version of the newswire right column
 | 
			
		||||
    """
 | 
			
		||||
    htmlStr = ''
 | 
			
		||||
 | 
			
		||||
    # the css filename
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    if nickname == 'news':
 | 
			
		||||
        editor = False
 | 
			
		||||
| 
						 | 
				
			
			@ -479,18 +480,19 @@ def html_newswire_mobile(css_cache: {}, base_dir: str, nickname: str,
 | 
			
		|||
 | 
			
		||||
    showPublishButton = editor
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
    instance_title = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    htmlStr = html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    htmlStr = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instance_title, None)
 | 
			
		||||
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
    htmlStr += \
 | 
			
		||||
        '<a href="/users/' + nickname + '/' + defaultTimeline + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['menuTimeline'] + '">' + \
 | 
			
		||||
        'accesskey="' + access_keys['menuTimeline'] + '">' + \
 | 
			
		||||
        '<img loading="lazy" class="timeline-banner" ' + \
 | 
			
		||||
        'alt="' + translate['Timeline banner image'] + '" ' + \
 | 
			
		||||
        'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'
 | 
			
		||||
        'src="/users/' + nickname + '/' + banner_file + '" /></a>\n'
 | 
			
		||||
 | 
			
		||||
    htmlStr += '<div class="col-right-mobile">\n'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -506,7 +508,7 @@ def html_newswire_mobile(css_cache: {}, base_dir: str, nickname: str,
 | 
			
		|||
                                 False, timelinePath, showPublishButton,
 | 
			
		||||
                                 show_publish_as_icon, rss_icon_at_top, False,
 | 
			
		||||
                                 authorized, False, theme,
 | 
			
		||||
                                 defaultTimeline, accessKeys)
 | 
			
		||||
                                 defaultTimeline, access_keys)
 | 
			
		||||
    if editor and not newswire:
 | 
			
		||||
        htmlStr += '<br><br><br>\n'
 | 
			
		||||
        htmlStr += '<center>\n  '
 | 
			
		||||
| 
						 | 
				
			
			@ -522,7 +524,7 @@ def html_newswire_mobile(css_cache: {}, base_dir: str, nickname: str,
 | 
			
		|||
def html_edit_newswire(css_cache: {}, translate: {}, base_dir: str, path: str,
 | 
			
		||||
                       domain: str, port: int, http_prefix: str,
 | 
			
		||||
                       defaultTimeline: str, theme: str,
 | 
			
		||||
                       accessKeys: {}) -> str:
 | 
			
		||||
                       access_keys: {}) -> str:
 | 
			
		||||
    """Shows the edit newswire screen
 | 
			
		||||
    """
 | 
			
		||||
    if '/users/' not in path:
 | 
			
		||||
| 
						 | 
				
			
			@ -538,18 +540,18 @@ def html_edit_newswire(css_cache: {}, translate: {}, base_dir: str, path: str,
 | 
			
		|||
    if not is_moderator(base_dir, nickname):
 | 
			
		||||
        return ''
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-links.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-links.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/links.css'):
 | 
			
		||||
        cssFilename = base_dir + '/links.css'
 | 
			
		||||
        css_filename = base_dir + '/links.css'
 | 
			
		||||
 | 
			
		||||
    # filename of the banner shown at the top
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
    instance_title = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    editNewswireForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instance_title, None)
 | 
			
		||||
 | 
			
		||||
    # top banner
 | 
			
		||||
    editNewswireForm += \
 | 
			
		||||
| 
						 | 
				
			
			@ -557,9 +559,9 @@ def html_edit_newswire(css_cache: {}, translate: {}, base_dir: str, path: str,
 | 
			
		|||
        '<a href="/users/' + nickname + '/' + defaultTimeline + '" title="' + \
 | 
			
		||||
        translate['Switch to timeline view'] + '" alt="' + \
 | 
			
		||||
        translate['Switch to timeline view'] + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['menuTimeline'] + '">\n'
 | 
			
		||||
        'accesskey="' + access_keys['menuTimeline'] + '">\n'
 | 
			
		||||
    editNewswireForm += '<img loading="lazy" class="timeline-banner" src="' + \
 | 
			
		||||
        '/users/' + nickname + '/' + bannerFile + '" ' + \
 | 
			
		||||
        '/users/' + nickname + '/' + banner_file + '" ' + \
 | 
			
		||||
        'alt="" /></a>\n</header>'
 | 
			
		||||
 | 
			
		||||
    editNewswireForm += \
 | 
			
		||||
| 
						 | 
				
			
			@ -574,7 +576,7 @@ def html_edit_newswire(css_cache: {}, translate: {}, base_dir: str, path: str,
 | 
			
		|||
    editNewswireForm += \
 | 
			
		||||
        '      <input type="submit" name="submitNewswire" value="' + \
 | 
			
		||||
        translate['Submit'] + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['submitButton'] + '">\n'
 | 
			
		||||
        'accesskey="' + access_keys['submitButton'] + '">\n'
 | 
			
		||||
    editNewswireForm += \
 | 
			
		||||
        '    </div>\n'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -668,14 +670,14 @@ def html_edit_news_post(css_cache: {}, translate: {}, base_dir: str, path: str,
 | 
			
		|||
    if not post_json_object:
 | 
			
		||||
        return ''
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-links.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-links.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/links.css'):
 | 
			
		||||
        cssFilename = base_dir + '/links.css'
 | 
			
		||||
        css_filename = base_dir + '/links.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
    instance_title = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    editNewsPostForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instance_title, None)
 | 
			
		||||
    editNewsPostForm += \
 | 
			
		||||
        '<form enctype="multipart/form-data" method="POST" ' + \
 | 
			
		||||
        'accept-charset="UTF-8" action="' + path + '/newseditdata">\n'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,14 +56,14 @@ def html_confirm_delete(css_cache: {},
 | 
			
		|||
        return None
 | 
			
		||||
 | 
			
		||||
    delete_postStr = None
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    delete_postStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    delete_postStr += \
 | 
			
		||||
        individual_post_as_html(signing_priv_key_pem,
 | 
			
		||||
                                True, recent_posts_cache, max_recent_posts,
 | 
			
		||||
| 
						 | 
				
			
			@ -135,12 +135,12 @@ def html_confirm_remove_shared_item(css_cache: {}, translate: {},
 | 
			
		|||
 | 
			
		||||
    set_custom_background(base_dir, 'shares-background', 'follow-background')
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/follow.css'):
 | 
			
		||||
        cssFilename = base_dir + '/follow.css'
 | 
			
		||||
        css_filename = base_dir + '/follow.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    sharesStr = html_header_with_external_style(cssFilename,
 | 
			
		||||
    sharesStr = html_header_with_external_style(css_filename,
 | 
			
		||||
                                                instanceTitle, None)
 | 
			
		||||
    sharesStr += '<div class="follow">\n'
 | 
			
		||||
    sharesStr += '  <div class="followAvatar">\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -189,12 +189,12 @@ def html_confirm_follow(css_cache: {}, translate: {}, base_dir: str,
 | 
			
		|||
            copyfile(base_dir + '/accounts/follow-background-custom.jpg',
 | 
			
		||||
                     base_dir + '/accounts/follow-background.jpg')
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/follow.css'):
 | 
			
		||||
        cssFilename = base_dir + '/follow.css'
 | 
			
		||||
        css_filename = base_dir + '/follow.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    followStr = html_header_with_external_style(cssFilename,
 | 
			
		||||
    followStr = html_header_with_external_style(css_filename,
 | 
			
		||||
                                                instanceTitle, None)
 | 
			
		||||
    followStr += '<div class="follow">\n'
 | 
			
		||||
    followStr += '  <div class="followAvatar">\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -235,12 +235,12 @@ def html_confirm_unfollow(css_cache: {}, translate: {}, base_dir: str,
 | 
			
		|||
            copyfile(base_dir + '/accounts/follow-background-custom.jpg',
 | 
			
		||||
                     base_dir + '/accounts/follow-background.jpg')
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/follow.css'):
 | 
			
		||||
        cssFilename = base_dir + '/follow.css'
 | 
			
		||||
        css_filename = base_dir + '/follow.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    followStr = html_header_with_external_style(cssFilename,
 | 
			
		||||
    followStr = html_header_with_external_style(css_filename,
 | 
			
		||||
                                                instanceTitle, None)
 | 
			
		||||
    followStr += '<div class="follow">\n'
 | 
			
		||||
    followStr += '  <div class="followAvatar">\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -279,12 +279,12 @@ def html_confirm_unblock(css_cache: {}, translate: {}, base_dir: str,
 | 
			
		|||
 | 
			
		||||
    set_custom_background(base_dir, 'block-background', 'follow-background')
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/follow.css'):
 | 
			
		||||
        cssFilename = base_dir + '/follow.css'
 | 
			
		||||
        css_filename = base_dir + '/follow.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    blockStr = html_header_with_external_style(cssFilename,
 | 
			
		||||
    blockStr = html_header_with_external_style(css_filename,
 | 
			
		||||
                                               instanceTitle, None)
 | 
			
		||||
    blockStr += '<div class="block">\n'
 | 
			
		||||
    blockStr += '  <div class="blockAvatar">\n'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,7 +80,7 @@ def _html_new_post_drop_down(scopeIcon: str, scopeDescription: str,
 | 
			
		|||
                             dropdownReminderSuffix: str,
 | 
			
		||||
                             dropdownReportSuffix: str,
 | 
			
		||||
                             noDropDown: bool,
 | 
			
		||||
                             accessKeys: {}) -> str:
 | 
			
		||||
                             access_keys: {}) -> str:
 | 
			
		||||
    """Returns the html for a drop down list of new post types
 | 
			
		||||
    """
 | 
			
		||||
    dropDownContent = '<nav><div class="newPostDropdown">\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +100,7 @@ def _html_new_post_drop_down(scopeIcon: str, scopeDescription: str,
 | 
			
		|||
    if showPublicOnDropdown:
 | 
			
		||||
        dropDownContent += \
 | 
			
		||||
            '<li><a href="' + pathBase + dropdownNewPostSuffix + \
 | 
			
		||||
            '" accesskey="' + accessKeys['Public'] + '">' + \
 | 
			
		||||
            '" accesskey="' + access_keys['Public'] + '">' + \
 | 
			
		||||
            '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
            'icons/scope_public.png"/><b>' + \
 | 
			
		||||
            translate['Public'] + '</b><br>' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ def _html_new_post_drop_down(scopeIcon: str, scopeDescription: str,
 | 
			
		|||
        if defaultTimeline == 'tlfeatures':
 | 
			
		||||
            dropDownContent += \
 | 
			
		||||
                '<li><a href="' + pathBase + dropdownNewBlogSuffix + \
 | 
			
		||||
                '" accesskey="' + accessKeys['menuBlogs'] + '">' + \
 | 
			
		||||
                '" accesskey="' + access_keys['menuBlogs'] + '">' + \
 | 
			
		||||
                '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
                'icons/scope_blog.png"/><b>' + \
 | 
			
		||||
                translate['Article'] + '</b><br>' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +116,7 @@ def _html_new_post_drop_down(scopeIcon: str, scopeDescription: str,
 | 
			
		|||
        else:
 | 
			
		||||
            dropDownContent += \
 | 
			
		||||
                '<li><a href="' + pathBase + dropdownNewBlogSuffix + \
 | 
			
		||||
                '" accesskey="' + accessKeys['menuBlogs'] + '">' + \
 | 
			
		||||
                '" accesskey="' + access_keys['menuBlogs'] + '">' + \
 | 
			
		||||
                '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
                'icons/scope_blog.png"/><b>' + \
 | 
			
		||||
                translate['Blog'] + '</b><br>' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -129,14 +129,14 @@ def _html_new_post_drop_down(scopeIcon: str, scopeDescription: str,
 | 
			
		|||
            translate['Not on public timeline'] + '</a></li>\n'
 | 
			
		||||
    dropDownContent += \
 | 
			
		||||
        '<li><a href="' + pathBase + dropdownFollowersSuffix + \
 | 
			
		||||
        '" accesskey="' + accessKeys['menuFollowers'] + '">' + \
 | 
			
		||||
        '" accesskey="' + access_keys['menuFollowers'] + '">' + \
 | 
			
		||||
        '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
        'icons/scope_followers.png"/><b>' + \
 | 
			
		||||
        translate['Followers'] + '</b><br>' + \
 | 
			
		||||
        translate['Only to followers'] + '</a></li>\n'
 | 
			
		||||
    dropDownContent += \
 | 
			
		||||
        '<li><a href="' + pathBase + dropdownDMSuffix + \
 | 
			
		||||
        '" accesskey="' + accessKeys['menuDM'] + '">' + \
 | 
			
		||||
        '" accesskey="' + access_keys['menuDM'] + '">' + \
 | 
			
		||||
        '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
        'icons/scope_dm.png"/><b>' + \
 | 
			
		||||
        translate['DM'] + '</b><br>' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -144,14 +144,14 @@ def _html_new_post_drop_down(scopeIcon: str, scopeDescription: str,
 | 
			
		|||
 | 
			
		||||
    dropDownContent += \
 | 
			
		||||
        '<li><a href="' + pathBase + dropdownReminderSuffix + \
 | 
			
		||||
        '" accesskey="' + accessKeys['Reminder'] + '">' + \
 | 
			
		||||
        '" accesskey="' + access_keys['Reminder'] + '">' + \
 | 
			
		||||
        '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
        'icons/scope_reminder.png"/><b>' + \
 | 
			
		||||
        translate['Reminder'] + '</b><br>' + \
 | 
			
		||||
        translate['Scheduled note to yourself'] + '</a></li>\n'
 | 
			
		||||
    dropDownContent += \
 | 
			
		||||
        '<li><a href="' + pathBase + dropdownReportSuffix + \
 | 
			
		||||
        '" accesskey="' + accessKeys['reportButton'] + '">' + \
 | 
			
		||||
        '" accesskey="' + access_keys['reportButton'] + '">' + \
 | 
			
		||||
        '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
        'icons/scope_report.png"/><b>' + \
 | 
			
		||||
        translate['Report'] + '</b><br>' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -160,14 +160,14 @@ def _html_new_post_drop_down(scopeIcon: str, scopeDescription: str,
 | 
			
		|||
    if not replyStr:
 | 
			
		||||
        dropDownContent += \
 | 
			
		||||
            '<li><a href="' + pathBase + \
 | 
			
		||||
            '/newshare" accesskey="' + accessKeys['menuShares'] + '">' + \
 | 
			
		||||
            '/newshare" accesskey="' + access_keys['menuShares'] + '">' + \
 | 
			
		||||
            '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
            'icons/scope_share.png"/><b>' + \
 | 
			
		||||
            translate['Shares'] + '</b><br>' + \
 | 
			
		||||
            translate['Describe a shared item'] + '</a></li>\n'
 | 
			
		||||
        dropDownContent += \
 | 
			
		||||
            '<li><a href="' + pathBase + \
 | 
			
		||||
            '/newwanted" accesskey="' + accessKeys['menuWanted'] + '">' + \
 | 
			
		||||
            '/newwanted" accesskey="' + access_keys['menuWanted'] + '">' + \
 | 
			
		||||
            '<img loading="lazy" alt="" title="" src="/' + \
 | 
			
		||||
            'icons/scope_wanted.png"/><b>' + \
 | 
			
		||||
            translate['Wanted'] + '</b><br>' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {},
 | 
			
		|||
                  domain_full: str,
 | 
			
		||||
                  defaultTimeline: str, newswire: {},
 | 
			
		||||
                  theme: str, noDropDown: bool,
 | 
			
		||||
                  accessKeys: {}, customSubmitText: str,
 | 
			
		||||
                  access_keys: {}, customSubmitText: str,
 | 
			
		||||
                  conversationId: str,
 | 
			
		||||
                  recent_posts_cache: {}, max_recent_posts: int,
 | 
			
		||||
                  session, cached_webfingers: {},
 | 
			
		||||
| 
						 | 
				
			
			@ -239,7 +239,7 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {},
 | 
			
		|||
    messageBoxHeight = 400
 | 
			
		||||
 | 
			
		||||
    # filename of the banner shown at the top
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
 | 
			
		||||
    if not path.endswith('/newshare') and not path.endswith('/newwanted'):
 | 
			
		||||
| 
						 | 
				
			
			@ -345,9 +345,9 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {},
 | 
			
		|||
            newPostText = \
 | 
			
		||||
                '<p>' + file.read() + '</p>\n'
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    if '?' in path:
 | 
			
		||||
        path = path.split('?')[0]
 | 
			
		||||
| 
						 | 
				
			
			@ -638,7 +638,7 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {},
 | 
			
		|||
        dateAndLocation += '</div>\n'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    newPostForm = html_header_with_external_style(cssFilename,
 | 
			
		||||
    newPostForm = html_header_with_external_style(css_filename,
 | 
			
		||||
                                                  instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    newPostForm += \
 | 
			
		||||
| 
						 | 
				
			
			@ -646,9 +646,9 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {},
 | 
			
		|||
        '<a href="/users/' + nickname + '/' + defaultTimeline + '" title="' + \
 | 
			
		||||
        translate['Switch to timeline view'] + '" alt="' + \
 | 
			
		||||
        translate['Switch to timeline view'] + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['menuTimeline'] + '">\n'
 | 
			
		||||
        'accesskey="' + access_keys['menuTimeline'] + '">\n'
 | 
			
		||||
    newPostForm += '<img loading="lazy" class="timeline-banner" src="' + \
 | 
			
		||||
        '/users/' + nickname + '/' + bannerFile + '" alt="" /></a>\n' + \
 | 
			
		||||
        '/users/' + nickname + '/' + banner_file + '" alt="" /></a>\n' + \
 | 
			
		||||
        '</header>\n'
 | 
			
		||||
 | 
			
		||||
    mentionsStr = ''
 | 
			
		||||
| 
						 | 
				
			
			@ -721,7 +721,7 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {},
 | 
			
		|||
                                     dropdownDMSuffix,
 | 
			
		||||
                                     dropdownReminderSuffix,
 | 
			
		||||
                                     dropdownReportSuffix,
 | 
			
		||||
                                     noDropDown, accessKeys)
 | 
			
		||||
                                     noDropDown, access_keys)
 | 
			
		||||
    else:
 | 
			
		||||
        if not shareDescription:
 | 
			
		||||
            # reporting a post to moderator
 | 
			
		||||
| 
						 | 
				
			
			@ -771,7 +771,7 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {},
 | 
			
		|||
    newPostForm += \
 | 
			
		||||
        '      <td><input type="submit" name="submitPost" value="' + \
 | 
			
		||||
        submitText + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['submitButton'] + '"></td>\n'
 | 
			
		||||
        'accesskey="' + access_keys['submitButton'] + '"></td>\n'
 | 
			
		||||
 | 
			
		||||
    newPostForm += '      </tr>\n</table>\n'
 | 
			
		||||
    newPostForm += '    </div>\n'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,7 +109,7 @@ def html_front_screen(signing_priv_key_pem: str,
 | 
			
		|||
                      newswire: {}, theme: str,
 | 
			
		||||
                      peertube_instances: [],
 | 
			
		||||
                      allow_local_network_access: bool,
 | 
			
		||||
                      accessKeys: {},
 | 
			
		||||
                      access_keys: {},
 | 
			
		||||
                      system_language: str, max_like_count: int,
 | 
			
		||||
                      shared_items_federated_domains: [],
 | 
			
		||||
                      extraJson: {},
 | 
			
		||||
| 
						 | 
				
			
			@ -135,11 +135,11 @@ def html_front_screen(signing_priv_key_pem: str,
 | 
			
		|||
                                              icons_as_buttons)
 | 
			
		||||
 | 
			
		||||
    # If this is the news account then show a different banner
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
    profileHeaderStr = \
 | 
			
		||||
        '<img loading="lazy" class="timeline-banner" ' + \
 | 
			
		||||
        'src="/users/' + nickname + '/' + bannerFile + '" />\n'
 | 
			
		||||
        'src="/users/' + nickname + '/' + banner_file + '" />\n'
 | 
			
		||||
    if loginButton:
 | 
			
		||||
        profileHeaderStr += '<center>' + loginButton + '</center>\n'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ def html_front_screen(signing_priv_key_pem: str,
 | 
			
		|||
                                http_prefix, translate,
 | 
			
		||||
                                False, False,
 | 
			
		||||
                                False, None, rss_icon_at_top, True,
 | 
			
		||||
                                True, theme, accessKeys,
 | 
			
		||||
                                True, theme, access_keys,
 | 
			
		||||
                                shared_items_federated_domains)
 | 
			
		||||
    profileHeaderStr += \
 | 
			
		||||
        '      </td>\n' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -166,12 +166,12 @@ def html_front_screen(signing_priv_key_pem: str,
 | 
			
		|||
 | 
			
		||||
    profileStr = profileHeaderStr
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    licenseStr = ''
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
    profileStr += \
 | 
			
		||||
        _html_front_screen_posts(recent_posts_cache, max_recent_posts,
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +199,7 @@ def html_front_screen(signing_priv_key_pem: str,
 | 
			
		|||
                                 False, False, newswire, False,
 | 
			
		||||
                                 False, None, False, False,
 | 
			
		||||
                                 False, True, authorized, True, theme,
 | 
			
		||||
                                 defaultTimeline, accessKeys)
 | 
			
		||||
                                 defaultTimeline, access_keys)
 | 
			
		||||
    profileFooterStr += \
 | 
			
		||||
        '      </td>\n' + \
 | 
			
		||||
        '  </tr>\n' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -209,6 +209,6 @@ def html_front_screen(signing_priv_key_pem: str,
 | 
			
		|||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    profileStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None) + \
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None) + \
 | 
			
		||||
        profileStr + profileFooterStr + html_footer()
 | 
			
		||||
    return profileStr
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,13 +203,14 @@ def html_search_hashtag_category(css_cache: {}, translate: {},
 | 
			
		|||
 | 
			
		||||
    set_custom_background(base_dir, 'search-background', 'follow-background')
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-search.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-search.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/search.css'):
 | 
			
		||||
        cssFilename = base_dir + '/search.css'
 | 
			
		||||
        css_filename = base_dir + '/search.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    htmlStr = html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    htmlStr = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    # show a banner above the search box
 | 
			
		||||
    searchBannerFile, searchBannerFilename = \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,7 +47,7 @@ def header_buttons_timeline(defaultTimeline: str,
 | 
			
		|||
                            calendarImage: str,
 | 
			
		||||
                            followApprovals: str,
 | 
			
		||||
                            icons_as_buttons: bool,
 | 
			
		||||
                            accessKeys: {}) -> str:
 | 
			
		||||
                            access_keys: {}) -> str:
 | 
			
		||||
    """Returns the header at the top of the timeline, containing
 | 
			
		||||
    buttons for inbox, outbox, search, calendar, etc
 | 
			
		||||
    """
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ def header_buttons_timeline(defaultTimeline: str,
 | 
			
		|||
    if defaultTimeline == 'tlmedia':
 | 
			
		||||
        tlStr += \
 | 
			
		||||
            '<a href="' + usersPath + '/tlmedia" tabindex="-1" ' + \
 | 
			
		||||
            'accesskey="' + accessKeys['menuMedia'] + '"' + \
 | 
			
		||||
            'accesskey="' + access_keys['menuMedia'] + '"' + \
 | 
			
		||||
            '><button class="' + \
 | 
			
		||||
            mediaButton + '"><span>' + translate['Media'] + \
 | 
			
		||||
            '</span></button></a>'
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +106,7 @@ def header_buttons_timeline(defaultTimeline: str,
 | 
			
		|||
        if not minimal and not featuresHeader:
 | 
			
		||||
            tlStr += \
 | 
			
		||||
                '<a href="' + usersPath + '/tlmedia" tabindex="-1" ' + \
 | 
			
		||||
                'accesskey="' + accessKeys['menuMedia'] + '">' + \
 | 
			
		||||
                'accesskey="' + access_keys['menuMedia'] + '">' + \
 | 
			
		||||
                '<button class="' + \
 | 
			
		||||
                mediaButton + '"><span>' + translate['Media'] + \
 | 
			
		||||
                '</span></button></a>'
 | 
			
		||||
| 
						 | 
				
			
			@ -234,9 +234,9 @@ def header_buttons_timeline(defaultTimeline: str,
 | 
			
		|||
                '</span></button></a>'
 | 
			
		||||
 | 
			
		||||
    # benchmark 5
 | 
			
		||||
    timeDiff = int((time.time() - timelineStartTime) * 1000)
 | 
			
		||||
    if timeDiff > 100:
 | 
			
		||||
        print('TIMELINE TIMING ' + boxName + ' 5 = ' + str(timeDiff))
 | 
			
		||||
    time_diff = int((time.time() - timelineStartTime) * 1000)
 | 
			
		||||
    if time_diff > 100:
 | 
			
		||||
        print('TIMELINE TIMING ' + boxName + ' 5 = ' + str(time_diff))
 | 
			
		||||
 | 
			
		||||
    # the calendar button
 | 
			
		||||
    if not featuresHeader:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,9 +113,9 @@ def html_login(css_cache: {}, translate: {},
 | 
			
		|||
        with open(base_dir + '/accounts/login.txt', 'r') as file:
 | 
			
		||||
            loginText = '<p class="login-text">' + file.read() + '</p>'
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-login.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-login.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/login.css'):
 | 
			
		||||
        cssFilename = base_dir + '/login.css'
 | 
			
		||||
        css_filename = base_dir + '/login.css'
 | 
			
		||||
 | 
			
		||||
    # show the register button
 | 
			
		||||
    registerButtonStr = ''
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +151,7 @@ def html_login(css_cache: {}, translate: {},
 | 
			
		|||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    loginForm = \
 | 
			
		||||
        html_header_with_website_markup(cssFilename, instanceTitle,
 | 
			
		||||
        html_header_with_website_markup(css_filename, instanceTitle,
 | 
			
		||||
                                        http_prefix, domain,
 | 
			
		||||
                                        system_language)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ def html_moderation(css_cache: {}, defaultTimeline: str,
 | 
			
		|||
                    theme: str, peertube_instances: [],
 | 
			
		||||
                    allow_local_network_access: bool,
 | 
			
		||||
                    text_mode_banner: str,
 | 
			
		||||
                    accessKeys: {}, system_language: str,
 | 
			
		||||
                    access_keys: {}, system_language: str,
 | 
			
		||||
                    max_like_count: int,
 | 
			
		||||
                    shared_items_federated_domains: [],
 | 
			
		||||
                    signing_priv_key_pem: str,
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ def html_moderation(css_cache: {}, defaultTimeline: str,
 | 
			
		|||
                         publish_button_at_top,
 | 
			
		||||
                         authorized, moderationActionStr, theme,
 | 
			
		||||
                         peertube_instances, allow_local_network_access,
 | 
			
		||||
                         text_mode_banner, accessKeys, system_language,
 | 
			
		||||
                         text_mode_banner, access_keys, system_language,
 | 
			
		||||
                         max_like_count, shared_items_federated_domains,
 | 
			
		||||
                         signing_priv_key_pem, cw_lists, lists_enabled)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -95,14 +95,14 @@ def html_account_info(css_cache: {}, translate: {},
 | 
			
		|||
    msgStr1 = 'This account interacts with the following instances'
 | 
			
		||||
 | 
			
		||||
    infoForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    infoForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    searchNickname = get_nickname_from_actor(searchHandle)
 | 
			
		||||
    searchDomain, searchPort = get_domain_from_actor(searchHandle)
 | 
			
		||||
| 
						 | 
				
			
			@ -284,13 +284,13 @@ def html_moderation_info(css_cache: {}, translate: {},
 | 
			
		|||
        'Any blocks or suspensions made by moderators will be shown here.'
 | 
			
		||||
 | 
			
		||||
    infoForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    infoForm = html_header_with_external_style(cssFilename,
 | 
			
		||||
    infoForm = html_header_with_external_style(css_filename,
 | 
			
		||||
                                               instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    infoForm += \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,7 +61,7 @@ def html_person_options(defaultTimeline: str,
 | 
			
		|||
                        text_mode_banner: str,
 | 
			
		||||
                        news_instance: bool,
 | 
			
		||||
                        authorized: bool,
 | 
			
		||||
                        accessKeys: {},
 | 
			
		||||
                        access_keys: {},
 | 
			
		||||
                        isGroup: bool) -> str:
 | 
			
		||||
    """Show options for a person: view/follow/block/report
 | 
			
		||||
    """
 | 
			
		||||
| 
						 | 
				
			
			@ -111,9 +111,9 @@ def html_person_options(defaultTimeline: str,
 | 
			
		|||
        optionsLinkStr = \
 | 
			
		||||
            '    <input type="hidden" name="postUrl" value="' + \
 | 
			
		||||
            optionsLink + '">\n'
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-options.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-options.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/options.css'):
 | 
			
		||||
        cssFilename = base_dir + '/options.css'
 | 
			
		||||
        css_filename = base_dir + '/options.css'
 | 
			
		||||
 | 
			
		||||
    # To snooze, or not to snooze? That is the question
 | 
			
		||||
    snoozeButtonStr = 'Snooze'
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ def html_person_options(defaultTimeline: str,
 | 
			
		|||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    optionsStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    optionsStr += html_keyboard_navigation(text_mode_banner, {}, {})
 | 
			
		||||
    optionsStr += '<br><br>\n'
 | 
			
		||||
    optionsStr += '<div class="options">\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -255,7 +255,7 @@ def html_person_options(defaultTimeline: str,
 | 
			
		|||
                    '    ' + translate['Petname'] + ': \n' + \
 | 
			
		||||
                    '    <input type="text" name="optionpetname" value="' + \
 | 
			
		||||
                    petname + '" ' + \
 | 
			
		||||
                    'accesskey="' + accessKeys['enterPetname'] + '">\n' \
 | 
			
		||||
                    'accesskey="' + access_keys['enterPetname'] + '">\n' \
 | 
			
		||||
                    '    <button type="submit" class="buttonsmall" ' + \
 | 
			
		||||
                    'name="submitPetname">' + \
 | 
			
		||||
                    translate['Submit'] + '</button><br>\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -291,8 +291,8 @@ def html_person_options(defaultTimeline: str,
 | 
			
		|||
            # checkbox for permission to post to newswire
 | 
			
		||||
            newswirePostsPermitted = False
 | 
			
		||||
            if optionsDomainFull == domain_full:
 | 
			
		||||
                adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
                if (nickname == adminNickname or
 | 
			
		||||
                admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
                if (nickname == admin_nickname or
 | 
			
		||||
                    (is_moderator(base_dir, nickname) and
 | 
			
		||||
                     not is_moderator(base_dir, optionsNickname))):
 | 
			
		||||
                    newswireBlockedFilename = \
 | 
			
		||||
| 
						 | 
				
			
			@ -332,8 +332,8 @@ def html_person_options(defaultTimeline: str,
 | 
			
		|||
 | 
			
		||||
            # checkbox for permission to post to featured articles
 | 
			
		||||
            if news_instance and optionsDomainFull == domain_full:
 | 
			
		||||
                adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
                if (nickname == adminNickname or
 | 
			
		||||
                admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
                if (nickname == admin_nickname or
 | 
			
		||||
                    (is_moderator(base_dir, nickname) and
 | 
			
		||||
                     not is_moderator(base_dir, optionsNickname))):
 | 
			
		||||
                    checkboxStr = \
 | 
			
		||||
| 
						 | 
				
			
			@ -359,50 +359,51 @@ def html_person_options(defaultTimeline: str,
 | 
			
		|||
        optionsStr += \
 | 
			
		||||
            '    <a href="' + backPath + '"><button type="button" ' + \
 | 
			
		||||
            'class="buttonIcon" name="submitBack" ' + \
 | 
			
		||||
            'accesskey="' + accessKeys['menuTimeline'] + '">' + \
 | 
			
		||||
            'accesskey="' + access_keys['menuTimeline'] + '">' + \
 | 
			
		||||
            translate['Go Back'] + '</button></a>\n'
 | 
			
		||||
    else:
 | 
			
		||||
        optionsStr += \
 | 
			
		||||
            '    <a href="' + originPathStr + '"><button type="button" ' + \
 | 
			
		||||
            'class="buttonIcon" name="submitBack" accesskey="' + \
 | 
			
		||||
            accessKeys['menuTimeline'] + '">' + translate['Go Back'] + \
 | 
			
		||||
            access_keys['menuTimeline'] + '">' + translate['Go Back'] + \
 | 
			
		||||
            '</button></a>\n'
 | 
			
		||||
    if authorized:
 | 
			
		||||
        optionsStr += \
 | 
			
		||||
            '    <button type="submit" class="button" ' + \
 | 
			
		||||
            'name="submitView" accesskey="' + \
 | 
			
		||||
            accessKeys['viewButton'] + '">' + \
 | 
			
		||||
            access_keys['viewButton'] + '">' + \
 | 
			
		||||
            translate['View'] + '</button>\n'
 | 
			
		||||
    optionsStr += donateStr
 | 
			
		||||
    if authorized:
 | 
			
		||||
        optionsStr += \
 | 
			
		||||
            '    <button type="submit" class="button" name="submit' + \
 | 
			
		||||
            followStr + '" accesskey="' + accessKeys['followButton'] + '">' + \
 | 
			
		||||
            followStr + \
 | 
			
		||||
            '" accesskey="' + access_keys['followButton'] + '">' + \
 | 
			
		||||
            translate[followStr] + '</button>\n'
 | 
			
		||||
        optionsStr += \
 | 
			
		||||
            '    <button type="submit" class="button" name="submit' + \
 | 
			
		||||
            blockStr + '" accesskey="' + accessKeys['blockButton'] + '">' + \
 | 
			
		||||
            blockStr + '" accesskey="' + access_keys['blockButton'] + '">' + \
 | 
			
		||||
            translate[blockStr] + '</button>\n'
 | 
			
		||||
        optionsStr += \
 | 
			
		||||
            '    <button type="submit" class="button" name="submitDM" ' + \
 | 
			
		||||
            'accesskey="' + accessKeys['menuDM'] + '">' + \
 | 
			
		||||
            'accesskey="' + access_keys['menuDM'] + '">' + \
 | 
			
		||||
            translate['DM'] + '</button>\n'
 | 
			
		||||
        optionsStr += \
 | 
			
		||||
            '    <button type="submit" class="button" name="submit' + \
 | 
			
		||||
            snoozeButtonStr + '" accesskey="' + \
 | 
			
		||||
            accessKeys['snoozeButton'] + '">' + translate[snoozeButtonStr] + \
 | 
			
		||||
            access_keys['snoozeButton'] + '">' + translate[snoozeButtonStr] + \
 | 
			
		||||
            '</button>\n'
 | 
			
		||||
        optionsStr += \
 | 
			
		||||
            '    <button type="submit" class="button" ' + \
 | 
			
		||||
            'name="submitReport" accesskey="' + \
 | 
			
		||||
            accessKeys['reportButton'] + '">' + \
 | 
			
		||||
            access_keys['reportButton'] + '">' + \
 | 
			
		||||
            translate['Report'] + '</button>\n'
 | 
			
		||||
 | 
			
		||||
        if is_moderator(base_dir, nickname):
 | 
			
		||||
            optionsStr += \
 | 
			
		||||
                '    <button type="submit" class="button" ' + \
 | 
			
		||||
                'name="submitPersonInfo" accesskey="' + \
 | 
			
		||||
                accessKeys['infoButton'] + '">' + \
 | 
			
		||||
                access_keys['infoButton'] + '">' + \
 | 
			
		||||
                translate['Info'] + '</button>\n'
 | 
			
		||||
 | 
			
		||||
        personNotes = ''
 | 
			
		||||
| 
						 | 
				
			
			@ -422,7 +423,7 @@ def html_person_options(defaultTimeline: str,
 | 
			
		|||
        optionsStr += \
 | 
			
		||||
            '    <textarea id="message" ' + \
 | 
			
		||||
            'name="optionnotes" style="height:400px" spellcheck="true" ' + \
 | 
			
		||||
            'accesskey="' + accessKeys['enterNotes'] + '">' + \
 | 
			
		||||
            'accesskey="' + access_keys['enterNotes'] + '">' + \
 | 
			
		||||
            personNotes + '</textarea>\n'
 | 
			
		||||
 | 
			
		||||
    optionsStr += \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,9 +179,9 @@ def _log_post_timing(enableTimingLog: bool, postStartTime,
 | 
			
		|||
    """
 | 
			
		||||
    if not enableTimingLog:
 | 
			
		||||
        return
 | 
			
		||||
    timeDiff = int((time.time() - postStartTime) * 1000)
 | 
			
		||||
    if timeDiff > 100:
 | 
			
		||||
        print('TIMING INDIV ' + debugId + ' = ' + str(timeDiff))
 | 
			
		||||
    time_diff = int((time.time() - postStartTime) * 1000)
 | 
			
		||||
    if time_diff > 100:
 | 
			
		||||
        print('TIMING INDIV ' + debugId + ' = ' + str(time_diff))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def prepare_html_post_nickname(nickname: str, postHtml: str) -> str:
 | 
			
		||||
| 
						 | 
				
			
			@ -2153,14 +2153,14 @@ def html_individual_post(css_cache: {},
 | 
			
		|||
                                            False, authorized,
 | 
			
		||||
                                            False, False, False, False,
 | 
			
		||||
                                            cw_lists, lists_enabled)
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    metadataStr = _html_post_metadata_open_graph(domain, originalPostJson)
 | 
			
		||||
    headerStr = html_header_with_external_style(cssFilename,
 | 
			
		||||
    headerStr = html_header_with_external_style(css_filename,
 | 
			
		||||
                                                instanceTitle, metadataStr)
 | 
			
		||||
    return headerStr + postStr + html_footer()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2206,14 +2206,14 @@ def html_post_replies(css_cache: {},
 | 
			
		|||
                                        False, False,
 | 
			
		||||
                                        cw_lists, lists_enabled)
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    metadata = ''
 | 
			
		||||
    headerStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, metadata)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, metadata)
 | 
			
		||||
    return headerStr + repliesStr + html_footer()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2280,18 +2280,18 @@ def html_emoji_reaction_picker(css_cache: {},
 | 
			
		|||
                '  <a href="' + emojiUrl + '">' + emojiLabel + '</a>\n'
 | 
			
		||||
        emojiPicksStr += '</div>\n'
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    # filename of the banner shown at the top
 | 
			
		||||
    bannerFile, _ = \
 | 
			
		||||
    banner_file, _ = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme_name)
 | 
			
		||||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    metadata = ''
 | 
			
		||||
    headerStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, metadata)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, metadata)
 | 
			
		||||
 | 
			
		||||
    # banner
 | 
			
		||||
    headerStr += \
 | 
			
		||||
| 
						 | 
				
			
			@ -2302,7 +2302,7 @@ def html_emoji_reaction_picker(css_cache: {},
 | 
			
		|||
        translate['Switch to timeline view'] + '">\n'
 | 
			
		||||
    headerStr += '<img loading="lazy" class="timeline-banner" ' + \
 | 
			
		||||
        'alt="" ' + \
 | 
			
		||||
        'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n' + \
 | 
			
		||||
        'src="/users/' + nickname + '/' + banner_file + '" /></a>\n' + \
 | 
			
		||||
        '</header>\n'
 | 
			
		||||
 | 
			
		||||
    return headerStr + reactedToPostStr + emojiPicksStr + html_footer()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,9 +54,9 @@ def html_search_emoji(css_cache: {}, translate: {},
 | 
			
		|||
                 base_dir + '/emoji/emoji.json')
 | 
			
		||||
 | 
			
		||||
    searchStr = searchStr.lower().replace(':', '').strip('\n').strip('\r')
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    emojiLookupFilename = base_dir + '/emoji/emoji.json'
 | 
			
		||||
    customEmojiLookupFilename = base_dir + '/emojicustom/emoji.json'
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ def html_search_emoji(css_cache: {}, translate: {},
 | 
			
		|||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    emojiForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    emojiForm += '<center><h1>' + \
 | 
			
		||||
        translate['Emoji Search'] + \
 | 
			
		||||
        '</h1></center>'
 | 
			
		||||
| 
						 | 
				
			
			@ -235,14 +235,14 @@ def html_search_shared_items(css_cache: {}, translate: {},
 | 
			
		|||
    searchStrLower = urllib.parse.unquote(searchStr)
 | 
			
		||||
    searchStrLower = searchStrLower.lower().strip('\n').strip('\r')
 | 
			
		||||
    searchStrLowerList = searchStrLower.split('+')
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    sharedItemsForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    if sharesFileType == 'shares':
 | 
			
		||||
        titleStr = translate['Shared Items Search']
 | 
			
		||||
    else:
 | 
			
		||||
| 
						 | 
				
			
			@ -342,14 +342,14 @@ def html_search_emoji_text_entry(css_cache: {}, translate: {},
 | 
			
		|||
 | 
			
		||||
    set_custom_background(base_dir, 'search-background', 'follow-background')
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-follow.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/follow.css'):
 | 
			
		||||
        cssFilename = base_dir + '/follow.css'
 | 
			
		||||
        css_filename = base_dir + '/follow.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    emojiStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    emojiStr += '<div class="follow">\n'
 | 
			
		||||
    emojiStr += '  <div class="followAvatar">\n'
 | 
			
		||||
    emojiStr += '  <center>\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -375,7 +375,7 @@ def html_search_emoji_text_entry(css_cache: {}, translate: {},
 | 
			
		|||
def html_search(css_cache: {}, translate: {},
 | 
			
		||||
                base_dir: str, path: str, domain: str,
 | 
			
		||||
                defaultTimeline: str, theme: str,
 | 
			
		||||
                text_mode_banner: str, accessKeys: {}) -> str:
 | 
			
		||||
                text_mode_banner: str, access_keys: {}) -> str:
 | 
			
		||||
    """Search called from the timeline icon
 | 
			
		||||
    """
 | 
			
		||||
    actor = path.replace('/search', '')
 | 
			
		||||
| 
						 | 
				
			
			@ -383,13 +383,13 @@ def html_search(css_cache: {}, translate: {},
 | 
			
		|||
 | 
			
		||||
    set_custom_background(base_dir, 'search-background', 'follow-background')
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-search.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-search.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/search.css'):
 | 
			
		||||
        cssFilename = base_dir + '/search.css'
 | 
			
		||||
        css_filename = base_dir + '/search.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    followStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    # show a banner above the search box
 | 
			
		||||
    searchBannerFile, searchBannerFilename = \
 | 
			
		||||
| 
						 | 
				
			
			@ -400,7 +400,7 @@ def html_search(css_cache: {}, translate: {},
 | 
			
		|||
        text_mode_bannerStr = ''
 | 
			
		||||
 | 
			
		||||
    if os.path.isfile(searchBannerFilename):
 | 
			
		||||
        timelineKey = accessKeys['menuTimeline']
 | 
			
		||||
        timelineKey = access_keys['menuTimeline']
 | 
			
		||||
        usersPath = '/users/' + searchNickname
 | 
			
		||||
        followStr += \
 | 
			
		||||
            '<header>\n' + text_mode_bannerStr + \
 | 
			
		||||
| 
						 | 
				
			
			@ -423,7 +423,7 @@ def html_search(css_cache: {}, translate: {},
 | 
			
		|||
    followStr += \
 | 
			
		||||
        '    <input type="hidden" name="actor" value="' + actor + '">\n'
 | 
			
		||||
    followStr += '    <input type="text" name="searchtext" autofocus><br>\n'
 | 
			
		||||
    submitKey = accessKeys['submitButton']
 | 
			
		||||
    submitKey = access_keys['submitButton']
 | 
			
		||||
    followStr += '    <button type="submit" class="button" ' + \
 | 
			
		||||
        'name="submitSearch" accesskey="' + submitKey + '">' + \
 | 
			
		||||
        translate['Submit'] + '</button>\n'
 | 
			
		||||
| 
						 | 
				
			
			@ -545,14 +545,14 @@ def html_skills_search(actor: str,
 | 
			
		|||
 | 
			
		||||
    results.sort(reverse=True)
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    skillSearchForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    skillSearchForm += \
 | 
			
		||||
        '<center><h1><a href = "' + actor + '/search">' + \
 | 
			
		||||
        translate['Skills search'] + ': ' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -622,14 +622,14 @@ def html_history_search(css_cache: {}, translate: {}, base_dir: str,
 | 
			
		|||
        search_box_posts(base_dir, nickname, domain,
 | 
			
		||||
                         historysearch, postsPerPage, boxName)
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    historySearchForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    # add the page title
 | 
			
		||||
    domain_full = get_full_domain(domain, port)
 | 
			
		||||
| 
						 | 
				
			
			@ -751,9 +751,9 @@ def html_hashtag_search(css_cache: {},
 | 
			
		|||
        lines = f.readlines()
 | 
			
		||||
 | 
			
		||||
    # read the css
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    # ensure that the page number is in bounds
 | 
			
		||||
    if not pageNumber:
 | 
			
		||||
| 
						 | 
				
			
			@ -772,7 +772,7 @@ def html_hashtag_search(css_cache: {},
 | 
			
		|||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    hashtagSearchForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    if nickname:
 | 
			
		||||
        hashtagSearchForm += '<center>\n' + \
 | 
			
		||||
            '<h1><a href="/users/' + nickname + '/search">#' + \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,14 +17,14 @@ def html_suspended(css_cache: {}, base_dir: str) -> str:
 | 
			
		|||
    """Show the screen for suspended accounts
 | 
			
		||||
    """
 | 
			
		||||
    suspendedForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-suspended.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-suspended.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/suspended.css'):
 | 
			
		||||
        cssFilename = base_dir + '/suspended.css'
 | 
			
		||||
        css_filename = base_dir + '/suspended.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    suspendedForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    suspendedForm += \
 | 
			
		||||
        '<div><center>\n' + \
 | 
			
		||||
        '  <p class="screentitle">Account Suspended</p>\n' + \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,7 +169,7 @@ color_to_hex = {
 | 
			
		|||
def html_theme_designer(css_cache: {}, base_dir: str,
 | 
			
		||||
                        nickname: str, domain: str,
 | 
			
		||||
                        translate: {}, defaultTimeline: str,
 | 
			
		||||
                        theme_name: str, accessKeys: {}) -> str:
 | 
			
		||||
                        theme_name: str, access_keys: {}) -> str:
 | 
			
		||||
    """Edit theme settings
 | 
			
		||||
    """
 | 
			
		||||
    themeFilename = base_dir + '/theme/' + theme_name + '/theme.json'
 | 
			
		||||
| 
						 | 
				
			
			@ -186,23 +186,23 @@ def html_theme_designer(css_cache: {}, base_dir: str,
 | 
			
		|||
                themeJson[variableName] = value
 | 
			
		||||
 | 
			
		||||
    themeForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    themeForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme_name)
 | 
			
		||||
    themeForm += \
 | 
			
		||||
        '<a href="/users/' + nickname + '/' + defaultTimeline + '" ' + \
 | 
			
		||||
        'accesskey="' + accessKeys['menuTimeline'] + '">' + \
 | 
			
		||||
        'accesskey="' + access_keys['menuTimeline'] + '">' + \
 | 
			
		||||
        '<img loading="lazy" class="timeline-banner" ' + \
 | 
			
		||||
        'title="' + translate['Switch to timeline view'] + '" ' + \
 | 
			
		||||
        'alt="' + translate['Switch to timeline view'] + '" ' + \
 | 
			
		||||
        'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'
 | 
			
		||||
        'src="/users/' + nickname + '/' + banner_file + '" /></a>\n'
 | 
			
		||||
    themeForm += '<div class="container">\n'
 | 
			
		||||
 | 
			
		||||
    themeForm += \
 | 
			
		||||
| 
						 | 
				
			
			@ -211,8 +211,8 @@ def html_theme_designer(css_cache: {}, base_dir: str,
 | 
			
		|||
    themeForm += '  <form method="POST" action="' + \
 | 
			
		||||
        '/users/' + nickname + '/changeThemeSettings">\n'
 | 
			
		||||
 | 
			
		||||
    resetKey = accessKeys['menuLogout']
 | 
			
		||||
    submitKey = accessKeys['submitButton']
 | 
			
		||||
    resetKey = access_keys['menuLogout']
 | 
			
		||||
    submitKey = access_keys['submitButton']
 | 
			
		||||
    themeForm += \
 | 
			
		||||
        '    <center>\n' + \
 | 
			
		||||
        '    <button type="submit" class="button" ' + \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1354
									
								
								webapp_timeline.py
								
								
								
								
							
							
						
						
									
										1354
									
								
								webapp_timeline.py
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -20,7 +20,7 @@ def html_terms_of_service(css_cache: {}, base_dir: str,
 | 
			
		|||
                          http_prefix: str, domain_full: str) -> str:
 | 
			
		||||
    """Show the terms of service screen
 | 
			
		||||
    """
 | 
			
		||||
    adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
    if not os.path.isfile(base_dir + '/accounts/tos.md'):
 | 
			
		||||
        copyfile(base_dir + '/default_tos.md',
 | 
			
		||||
                 base_dir + '/accounts/tos.md')
 | 
			
		||||
| 
						 | 
				
			
			@ -36,20 +36,21 @@ def html_terms_of_service(css_cache: {}, base_dir: str,
 | 
			
		|||
            TOSText = markdown_to_html(file.read())
 | 
			
		||||
 | 
			
		||||
    TOSForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    TOSForm = html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
    TOSForm = \
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    TOSForm += '<div class="container">' + TOSText + '</div>\n'
 | 
			
		||||
    if adminNickname:
 | 
			
		||||
        adminActor = local_actor_url(http_prefix, adminNickname, domain_full)
 | 
			
		||||
    if admin_nickname:
 | 
			
		||||
        adminActor = local_actor_url(http_prefix, admin_nickname, domain_full)
 | 
			
		||||
        TOSForm += \
 | 
			
		||||
            '<div class="container"><center>\n' + \
 | 
			
		||||
            '<p class="administeredby">Administered by <a href="' + \
 | 
			
		||||
            adminActor + '">' + adminNickname + '</a></p>\n' + \
 | 
			
		||||
            adminActor + '">' + admin_nickname + '</a></p>\n' + \
 | 
			
		||||
            '</center></div>\n'
 | 
			
		||||
    TOSForm += html_footer()
 | 
			
		||||
    return TOSForm
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,14 +49,14 @@ def html_following_list(css_cache: {}, base_dir: str,
 | 
			
		|||
        followingList = msg.split('\n')
 | 
			
		||||
        followingList.sort()
 | 
			
		||||
        if followingList:
 | 
			
		||||
            cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
            css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
            if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
                cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
                css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
 | 
			
		||||
            instanceTitle = \
 | 
			
		||||
                get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
            followingListHtml = \
 | 
			
		||||
                html_header_with_external_style(cssFilename,
 | 
			
		||||
                html_header_with_external_style(css_filename,
 | 
			
		||||
                                                instanceTitle, None)
 | 
			
		||||
            for followingAddress in followingList:
 | 
			
		||||
                if followingAddress:
 | 
			
		||||
| 
						 | 
				
			
			@ -72,14 +72,14 @@ def html_hashtag_blocked(css_cache: {}, base_dir: str, translate: {}) -> str:
 | 
			
		|||
    """Show the screen for a blocked hashtag
 | 
			
		||||
    """
 | 
			
		||||
    blockedHashtagForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-suspended.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-suspended.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/suspended.css'):
 | 
			
		||||
        cssFilename = base_dir + '/suspended.css'
 | 
			
		||||
        css_filename = base_dir + '/suspended.css'
 | 
			
		||||
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
    blockedHashtagForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    blockedHashtagForm += '<div><center>\n'
 | 
			
		||||
    blockedHashtagForm += \
 | 
			
		||||
        '  <p class="screentitle">' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -476,26 +476,26 @@ def _get_image_file(base_dir: str, name: str, directory: str,
 | 
			
		|||
    returns the filenames for an image with the given name
 | 
			
		||||
    """
 | 
			
		||||
    bannerExtensions = get_image_extensions()
 | 
			
		||||
    bannerFile = ''
 | 
			
		||||
    bannerFilename = ''
 | 
			
		||||
    banner_file = ''
 | 
			
		||||
    banner_filename = ''
 | 
			
		||||
    for ext in bannerExtensions:
 | 
			
		||||
        bannerFileTest = name + '.' + ext
 | 
			
		||||
        bannerFilenameTest = directory + '/' + bannerFileTest
 | 
			
		||||
        if os.path.isfile(bannerFilenameTest):
 | 
			
		||||
            bannerFile = name + '_' + theme + '.' + ext
 | 
			
		||||
            bannerFilename = bannerFilenameTest
 | 
			
		||||
            return bannerFile, bannerFilename
 | 
			
		||||
        banner_fileTest = name + '.' + ext
 | 
			
		||||
        banner_filenameTest = directory + '/' + banner_fileTest
 | 
			
		||||
        if os.path.isfile(banner_filenameTest):
 | 
			
		||||
            banner_file = name + '_' + theme + '.' + ext
 | 
			
		||||
            banner_filename = banner_filenameTest
 | 
			
		||||
            return banner_file, banner_filename
 | 
			
		||||
    # if not found then use the default image
 | 
			
		||||
    theme = 'default'
 | 
			
		||||
    directory = base_dir + '/theme/' + theme
 | 
			
		||||
    for ext in bannerExtensions:
 | 
			
		||||
        bannerFileTest = name + '.' + ext
 | 
			
		||||
        bannerFilenameTest = directory + '/' + bannerFileTest
 | 
			
		||||
        if os.path.isfile(bannerFilenameTest):
 | 
			
		||||
            bannerFile = name + '_' + theme + '.' + ext
 | 
			
		||||
            bannerFilename = bannerFilenameTest
 | 
			
		||||
        banner_fileTest = name + '.' + ext
 | 
			
		||||
        banner_filenameTest = directory + '/' + banner_fileTest
 | 
			
		||||
        if os.path.isfile(banner_filenameTest):
 | 
			
		||||
            banner_file = name + '_' + theme + '.' + ext
 | 
			
		||||
            banner_filename = banner_filenameTest
 | 
			
		||||
            break
 | 
			
		||||
    return bannerFile, bannerFilename
 | 
			
		||||
    return banner_file, banner_filename
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_banner_file(base_dir: str,
 | 
			
		||||
| 
						 | 
				
			
			@ -527,11 +527,11 @@ def get_right_image_file(base_dir: str,
 | 
			
		|||
                           accountDir, nickname, domain, theme)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def html_header_with_external_style(cssFilename: str, instanceTitle: str,
 | 
			
		||||
def html_header_with_external_style(css_filename: str, instanceTitle: str,
 | 
			
		||||
                                    metadata: str, lang='en') -> str:
 | 
			
		||||
    if metadata is None:
 | 
			
		||||
        metadata = ''
 | 
			
		||||
    cssFile = '/' + cssFilename.split('/')[-1]
 | 
			
		||||
    cssFile = '/' + css_filename.split('/')[-1]
 | 
			
		||||
    htmlStr = \
 | 
			
		||||
        '<!DOCTYPE html>\n' + \
 | 
			
		||||
        '<html lang="' + lang + '">\n' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -554,7 +554,7 @@ def html_header_with_external_style(cssFilename: str, instanceTitle: str,
 | 
			
		|||
    return htmlStr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def html_header_with_person_markup(cssFilename: str, instanceTitle: str,
 | 
			
		||||
def html_header_with_person_markup(css_filename: str, instanceTitle: str,
 | 
			
		||||
                                   actor_json: {}, city: str,
 | 
			
		||||
                                   content_license_url: str,
 | 
			
		||||
                                   lang='en') -> str:
 | 
			
		||||
| 
						 | 
				
			
			@ -563,7 +563,7 @@ def html_header_with_person_markup(cssFilename: str, instanceTitle: str,
 | 
			
		|||
    """
 | 
			
		||||
    if not actor_json:
 | 
			
		||||
        htmlStr = \
 | 
			
		||||
            html_header_with_external_style(cssFilename,
 | 
			
		||||
            html_header_with_external_style(css_filename,
 | 
			
		||||
                                            instanceTitle, None, lang)
 | 
			
		||||
        return htmlStr
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -735,12 +735,12 @@ def html_header_with_person_markup(cssFilename: str, instanceTitle: str,
 | 
			
		|||
                    "\" property=\"og:" + ogTag + "\" />\n"
 | 
			
		||||
 | 
			
		||||
    htmlStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle,
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle,
 | 
			
		||||
                                        ogMetadata + profileMarkup, lang)
 | 
			
		||||
    return htmlStr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def html_header_with_website_markup(cssFilename: str, instanceTitle: str,
 | 
			
		||||
def html_header_with_website_markup(css_filename: str, instanceTitle: str,
 | 
			
		||||
                                    http_prefix: str, domain: str,
 | 
			
		||||
                                    system_language: str) -> str:
 | 
			
		||||
    """html header which includes website markup
 | 
			
		||||
| 
						 | 
				
			
			@ -792,13 +792,13 @@ def html_header_with_website_markup(cssFilename: str, instanceTitle: str,
 | 
			
		|||
        '    <meta content="summary_large_image" property="twitter:card" />\n'
 | 
			
		||||
 | 
			
		||||
    htmlStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle,
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle,
 | 
			
		||||
                                        ogMetadata + websiteMarkup,
 | 
			
		||||
                                        system_language)
 | 
			
		||||
    return htmlStr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def html_header_with_blog_markup(cssFilename: str, instanceTitle: str,
 | 
			
		||||
def html_header_with_blog_markup(css_filename: str, instanceTitle: str,
 | 
			
		||||
                                 http_prefix: str, domain: str, nickname: str,
 | 
			
		||||
                                 system_language: str,
 | 
			
		||||
                                 published: str, modified: str,
 | 
			
		||||
| 
						 | 
				
			
			@ -851,7 +851,7 @@ def html_header_with_blog_markup(cssFilename: str, instanceTitle: str,
 | 
			
		|||
        modified + '" />\n'
 | 
			
		||||
 | 
			
		||||
    htmlStr = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle,
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle,
 | 
			
		||||
                                        ogMetadata + blogMarkup,
 | 
			
		||||
                                        system_language)
 | 
			
		||||
    return htmlStr
 | 
			
		||||
| 
						 | 
				
			
			@ -1273,7 +1273,7 @@ def html_hide_from_screen_reader(htmlStr: str) -> str:
 | 
			
		|||
    return '<span aria-hidden="true">' + htmlStr + '</span>'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def html_keyboard_navigation(banner: str, links: {}, accessKeys: {},
 | 
			
		||||
def html_keyboard_navigation(banner: str, links: {}, access_keys: {},
 | 
			
		||||
                             subHeading: str = None,
 | 
			
		||||
                             usersPath: str = None, translate: {} = None,
 | 
			
		||||
                             followApprovals: bool = False) -> str:
 | 
			
		||||
| 
						 | 
				
			
			@ -1298,8 +1298,8 @@ def html_keyboard_navigation(banner: str, links: {}, accessKeys: {},
 | 
			
		|||
    # show the list of links
 | 
			
		||||
    for title, url in links.items():
 | 
			
		||||
        accessKeyStr = ''
 | 
			
		||||
        if accessKeys.get(title):
 | 
			
		||||
            accessKeyStr = 'accesskey="' + accessKeys[title] + '"'
 | 
			
		||||
        if access_keys.get(title):
 | 
			
		||||
            accessKeyStr = 'accesskey="' + access_keys[title] + '"'
 | 
			
		||||
 | 
			
		||||
        htmlStr += '<li><label class="transparent">' + \
 | 
			
		||||
            '<a href="' + str(url) + '" ' + accessKeyStr + '>' + \
 | 
			
		||||
| 
						 | 
				
			
			@ -1480,9 +1480,9 @@ def html_search_result_share(base_dir: str, sharedItem: {}, translate: {},
 | 
			
		|||
    elif is_moderator(base_dir, nickname):
 | 
			
		||||
        showRemoveButton = True
 | 
			
		||||
    else:
 | 
			
		||||
        adminNickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
        if adminNickname:
 | 
			
		||||
            if actor.endswith('/users/' + adminNickname):
 | 
			
		||||
        admin_nickname = get_config_param(base_dir, 'admin')
 | 
			
		||||
        if admin_nickname:
 | 
			
		||||
            if actor.endswith('/users/' + admin_nickname):
 | 
			
		||||
                showRemoveButton = True
 | 
			
		||||
 | 
			
		||||
    if showRemoveButton:
 | 
			
		||||
| 
						 | 
				
			
			@ -1556,7 +1556,7 @@ def html_show_share(base_dir: str, domain: str, nickname: str,
 | 
			
		|||
    actor = local_actor_url(http_prefix, nickname, domain_full)
 | 
			
		||||
 | 
			
		||||
    # filename of the banner shown at the top
 | 
			
		||||
    bannerFile, bannerFilename = \
 | 
			
		||||
    banner_file, banner_filename = \
 | 
			
		||||
        get_banner_file(base_dir, nickname, domain, theme)
 | 
			
		||||
 | 
			
		||||
    shareStr = \
 | 
			
		||||
| 
						 | 
				
			
			@ -1565,20 +1565,20 @@ def html_show_share(base_dir: str, domain: str, nickname: str,
 | 
			
		|||
        defaultTimeline + '" title="" alt="">\n'
 | 
			
		||||
    shareStr += '<img loading="lazy" class="timeline-banner" ' + \
 | 
			
		||||
        'alt="" ' + \
 | 
			
		||||
        'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n' + \
 | 
			
		||||
        'src="/users/' + nickname + '/' + banner_file + '" /></a>\n' + \
 | 
			
		||||
        '</header><br>\n'
 | 
			
		||||
    shareStr += \
 | 
			
		||||
        html_search_result_share(base_dir, sharedItem, translate, http_prefix,
 | 
			
		||||
                                 domain_full, contactNickname, itemID,
 | 
			
		||||
                                 actor, sharesFileType, category)
 | 
			
		||||
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-profile.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/epicyon.css'):
 | 
			
		||||
        cssFilename = base_dir + '/epicyon.css'
 | 
			
		||||
        css_filename = base_dir + '/epicyon.css'
 | 
			
		||||
    instanceTitle = \
 | 
			
		||||
        get_config_param(base_dir, 'instanceTitle')
 | 
			
		||||
 | 
			
		||||
    return html_header_with_external_style(cssFilename,
 | 
			
		||||
    return html_header_with_external_style(css_filename,
 | 
			
		||||
                                           instanceTitle, None) + \
 | 
			
		||||
        shareStr + html_footer()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,12 +83,12 @@ def html_welcome_screen(base_dir: str, nickname: str,
 | 
			
		|||
            welcomeText = markdown_to_html(remove_html(welcomeText))
 | 
			
		||||
 | 
			
		||||
    welcomeForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-welcome.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-welcome.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/welcome.css'):
 | 
			
		||||
        cssFilename = base_dir + '/welcome.css'
 | 
			
		||||
        css_filename = base_dir + '/welcome.css'
 | 
			
		||||
 | 
			
		||||
    welcomeForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
    welcomeForm += \
 | 
			
		||||
        '<form enctype="multipart/form-data" method="POST" ' + \
 | 
			
		||||
        'accept-charset="UTF-8" ' + \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,12 +57,12 @@ def html_welcome_final(base_dir: str, nickname: str, domain: str,
 | 
			
		|||
            finalText = markdown_to_html(remove_html(finalText))
 | 
			
		||||
 | 
			
		||||
    finalForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-welcome.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-welcome.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/welcome.css'):
 | 
			
		||||
        cssFilename = base_dir + '/welcome.css'
 | 
			
		||||
        css_filename = base_dir + '/welcome.css'
 | 
			
		||||
 | 
			
		||||
    finalForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    finalForm += \
 | 
			
		||||
        '<div class="container">' + finalText + '</div>\n' + \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,12 +63,12 @@ def html_welcome_profile(base_dir: str, nickname: str, domain: str,
 | 
			
		|||
            profileText = markdown_to_html(remove_html(profileText))
 | 
			
		||||
 | 
			
		||||
    profileForm = ''
 | 
			
		||||
    cssFilename = base_dir + '/epicyon-welcome.css'
 | 
			
		||||
    css_filename = base_dir + '/epicyon-welcome.css'
 | 
			
		||||
    if os.path.isfile(base_dir + '/welcome.css'):
 | 
			
		||||
        cssFilename = base_dir + '/welcome.css'
 | 
			
		||||
        css_filename = base_dir + '/welcome.css'
 | 
			
		||||
 | 
			
		||||
    profileForm = \
 | 
			
		||||
        html_header_with_external_style(cssFilename, instanceTitle, None)
 | 
			
		||||
        html_header_with_external_style(css_filename, instanceTitle, None)
 | 
			
		||||
 | 
			
		||||
    # get the url of the avatar
 | 
			
		||||
    for ext in get_image_extensions():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue