#!/usr/bin/env python3.12 # pylint: disable=bare-except, broad-exception-caught import os import logging import time import datetime import traceback import aiosqlite as sqlite3 from fastapi import FastAPI, Request, HTTPException from .constructors import ValidTopKarmaRequest, ValidKarmaRetrievalRequest,\ ValidKarmaUpdateRequest class KarmaDB: """Karma DB Util""" def __init__(self): self.db_path = os.path.join("/", "usr", "local", "share", "sqlite_dbs", "karma.db") async def get_karma(self, keyword: str) -> int | dict: """Get Karma Value for Keyword""" async with sqlite3.connect(self.db_path, timeout=2) as db_conn: async with await db_conn.execute("SELECT score FROM karma WHERE keyword LIKE ? LIMIT 1", (keyword,)) as db_cursor: try: (score,) = await db_cursor.fetchone() return score except TypeError: return { 'err': True, 'errorText': f'No records for {keyword}', } async def get_top(self, n: int = 10): """Get Top n=10 Karma Entries""" try: async with sqlite3.connect(self.db_path, timeout=2) as db_conn: async with await db_conn.execute("SELECT keyword, score FROM karma ORDER BY score DESC LIMIT ?", (n,)) as db_cursor: return await db_cursor.fetchall() except: traceback.print_exc() return async def update_karma(self, granter: str, keyword: str, flag: int): """Update Karma for Keyword""" if not flag in [0, 1]: return modifier = "score + 1" if not flag else "score - 1" query = f"UPDATE karma SET score = {modifier}, last_change = ? WHERE keyword LIKE ?" new_keyword_query = "INSERT INTO karma(keyword, score, last_change) VALUES(?, ?, ?)" friendly_flag = "++" if not flag else "--" audit_message = f"{granter} adjusted karma for {keyword} @ {datetime.datetime.now().isoformat()}: {friendly_flag}" audit_query = "INSERT INTO karma_audit(impacted_keyword, comment) VALUES(?, ?)" now = int(time.time()) logging.debug("Audit message: %s{audit_message}\nKeyword: %s{keyword}") async with sqlite3.connect(self.db_path, timeout=2) as db_conn: async with await db_conn.execute(audit_query, (keyword, audit_message,)) as db_cursor: await db_conn.commit() await db_cursor.close() async with await db_conn.execute(query, (now, keyword,)) as db_cursor: if db_cursor.rowcount: await db_conn.commit() return True if db_cursor.rowcount < 1: # Keyword does not already exist await db_cursor.close() new_val = 1 if not flag else -1 async with await db_conn.execute(new_keyword_query, (keyword, new_val, now,)) as db_cursor: if db_cursor.rowcount >= 1: await db_conn.commit() return True else: return False class Karma(FastAPI): """Karma Endpoints""" def __init__(self, app: FastAPI, util, constants, glob_state): # pylint: disable=super-init-not-called self.app = app self.util = util self.constants = constants self.glob_state = glob_state self.db = KarmaDB() self.endpoints = { "karma/get": self.get_karma_handler, "karma/modify": self.modify_karma_handler, "karma/top": self.top_karma_handler, } for endpoint, handler in self.endpoints.items(): app.add_api_route(f"/{endpoint}", handler, methods=["POST"], include_in_schema=False) async def top_karma_handler(self, request: Request, data: ValidTopKarmaRequest | None = None): """ /karma/top Get top keywords for karma (Requires key) """ if not self.util.check_key(request.url.path, request.headers.get('X-Authd-With')): raise HTTPException(status_code=403, detail="Unauthorized") n = 10 if data: n = data.n try: top10 = await self.db.get_top(n=n) return top10 except: traceback.print_exc() return { 'err': True, 'errorText': 'Exception occurred.', } async def get_karma_handler(self, data: ValidKarmaRetrievalRequest, request: Request): """ /karma/get Get current karma value (Requires key) """ if not self.util.check_key(request.url.path, request.headers.get('X-Authd-With')): raise HTTPException(status_code=403, detail="Unauthorized") keyword = data.keyword try: count = await self.db.get_karma(keyword) return { 'keyword': keyword, 'count': count, } except: traceback.print_exc() return { 'err': True, 'errorText': "Exception occurred." } async def modify_karma_handler(self, data: ValidKarmaUpdateRequest, request: Request): """ /karma/update Update karma count (Requires key) """ if not self.util.check_key(request.url.path, request.headers.get('X-Authd-With'), 2): raise HTTPException(status_code=403, detail="Unauthorized") if not data.flag in [0, 1]: return { 'err': True, 'errorText': 'Invalid request' } return { 'success': await self.db.update_karma(data.granter, data.keyword, data.flag) }