working on changing from flask -> fastapi
This commit is contained in:
parent
ec4c5f0c34
commit
a0bfa54406
@ -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
|
@ -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)
|
||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
))
|
))
|
||||||
|
@ -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 content_type == 'application/json':
|
|
||||||
try:
|
|
||||||
redirect_link = request.json['redirect_link']
|
|
||||||
except KeyError:
|
|
||||||
return 'Redirect link not provided', 400
|
|
||||||
|
|
||||||
if not validators.url(redirect_link):
|
if not validators.url(redirect_link):
|
||||||
return 'Redirect link is malformed. Please try again', 400
|
return None
|
||||||
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
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
147
app/routes.py
147
app/routes.py
@ -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]
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user