mirror of
https://codeberg.org/catask-org/catask.git
synced 2025-04-20 13:53:42 -05:00
type annotations and return types, gif emoji support
This commit is contained in:
parent
a65d89c301
commit
65ed14858c
1 changed files with 35 additions and 33 deletions
68
functions.py
68
functions.py
|
@ -60,7 +60,7 @@ def saveJSON(dict, file_path):
|
||||||
json.dump(dict, file, indent=4)
|
json.dump(dict, file, indent=4)
|
||||||
|
|
||||||
# append to a json file
|
# append to a json file
|
||||||
def appendToJSON(new_data, file_path):
|
def appendToJSON(new_data, file_path) -> bool:
|
||||||
try:
|
try:
|
||||||
# open the file
|
# open the file
|
||||||
path = Path(file_path)
|
path = Path(file_path)
|
||||||
|
@ -80,16 +80,16 @@ def appendToJSON(new_data, file_path):
|
||||||
|
|
||||||
cfg = loadJSON(const.configFile)
|
cfg = loadJSON(const.configFile)
|
||||||
|
|
||||||
def formatRelativeTime(date_str):
|
def formatRelativeTime(date_str: str) -> str:
|
||||||
date_format = "%Y-%m-%d %H:%M:%S"
|
date_format = "%Y-%m-%d %H:%M:%S"
|
||||||
past_date = datetime.strptime(date_str, date_format)
|
past_date = datetime.strptime(date_str, date_format).replace(tzinfo=None)
|
||||||
|
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
time_difference = now - past_date
|
time_difference = now - past_date
|
||||||
|
|
||||||
return humanize.naturaltime(time_difference)
|
return humanize.naturaltime(time_difference)
|
||||||
|
|
||||||
def formatRelativeTime2(date_str):
|
def formatRelativeTime2(date_str: str) -> str:
|
||||||
date_format = "%Y-%m-%dT%H:%M:%SZ"
|
date_format = "%Y-%m-%dT%H:%M:%SZ"
|
||||||
|
|
||||||
past_date = None
|
past_date = None
|
||||||
|
@ -195,7 +195,8 @@ def getAllQuestions(limit: int = None, offset: int = None) -> dict:
|
||||||
|
|
||||||
return combined, metadata
|
return combined, metadata
|
||||||
|
|
||||||
def addQuestion(from_who, question, cw, noAntispam=False):
|
|
||||||
|
def addQuestion(from_who: str, question: str, cw: str, noAntispam: bool = False) -> dict:
|
||||||
|
|
||||||
if cfg['antispam']['type'] == 'basic':
|
if cfg['antispam']['type'] == 'basic':
|
||||||
antispam = request.form.get('antispam', '')
|
antispam = request.form.get('antispam', '')
|
||||||
|
@ -345,15 +346,15 @@ def readPlainFile(file, split=False):
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def savePlainFile(file, contents):
|
def savePlainFile(file, contents) -> None:
|
||||||
with open(file, 'w') as file:
|
with open(file, 'w') as file:
|
||||||
file.write(contents)
|
file.write(contents)
|
||||||
|
|
||||||
def getRandomWord():
|
def getRandomWord() -> str:
|
||||||
items = readPlainFile(const.antiSpamFile, split=True)
|
items = readPlainFile(const.antiSpamFile, split=True)
|
||||||
return random.choice(items)
|
return random.choice(items)
|
||||||
|
|
||||||
def trimContent(var, trim):
|
def trimContent(var, trim) -> str:
|
||||||
trim = int(trim)
|
trim = int(trim)
|
||||||
if trim > 0:
|
if trim > 0:
|
||||||
trimmed = var[:trim] + '…' if len(var) >= trim else var
|
trimmed = var[:trim] + '…' if len(var) >= trim else var
|
||||||
|
@ -394,7 +395,7 @@ def find_emoji_path(emoji_name):
|
||||||
head = to_snake_case(emoji_name).split('_')[0]
|
head = to_snake_case(emoji_name).split('_')[0]
|
||||||
if any(Path(EMOJI_BASE_PATH).glob(f'{head}.json')):
|
if any(Path(EMOJI_BASE_PATH).glob(f'{head}.json')):
|
||||||
for json_file in Path(EMOJI_BASE_PATH).glob('*.json'):
|
for json_file in Path(EMOJI_BASE_PATH).glob('*.json'):
|
||||||
app.logger.debug("\n[CatAsk/functions/find_emoji_path] Using JSON meta file\n")
|
app.logger.debug("[CatAsk/functions/find_emoji_path] Using JSON meta file")
|
||||||
pack_data = loadJSON(json_file)
|
pack_data = loadJSON(json_file)
|
||||||
emojis = pack_data.get('emojis', [])
|
emojis = pack_data.get('emojis', [])
|
||||||
|
|
||||||
|
@ -407,12 +408,13 @@ def find_emoji_path(emoji_name):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for address, dirs, files in os.walk(EMOJI_BASE_PATH):
|
for address, dirs, files in os.walk(EMOJI_BASE_PATH):
|
||||||
app.logger.debug("\n[CatAsk/functions/find_emoji_path] Falling back to scanning directories\n")
|
app.logger.debug("[CatAsk/functions/find_emoji_path] Falling back to scanning directories")
|
||||||
if f"{emoji_name}.png" in files:
|
for file in files:
|
||||||
rel_dir = os.path.relpath(address, EMOJI_BASE_PATH)
|
if os.path.splitext(file)[0] == emoji_name: # Check if the filename matches the emoji_name
|
||||||
emoji_path = os.path.join("static/emojis", rel_dir, f"{emoji_name}.png")
|
rel_dir = os.path.relpath(address, EMOJI_BASE_PATH)
|
||||||
emoji_cache[emoji_name] = emoji_path
|
emoji_path = os.path.join("static/emojis", rel_dir, file) # Use the actual file name
|
||||||
return emoji_path
|
emoji_cache[emoji_name] = emoji_path
|
||||||
|
return emoji_path
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -438,14 +440,14 @@ def emoji(md):
|
||||||
if md.renderer and md.renderer.NAME == 'html':
|
if md.renderer and md.renderer.NAME == 'html':
|
||||||
md.renderer.register('emoji', render_emoji)
|
md.renderer.register('emoji', render_emoji)
|
||||||
|
|
||||||
def listEmojis():
|
def listEmojis() -> list:
|
||||||
emojis = []
|
emojis = []
|
||||||
emoji_base_path = Path.cwd() / 'static' / 'emojis'
|
emoji_base_path = Path.cwd() / 'static' / 'emojis'
|
||||||
|
|
||||||
# Iterate over files that are directly in the emoji base path (not in subdirectories)
|
# Iterate over files that are directly in the emoji base path (not in subdirectories)
|
||||||
for file in emoji_base_path.iterdir():
|
for file in emoji_base_path.iterdir():
|
||||||
# Only include files, not directories
|
# Only include files, not directories
|
||||||
if file.is_file() and file.suffix in {'.png', '.jpg', '.jpeg', '.webp'}:
|
if file.is_file() and file.suffix in {'.png', '.jpg', '.jpeg', '.webp', '.gif'}:
|
||||||
# Get the relative path and name for the emoji
|
# Get the relative path and name for the emoji
|
||||||
relative_path = os.path.relpath(file, emoji_base_path)
|
relative_path = os.path.relpath(file, emoji_base_path)
|
||||||
emojis.append({
|
emojis.append({
|
||||||
|
@ -456,7 +458,7 @@ def listEmojis():
|
||||||
|
|
||||||
return emojis
|
return emojis
|
||||||
|
|
||||||
def listEmojiPacks():
|
def listEmojiPacks() -> list:
|
||||||
emoji_packs = []
|
emoji_packs = []
|
||||||
emoji_base_path = const.emojiPath
|
emoji_base_path = const.emojiPath
|
||||||
|
|
||||||
|
@ -473,7 +475,7 @@ def listEmojiPacks():
|
||||||
pack_data = loadJSON(meta_json_path)
|
pack_data = loadJSON(meta_json_path)
|
||||||
|
|
||||||
emoji_packs.append({
|
emoji_packs.append({
|
||||||
'name': pack_data.get('name', pack_dir.name).capitalize(),
|
'name': pack_data.get('name', pack_dir.name),
|
||||||
'exportedAt': pack_data.get('exportedAt', 'Unknown'),
|
'exportedAt': pack_data.get('exportedAt', 'Unknown'),
|
||||||
'preview_image': pack_data.get('preview_image', ''),
|
'preview_image': pack_data.get('preview_image', ''),
|
||||||
'website': pack_data.get('website', ''),
|
'website': pack_data.get('website', ''),
|
||||||
|
@ -486,13 +488,13 @@ def listEmojiPacks():
|
||||||
preview_image = None
|
preview_image = None
|
||||||
# Find the first image in the directory for preview
|
# Find the first image in the directory for preview
|
||||||
for file in pack_dir.iterdir():
|
for file in pack_dir.iterdir():
|
||||||
if file.suffix in {'.png', '.jpg', '.jpeg', '.webp'}:
|
if file.suffix in {'.png', '.jpg', '.jpeg', '.webp', '.gif'}:
|
||||||
preview_image = os.path.join('static/emojis', relative_path, file.name)
|
preview_image = os.path.join('static/emojis', relative_path, file.name)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Append pack info without meta.json
|
# Append pack info without meta.json
|
||||||
emoji_packs.append({
|
emoji_packs.append({
|
||||||
'name': pack_dir.name.capitalize(),
|
'name': pack_dir.name,
|
||||||
'preview_image': preview_image,
|
'preview_image': preview_image,
|
||||||
'relative_path': f'static/emojis/{relative_path}'
|
'relative_path': f'static/emojis/{relative_path}'
|
||||||
})
|
})
|
||||||
|
@ -500,10 +502,10 @@ def listEmojiPacks():
|
||||||
return emoji_packs
|
return emoji_packs
|
||||||
|
|
||||||
|
|
||||||
def processEmojis(meta_json_path):
|
def processEmojis(meta_json_path) -> list:
|
||||||
emoji_metadata = loadJSON(meta_json_path)
|
emoji_metadata = loadJSON(meta_json_path)
|
||||||
emojis = emoji_metadata.get('emojis', [])
|
emojis = emoji_metadata.get('emojis', [])
|
||||||
pack_name = emoji_metadata['emojis'][0]['emoji']['category'].capitalize()
|
pack_name = emoji_metadata['emojis'][0]['emoji']['category']
|
||||||
exported_at = emoji_metadata.get('exportedAt', 'Unknown')
|
exported_at = emoji_metadata.get('exportedAt', 'Unknown')
|
||||||
website = emoji_metadata.get('host', '')
|
website = emoji_metadata.get('host', '')
|
||||||
preview_image = os.path.join('static/emojis', pack_name.lower(), emoji_metadata['emojis'][0]['fileName'])
|
preview_image = os.path.join('static/emojis', pack_name.lower(), emoji_metadata['emojis'][0]['fileName'])
|
||||||
|
@ -534,7 +536,7 @@ def processEmojis(meta_json_path):
|
||||||
|
|
||||||
return processed_emojis
|
return processed_emojis
|
||||||
|
|
||||||
def renderMarkdown(text, allowed_tags=None):
|
def renderMarkdown(text: str, allowed_tags: bool = None) -> str:
|
||||||
plugins = [
|
plugins = [
|
||||||
'strikethrough',
|
'strikethrough',
|
||||||
button,
|
button,
|
||||||
|
@ -589,7 +591,7 @@ def renderMarkdown(text, allowed_tags=None):
|
||||||
clean_html = cleaner.clean(html)
|
clean_html = cleaner.clean(html)
|
||||||
return Markup(clean_html)
|
return Markup(clean_html)
|
||||||
|
|
||||||
def generateMetadata(question=None, answer=None):
|
def generateMetadata(question: str = None, answer: str = None) -> dict:
|
||||||
metadata = {
|
metadata = {
|
||||||
'title': cfg['instance']['title'],
|
'title': cfg['instance']['title'],
|
||||||
'description': cfg['instance']['description'],
|
'description': cfg['instance']['description'],
|
||||||
|
@ -609,23 +611,23 @@ def generateMetadata(question=None, answer=None):
|
||||||
# return 'metadata' dictionary
|
# return 'metadata' dictionary
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
allowedFileExtensions = {'png', 'jpg', 'jpeg', 'webp', 'bmp', 'jxl'}
|
allowedFileExtensions = {'png', 'jpg', 'jpeg', 'webp', 'bmp', 'jxl', 'gif'}
|
||||||
allowedArchiveExtensions = {'zip', 'tar', 'gz', 'bz2', 'xz'}
|
allowedArchiveExtensions = {'zip', 'tar', 'gz', 'bz2', 'xz'}
|
||||||
|
|
||||||
def allowedFile(filename):
|
def allowedFile(filename: str) -> bool:
|
||||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowedFileExtensions
|
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowedFileExtensions
|
||||||
|
|
||||||
def allowedArchive(filename):
|
def allowedArchive(filename: str) -> bool:
|
||||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowedArchiveExtensions
|
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowedArchiveExtensions
|
||||||
|
|
||||||
def stripArchExtension(filename):
|
def stripArchExtension(filename: str) -> str:
|
||||||
if filename.endswith(('.tar.gz', '.tar.bz2', '.tar.xz')):
|
if filename.endswith(('.tar.gz', '.tar.bz2', '.tar.xz')):
|
||||||
filename = filename.rsplit('.', 2)[0]
|
filename = filename.rsplit('.', 2)[0]
|
||||||
else:
|
else:
|
||||||
filename = filename.rsplit('.', 1)[0]
|
filename = filename.rsplit('.', 1)[0]
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
def generateFavicon(file_name):
|
def generateFavicon(file_name: str) -> None:
|
||||||
sizes = {
|
sizes = {
|
||||||
'apple-touch-icon.png': (180, 180),
|
'apple-touch-icon.png': (180, 180),
|
||||||
'android-chrome-192x192.png': (192, 192),
|
'android-chrome-192x192.png': (192, 192),
|
||||||
|
@ -645,7 +647,7 @@ def generateFavicon(file_name):
|
||||||
resized_img_absolute_path = const.faviconDir / filename
|
resized_img_absolute_path = const.faviconDir / filename
|
||||||
resized_img.save(resized_img_absolute_path)
|
resized_img.save(resized_img_absolute_path)
|
||||||
|
|
||||||
def createExport():
|
def createExport() -> dict:
|
||||||
try:
|
try:
|
||||||
# just to test if connection works
|
# just to test if connection works
|
||||||
conn = connectToDb()
|
conn = connectToDb()
|
||||||
|
@ -783,14 +785,14 @@ def retrospringImport(export_file):
|
||||||
conn.close()
|
conn.close()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def deleteExport(timestamp):
|
def deleteExport(timestamp: str) -> dict:
|
||||||
try:
|
try:
|
||||||
export_file = Path('static') / 'exports' / f'export-{timestamp}.zip'
|
export_file = Path('static') / 'exports' / f'export-{timestamp}.zip'
|
||||||
data = loadJSON(const.exportsFile)
|
data = loadJSON(const.exportsFile)
|
||||||
data = [export for export in data if export["timestamp_esc"] != timestamp]
|
data = [export for export in data if export["timestamp_esc"] != timestamp]
|
||||||
export_file.unlink()
|
export_file.unlink()
|
||||||
saveJSON(data, const.exportsFile)
|
saveJSON(data, const.exportsFile)
|
||||||
return {'message': f'Export {timestamp} deleted successfully.'}
|
return {'message': _('Export {} deleted successfully.').format(timestamp)}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {'error': str(e)}, 500
|
return {'error': str(e)}, 500
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue