diff options
Diffstat (limited to 'app/routes.py')
-rw-r--r-- | app/routes.py | 228 |
1 files changed, 151 insertions, 77 deletions
diff --git a/app/routes.py b/app/routes.py index fa73297..da8a502 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,120 +1,194 @@ import fastapi -from fastapi import Security, HTTPException -from fastapi.security import APIKeyHeader -import tabulate +from fastapi import Security, HTTPException, Request import pydantic import sqlalchemy from db import engine -from auth import auth -from func.signup import generate_account +from check_api_key import check_api_key +from func.generate_api_key import generate_api_key from func.newlink import generate_link from func.log import log -from func.delete_link import delete_link -from func.renew_link import renew_link -from func.link_records import link_records -from func.del_link_records import del_link_records +from func.link.delete import delete_link +from func.link.renew import renew_link +from func.link.records import get_link_records +from func.link.delrecords import delete_link_records +from func.remove_old_data import remove_old_data + +from apscheduler.schedulers.background import BackgroundScheduler +from contextlib import asynccontextmanager + + +@asynccontextmanager +async def lifespan(app: fastapi.FastAPI): + # Create the scheduler + scheduler = BackgroundScheduler() + scheduler.add_job(remove_old_data, "cron", hour="0", minute="01") + scheduler.start() + yield class Newlink(pydantic.BaseModel): redirect_link: str -app = fastapi.FastAPI() -api_key_header = APIKeyHeader(name="X-API-Key") +app = fastapi.FastAPI(lifespan=lifespan) -def check_api_key(api_key_header: str = Security(api_key_header)) -> str: - with engine.begin() as conn: - response = conn.execute(sqlalchemy.text("SELECT api_key FROM accounts WHERE api_key = :api_key"), {'api_key': api_key_header}).fetchone() - if response: - return response[0] - else: - raise HTTPException( - status_code=fastapi.status.HTTP_401_UNAUTHORIZED, - detail="Invalid or missing API key" - ) - -@app.get("/signup") -async def signup(): - api_key = generate_account() +@app.post("/api/getapikey") +async def get_api_key(): + """ + Create a new API key + """ + api_key = generate_api_key() return {"api_key": api_key} -@app.post("/newlink") +@app.post("/api/genlink") async def newlink(newlink: Newlink, api_key: str = Security(check_api_key)): + """ + Generate a new link that will redirect to the specified URL and log IPs in the middle + """ data = generate_link(newlink.redirect_link, api_key) - if data: - return {"link": data[0], "expire_date": data[1]} - else: + if data == 422: raise HTTPException( status_code=fastapi.status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Malformed redirect link provided" ) + return {"link": data[0], "expire_date": data[1]} -@app.post("/links") -async def links(api_key: str = Security(check_api_key)): - with engine.begin() as conn: - links = conn.execute(sqlalchemy.text("SELECT link, expire_date FROM links WHERE owner = :owner"), [{"owner": api_key}]).fetchall() - response = [] - for link, expire_date in links: - response.append({"link": link, "expire_date": expire_date}) - return response - - -@app.post("/records") +""" +Return all records associated with an API key, no matter the link +""" +@app.get("/api/records") async def records(api_key: str = Security(check_api_key)): + """ + Get ALL IP logs records for every link tied to your API key + """ with engine.begin() as conn: records = conn.execute(sqlalchemy.text("SELECT timestamp, ip, location, browser, os, user_agent, isp FROM records WHERE owner = :owner"), [{"owner": api_key}]).fetchall() if not records: - return flask.jsonify('No records found'), 200 + return {"records": "No records are associated with this API key"} + + response = [] + for timestamp, ip, location, browser, os, user_agent, isp in records: + response.append({"timestamp": timestamp, "ip": ip, "location": location, "browser": browser, "os": os, "user_agent": user_agent, "isp": isp}) + + return response - return tabulate.tabulate(records, headers=['Timestamp', 'IP', 'Location', 'Browser', 'OS', 'User Agent', 'ISP']), 200 +@app.get("/{link}") +def link(link, request: Request): + ip = request.client.host + user_agent = request.headers.get("user-agent") + redirect_link = log(link, ip, user_agent) + return fastapi.responses.RedirectResponse(url=redirect_link) -# """ -# Return all records associated with an account, no matter the link -# """ -# @app.route('/records', methods=['POST']) -# @auth.login_required -# def records(): +""" +Return all links associated with an API key +""" +@app.get("/api/links") +async def links(api_key: str = Security(check_api_key)): + """ + Retrieve all links that are currently tied to your API key + """ + with engine.begin() as conn: + links = conn.execute(sqlalchemy.text("SELECT link, expire_date FROM links WHERE owner = :owner"), [{"owner": api_key}]).fetchall() + + if not links: + return {"links": "No links are associated with this API key"} + + response = [] + for link, expire_date in links: + response.append({"link": link, "expire_date": expire_date}) + return response -# @app.route('/<link>', methods=['GET']) -# def link(link): -# redirect_link = log(link, flask.request) -# return flask.redirect(redirect_link) +@app.post("/api/{link}/delete") +async def link_delete(link: str, api_key: str = Security(check_api_key)): + """ + Delete the specified link and all records associated with it + """ + data = delete_link(link, api_key) + if data == 404: + raise HTTPException( + status_code=fastapi.status.HTTP_404_NOT_FOUND, + detail="Link does not exist" + ) + if data == 401: + raise HTTPException( + status_code=fastapi.status.HTTP_401_UNAUTHORIZED, + detail="Link not associated with given API key" + ) + else: + return {"link": f"The link {data} has been deleted"} -# @app.route('/<link>/delete', methods=['POST']) -# @auth.login_required -# def link_delete(link): -# response = delete_link(link, auth.current_user()) -# return flask.jsonify(msg=response[0]), response[1] +@app.post("/api/{link}/renew") +async def link_renew(link: str, api_key: str = Security(check_api_key)): + """ + Renew a specifiec link (adds 7 more days from the current date) + """ + data = renew_link(link, api_key) + if data == 404: + raise HTTPException( + status_code=fastapi.status.HTTP_404_NOT_FOUND, + detail="Link does not exist" + ) + if data == 401: + raise HTTPException( + status_code=fastapi.status.HTTP_401_UNAUTHORIZED, + detail="Link not associated with given API key" + ) + else: + return {"link": f"The link {data[0]} has been renewed and will expire on {data[1]}"} -# @app.route('/<link>/renew', methods=['POST']) -# @auth.login_required -# def renew_link(link): -# response = renew_link(link, auth.current_user()) -# return flask.jsonify(msg=response[0]), response[1] +@app.get("/api/{link}/records") +async def link_records(link: str, api_key: str = Security(check_api_key)): + """ + Retrieve all IP log records for the specified link + """ + data = get_link_records(link, api_key) + if data == 404: + raise HTTPException( + status_code=fastapi.status.HTTP_404_NOT_FOUND, + detail="Link does not exist" + ) + if data == 401: + raise HTTPException( + status_code=fastapi.status.HTTP_401_UNAUTHORIZED, + detail="Link not associated with given API key" + ) + if data == 204: + raise HTTPException( + status_code=fastapi.status.HTTP_204_NO_CONTENT, + detail="No records found" + ) + else: + response = [] + for timestamp, ip, location, browser, os, user_agent, isp in data: + response.append({"timestamp": timestamp, "ip": ip, "location": location, "browser": browser, "os": os, "user_agent": user_agent, "isp": isp}) -# @app.route('/<link>/records', methods=['POST']) -# @auth.login_required -# def records_link(link): -# response = link_records(link, auth.current_user()) -# # If we jsonify the tabulate string it fucks it up, so we have to return -# # it normally, this check does that -# if response[0].startswith('Timestamp'): -# return response[0], response[1] -# else: -# return flask.jsonify(msg=response[0]), response[1] + return response -# @app.route('/<link>/delrecords', methods=['POST']) -# @auth.login_required -# def records_delete(link): -# response = del_link_records(link, auth.current_user()) -# return flask.jsonify(msg=response[0]), response[1]
\ No newline at end of file +@app.post("/api/{link}/delrecords") +async def link_delrecords(link: str, api_key: str = Security(check_api_key)): + """ + Delete all IP log records for the specified link + """ + data = delete_link_records(link, api_key) + if data == 404: + raise HTTPException( + status_code=fastapi.status.HTTP_404_NOT_FOUND, + detail="Link does not exist" + ) + if data == 401: + raise HTTPException( + status_code=fastapi.status.HTTP_401_UNAUTHORIZED, + detail="Link not associated with given API key" + ) + else: + return {"link": f"The records for link {data} have been deleted"}
\ No newline at end of file |