working on changing from flask -> fastapi

This commit is contained in:
Parker M. 2024-02-26 16:31:09 -06:00
parent ec4c5f0c34
commit a0bfa54406
No known key found for this signature in database
GPG Key ID: 95CD2E0C7E329F2A
7 changed files with 102 additions and 89 deletions

View File

@ -10,7 +10,7 @@ auth = HTTPTokenAuth(scheme='Bearer')
def verify_token(token): def verify_token(token):
try: try:
with engine.begin() as conn: with engine.begin() as conn:
token = conn.execute(sqlalchemy.text('SELECT * FROM accounts WHERE account_name = :account_name'), [{'account_name': token}]).fetchone() token = conn.execute(sqlalchemy.text('SELECT * FROM accounts WHERE api_key = :api_key'), [{'api_key': token}]).fetchone()
return token[0] return token[0]
except TypeError: except TypeError:
return False return False

View File

@ -13,7 +13,7 @@ def init_db():
conn.execute(sqlalchemy.text( conn.execute(sqlalchemy.text(
''' '''
CREATE TABLE IF NOT EXISTS accounts ( CREATE TABLE IF NOT EXISTS accounts (
account_name, PRIMARY KEY (account_name) api_key, PRIMARY KEY (api_key)
) )
''' '''
)) ))
@ -21,7 +21,7 @@ def init_db():
''' '''
CREATE TABLE IF NOT EXISTS links ( CREATE TABLE IF NOT EXISTS links (
owner, link, redirect_link, expire_date, owner, link, redirect_link, expire_date,
FOREIGN KEY (owner) REFERENCES accounts(account_name), PRIMARY KEY (link) FOREIGN KEY (owner) REFERENCES accounts(api_key), PRIMARY KEY (link)
) )
''' '''
)) ))

View File

@ -11,18 +11,9 @@ from db import engine
Generate and return a new randomized link that is connected to the user Generate and return a new randomized link that is connected to the user
Links are composed of 5 uppercase ASCII characters + numbers Links are composed of 5 uppercase ASCII characters + numbers
""" """
def generate_link(request, owner): def generate_link(redirect_link, owner):
content_type = request.headers.get('Content-Type') if not validators.url(redirect_link):
if content_type == 'application/json': return None
try:
redirect_link = request.json['redirect_link']
except KeyError:
return 'Redirect link not provided', 400
if not validators.url(redirect_link):
return 'Redirect link is malformed. Please try again', 400
else:
return 'Content-Type not supported', 400
with engine.begin() as conn: with engine.begin() as conn:
choices = string.ascii_uppercase + '1234567890' choices = string.ascii_uppercase + '1234567890'
@ -36,4 +27,4 @@ def generate_link(request, owner):
except exc.IntegrityError: except exc.IntegrityError:
continue continue
return link, 200 return link, expire_date

View File

@ -15,7 +15,7 @@ def generate_account():
while True: while True:
try: try:
account_string = ''.join(random.choices(string.ascii_uppercase, k=20)) account_string = ''.join(random.choices(string.ascii_uppercase, k=20))
conn.execute(sqlalchemy.text('INSERT INTO accounts(account_name) VALUES(:account_name)'), [{'account_name': account_string}]) conn.execute(sqlalchemy.text('INSERT INTO accounts(api_key) VALUES(:api_key)'), [{'api_key': account_string}])
conn.commit() conn.commit()
break break
except exc.IntegrityError: except exc.IntegrityError:

View File

@ -1,19 +1,19 @@
from routes import app
from db import init_db from db import init_db
import waitress
import threading import threading
import schedule import schedule
import time import time
import uvicorn
from func.remove_old_data import remove_old_data from func.remove_old_data import remove_old_data
if __name__ == '__main__': if __name__ == '__main__':
init_db() init_db()
thread = threading.Thread(target=waitress.serve, args=(app,), kwargs={'port': 5252}) thread = threading.Thread(target=uvicorn.run("routes:app", host='127.0.0.1', port='5252'))
thread.start() thread.start()
print('Server running on port 5252. Healthy.') print('Server running on port 5252. Healthy.')
schedule.every().day.at('00:01').do(remove_old_data) # schedule.every().day.at('00:01').do(remove_old_data)
while True: # while True:
schedule.run_pending() # schedule.run_pending()
time.sleep(1) # time.sleep(1)

View File

@ -1,5 +1,8 @@
import flask import fastapi
from fastapi import Security, HTTPException
from fastapi.security import APIKeyHeader
import tabulate import tabulate
import pydantic
import sqlalchemy import sqlalchemy
from db import engine from db import engine
@ -12,47 +15,57 @@ from func.renew_link import renew_link
from func.link_records import link_records from func.link_records import link_records
from func.del_link_records import del_link_records from func.del_link_records import del_link_records
class Newlink(pydantic.BaseModel):
redirect_link: str
app = flask.Flask(__name__) app = fastapi.FastAPI()
api_key_header = APIKeyHeader(name="X-API-Key")
@app.route('/signup', methods=['GET']) def check_api_key(api_key_header: str = Security(api_key_header)) -> str:
def signup():
account_name = generate_account()
return flask.jsonify({'account_name': account_name})
@app.route('/newlink', methods=['POST'])
@auth.login_required
def newlink():
response = generate_link(flask.request, auth.current_user())
return flask.jsonify(msg=response[0]), response[1]
"""
Return all links associated with an account
"""
@app.route('/links', methods=['POST'])
@auth.login_required
def links():
with engine.begin() as conn: with engine.begin() as conn:
links = conn.execute(sqlalchemy.text('SELECT link, expire_date FROM links WHERE owner = :owner'), [{'owner': auth.current_user()}]).fetchall() 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"
)
string = ""
i = 1 @app.get("/signup")
async def signup():
api_key = generate_account()
return {"api_key": api_key}
@app.post("/newlink")
async def newlink(newlink: Newlink, api_key: str = Security(check_api_key)):
data = generate_link(newlink.redirect_link, api_key)
if data:
return {"link": data[0], "expire_date": data[1]}
else:
raise HTTPException(
status_code=fastapi.status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Malformed redirect link provided"
)
@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: for link, expire_date in links:
string += f"{i}. {link} - Expires on {expire_date}\n" response.append({"link": link, "expire_date": expire_date})
i += 1 return response
return string
""" @app.post("/records")
Return all records associated with an account, no matter the link async def records(api_key: str = Security(check_api_key)):
"""
@app.route('/records', methods=['POST'])
@auth.login_required
def records():
with engine.begin() as conn: 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': auth.current_user()}]).fetchall() 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: if not records:
return flask.jsonify('No records found'), 200 return flask.jsonify('No records found'), 200
@ -60,40 +73,48 @@ def records():
return tabulate.tabulate(records, headers=['Timestamp', 'IP', 'Location', 'Browser', 'OS', 'User Agent', 'ISP']), 200 return tabulate.tabulate(records, headers=['Timestamp', 'IP', 'Location', 'Browser', 'OS', 'User Agent', 'ISP']), 200
@app.route('/<link>', methods=['GET']) # """
def link(link): # Return all records associated with an account, no matter the link
redirect_link = log(link, flask.request) # """
return flask.redirect(redirect_link) # @app.route('/records', methods=['POST'])
# @auth.login_required
# def records():
@app.route('/<link>/delete', methods=['POST']) # @app.route('/<link>', methods=['GET'])
@auth.login_required # def link(link):
def link_delete(link): # redirect_link = log(link, flask.request)
response = delete_link(link, auth.current_user()) # return flask.redirect(redirect_link)
return flask.jsonify(msg=response[0]), response[1]
@app.route('/<link>/renew', methods=['POST']) # @app.route('/<link>/delete', methods=['POST'])
@auth.login_required # @auth.login_required
def renew_link(link): # def link_delete(link):
response = renew_link(link, auth.current_user()) # response = delete_link(link, auth.current_user())
return flask.jsonify(msg=response[0]), response[1] # return flask.jsonify(msg=response[0]), response[1]
@app.route('/<link>/records', methods=['POST']) # @app.route('/<link>/renew', methods=['POST'])
@auth.login_required # @auth.login_required
def records_link(link): # def renew_link(link):
response = link_records(link, auth.current_user()) # response = renew_link(link, auth.current_user())
# If we jsonify the tabulate string it fucks it up, so we have to return # return flask.jsonify(msg=response[0]), response[1]
# 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]
@app.route('/<link>/delrecords', methods=['POST']) # @app.route('/<link>/records', methods=['POST'])
@auth.login_required # @auth.login_required
def records_delete(link): # def records_link(link):
response = del_link_records(link, auth.current_user()) # response = link_records(link, auth.current_user())
return flask.jsonify(msg=response[0]), response[1] # # 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]
# @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]

View File

@ -1,6 +1,5 @@
Flask==3.0.0 Flask==3.0.0
Flask-HTTPAuth==4.8.0 Flask-HTTPAuth==4.8.0
waitress==2.1.2
ip2location-io==1.0.0 ip2location-io==1.0.0
python-dotenv==1.0.0 python-dotenv==1.0.0
SQLAlchemy==2.0.27 SQLAlchemy==2.0.27
@ -8,3 +7,5 @@ tabulate==0.9.0
ua-parser==0.18.0 ua-parser==0.18.0
validators==0.22.0 validators==0.22.0
schedule==1.2.1 schedule==1.2.1
# uvicorn, fastapi, pydantic