Moved frontend out of webserver into it's own container
This commit is contained in:
32
web_server/blueprints/__init__.py
Normal file
32
web_server/blueprints/__init__.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from flask import Flask
|
||||
from flask_session import Session
|
||||
from blueprints.utils import logged_in_user
|
||||
from flask_cors import CORS
|
||||
import os
|
||||
|
||||
print("Environment variables:")
|
||||
print(f"FLASK_SECRET_KEY: {os.getenv('FLASK_SECRET_KEY')}")
|
||||
print(f"STRIPE_SECRET_KEY: {os.getenv('STRIPE_SECRET_KEY')}")
|
||||
|
||||
|
||||
def create_app():
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = os.getenv("FLASK_SECRET_KEY")
|
||||
app.config["SESSION_PERMANENT"] = False
|
||||
app.config["SESSION_TYPE"] = "filesystem"
|
||||
#! ↓↓↓ For development purposes only
|
||||
CORS(app) # Allow cross-origin requests for the frontend
|
||||
|
||||
Session(app)
|
||||
app.before_request(logged_in_user)
|
||||
|
||||
with app.app_context():
|
||||
from blueprints.authentication import auth_bp
|
||||
from blueprints.main import main_bp
|
||||
from blueprints.stripe import stripe_bp
|
||||
|
||||
app.register_blueprint(auth_bp)
|
||||
app.register_blueprint(main_bp)
|
||||
app.register_blueprint(stripe_bp)
|
||||
|
||||
return app
|
||||
92
web_server/blueprints/authentication.py
Normal file
92
web_server/blueprints/authentication.py
Normal file
@@ -0,0 +1,92 @@
|
||||
from flask import Blueprint, render_template, session, request, url_for, redirect, g
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from forms import SignupForm, LoginForm
|
||||
from database.database import Database
|
||||
from blueprints.utils import login_required
|
||||
|
||||
auth_bp = Blueprint("auth", __name__)
|
||||
|
||||
@auth_bp.route("/signup", methods=["GET", "POST"])
|
||||
def signup():
|
||||
form = SignupForm()
|
||||
if form.validate_on_submit():
|
||||
# Retrieve data from the sign up form
|
||||
username = form.username.data
|
||||
email = form.email.data
|
||||
password = form.password.data
|
||||
password2 = form.password2.data
|
||||
|
||||
# Store in database and hash to avoid exposing sensitive information
|
||||
db = Database()
|
||||
cursor = db.create_connection()
|
||||
|
||||
# Check if user already exists to avoid duplicates
|
||||
dup_email = cursor.execute("""SELECT * FROM users
|
||||
WHERE email = ?;""", (email,)).fetchone()
|
||||
dup_username = cursor.execute("""SELECT * FROM users
|
||||
WHERE username = ?;""", (username,)).fetchone()
|
||||
|
||||
if dup_email is not None:
|
||||
form.email.errors.append("Email already taken.")
|
||||
elif dup_username is not None:
|
||||
form.username.errors.append("Username already taken.")
|
||||
elif password != password2:
|
||||
form.password.errors.append("Passwords must match.")
|
||||
else:
|
||||
cursor.execute("""INSERT INTO users (username, password, email, num_followers, isPartenered, bio)
|
||||
VALUES (?, ?, ?, ?, ?, ?);""", (username, generate_password_hash(password), email, 0, 0, "This user does not have a Bio."))
|
||||
db.commit_data()
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
|
||||
# Close connection to prevent data leaks
|
||||
db.close_connection()
|
||||
|
||||
return render_template("signup.html", form=form)
|
||||
|
||||
@auth_bp.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
# Retrieve data from the login form
|
||||
username = form.username.data
|
||||
password = form.username.data
|
||||
|
||||
# Compare with database
|
||||
db = Database()
|
||||
cursor = db.create_connection()
|
||||
|
||||
# Check if user exists so only users who have signed up can login
|
||||
user_exists = cursor.execute("""SELECT * FROM users
|
||||
WHERE username = ?;""", (username,)).fetchone()
|
||||
|
||||
if not user_exists:
|
||||
form.username.errors.append("Incorrect username or password.")
|
||||
db.close_connection()
|
||||
|
||||
# Check is hashed passwords match to verify the user logging in
|
||||
elif not check_password_hash(user_exists["password"], password):
|
||||
form.username.errors.append("Incorrect username or password.")
|
||||
db.close_connection()
|
||||
|
||||
else:
|
||||
# Create a new session to prevent users from exploiting horizontal access control
|
||||
session.clear()
|
||||
session["username"] = username
|
||||
|
||||
# Return to previous page if applicable
|
||||
next_page = request.args.get("next")
|
||||
|
||||
# Otherwise return home
|
||||
if not next_page:
|
||||
next_page = url_for("app.index")
|
||||
db.close_connection()
|
||||
return redirect(next_page)
|
||||
|
||||
return render_template("login.html", form=form)
|
||||
|
||||
@auth_bp.route("/logout")
|
||||
@login_required
|
||||
def logout():
|
||||
session.clear()
|
||||
return redirect(url_for("index"))
|
||||
78
web_server/blueprints/main.py
Normal file
78
web_server/blueprints/main.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from flask import Blueprint, render_template
|
||||
|
||||
main_bp = Blueprint("app", __name__)
|
||||
|
||||
## temp, showcasing HLS
|
||||
@main_bp.route('/hls1/<stream_id>')
|
||||
def hls(stream_id):
|
||||
stream_url = f"http://127.0.0.1:8080/hls/{stream_id}/index.m3u8"
|
||||
return render_template("video.html", video_url=stream_url)
|
||||
#--------------------------------------------------------
|
||||
|
||||
|
||||
@main_bp.route('/get_loggedin_status')
|
||||
def get_loggedin_status():
|
||||
logged_in = False
|
||||
"""
|
||||
Returns whether the user is logged in or not
|
||||
"""
|
||||
return {"logged_in": logged_in}
|
||||
|
||||
@main_bp.route('/authenticate_user')
|
||||
def authenticate_user():
|
||||
"""
|
||||
Authenticates the user
|
||||
"""
|
||||
return {"authenticated": True}
|
||||
|
||||
|
||||
@main_bp.route('/get_streams')
|
||||
def get_sample_streams():
|
||||
"""
|
||||
Returns a list of (sample) streamers live right now
|
||||
"""
|
||||
|
||||
# top 25, if not logged in
|
||||
# if logged in, show streams that match user's tags
|
||||
# user attains tags from the tags of the streamers they follow, and streamers they've watched
|
||||
|
||||
streamers = [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Gaming Stream",
|
||||
"streamer": "Gamer123",
|
||||
"viewers": 1500,
|
||||
"thumbnail": "dance_game.png",
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Art Stream",
|
||||
"streamer": "Artist456",
|
||||
"viewers": 800,
|
||||
"thumbnail": "surface.jpeg",
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Music Stream",
|
||||
"streamer": "Musician789",
|
||||
"viewers": 2000,
|
||||
"thumbnail": "monkey.png",
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Just Chatting",
|
||||
"streamer": "Chatty101",
|
||||
"viewers": 1200,
|
||||
"thumbnail": "elf.webp",
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "Cooking Stream",
|
||||
"streamer": "Chef202",
|
||||
"viewers": 1000,
|
||||
"thumbnail": "art.jpg",
|
||||
}
|
||||
]
|
||||
return streamers
|
||||
|
||||
#TODO Route for saving uploaded thumbnails to database, serving these images to the frontend upon request: →→→ @main_bp.route('/images/<path:filename>') \n def serve_image(filename): ←←←
|
||||
34
web_server/blueprints/stripe.py
Normal file
34
web_server/blueprints/stripe.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
import os, stripe
|
||||
|
||||
stripe_bp = Blueprint("stripe", __name__)
|
||||
|
||||
stripe.api_key = os.getenv("STRIPE_SECRET_KEY")
|
||||
|
||||
@stripe_bp.route('/create-checkout-session', methods=['POST'])
|
||||
def create_checkout_session():
|
||||
print("Creating checkout session")
|
||||
try:
|
||||
session = stripe.checkout.Session.create(
|
||||
ui_mode = 'embedded',
|
||||
payment_method_types=['card'],
|
||||
line_items=[
|
||||
{
|
||||
'price': 'price_1QikNCGk6yuk3uA86mZf3dmM', #Subscription ID
|
||||
'quantity': 1,
|
||||
},
|
||||
],
|
||||
mode='subscription',
|
||||
redirect_on_completion = 'never'
|
||||
)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return str(e)
|
||||
|
||||
return jsonify(clientSecret=session.client_secret)
|
||||
|
||||
@stripe_bp.route('/session-status', methods=['GET']) # check for payment status
|
||||
def session_status():
|
||||
session = stripe.checkout.Session.retrieve(request.args.get('session_id'))
|
||||
|
||||
return jsonify(status=session.status, customer_email=session.customer_details.email)
|
||||
27
web_server/blueprints/templates/video.html
Normal file
27
web_server/blueprints/templates/video.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
|
||||
<video id="video" controls></video>
|
||||
<script>
|
||||
if(Hls.isSupported())
|
||||
{
|
||||
var video = document.getElementById('video');
|
||||
var hls = new Hls();
|
||||
hls.loadSource('{{ video_url }}');
|
||||
hls.attachMedia(video);
|
||||
hls.on(Hls.Events.MANIFEST_PARSED,function()
|
||||
{
|
||||
video.play();
|
||||
});
|
||||
}
|
||||
else if (video.canPlayType('application/vnd.apple.mpegurl'))
|
||||
{
|
||||
video.src = ' {{ video_url }}';
|
||||
video.addEventListener('canplay',function()
|
||||
{
|
||||
video.play();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
24
web_server/blueprints/utils.py
Normal file
24
web_server/blueprints/utils.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from flask import redirect, url_for, request, g, session
|
||||
from functools import wraps
|
||||
|
||||
def logged_in_user():
|
||||
g.user = session.get("username", None)
|
||||
g.admin = session.get("username", None)
|
||||
|
||||
def login_required(view):
|
||||
"""add at start of routes where users need to be logged in to access"""
|
||||
@wraps(view)
|
||||
def wrapped_view(*args, **kwargs):
|
||||
if g.user is None:
|
||||
return redirect(url_for("login", next=request.url))
|
||||
return view(*args, **kwargs)
|
||||
return wrapped_view
|
||||
|
||||
def admin_required(view):
|
||||
"""add at start of routes where admins need to be logged in to access"""
|
||||
@wraps(view)
|
||||
def wrapped_view(*args, **kwargs):
|
||||
if g.admin != "admin":
|
||||
return redirect(url_for("login", next=request.url))
|
||||
return view(*args, **kwargs)
|
||||
return wrapped_view
|
||||
Reference in New Issue
Block a user