built ability to create a character
This commit is contained in:
@@ -1,15 +1,22 @@
|
||||
import os
|
||||
from flask import Flask, redirect, url_for, request, g, session, flash
|
||||
from .blueprints.auth.routes import auth_bp
|
||||
from .blueprints.main.routes import main_bp
|
||||
from .blueprints.public.routes import public_bp
|
||||
|
||||
# import blueprints
|
||||
from app.blueprints.auth import auth_bp
|
||||
from app.blueprints.main import main_bp
|
||||
from app.blueprints.char import char_bp
|
||||
from app.blueprints.public import public_bp
|
||||
from app.blueprints.ajax import ajax_bp
|
||||
|
||||
# load_dotenv()
|
||||
from .utils.settings import get_settings
|
||||
from app.utils.logging import get_logger
|
||||
from .utils.session_user import SessionUser
|
||||
|
||||
logger = get_logger()
|
||||
settings = get_settings()
|
||||
|
||||
|
||||
def create_app():
|
||||
app = Flask(__name__, template_folder="templates")
|
||||
app.config.update(
|
||||
@@ -25,7 +32,9 @@ def create_app():
|
||||
# Blueprints
|
||||
app.register_blueprint(auth_bp)
|
||||
app.register_blueprint(main_bp)
|
||||
app.register_blueprint(char_bp)
|
||||
app.register_blueprint(public_bp)
|
||||
app.register_blueprint(ajax_bp)
|
||||
|
||||
@app.before_request
|
||||
def require_login():
|
||||
@@ -68,7 +77,6 @@ def create_app():
|
||||
@app.before_request
|
||||
def load_user():
|
||||
user_data = session.get("user")
|
||||
print(user_data)
|
||||
|
||||
if user_data:
|
||||
g.current_user = SessionUser(
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
# app/auth/routes.py
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash, session,make_response
|
||||
from flask_login import login_user, logout_user, login_required
|
||||
|
||||
from app.services.appwrite_client import AppWriteClient
|
||||
|
||||
|
||||
auth_bp = Blueprint("auth", __name__, url_prefix="/auth")
|
||||
|
||||
|
||||
@auth_bp.route("/register", methods=["GET", "POST"])
|
||||
def register():
|
||||
if request.method == "POST":
|
||||
email = request.form.get("email", "").strip()
|
||||
password = request.form.get("password", "")
|
||||
name = (request.form.get("name") or "").strip() or None
|
||||
|
||||
if not email or not password:
|
||||
flash("Email and password are required.", "error")
|
||||
return redirect(url_for("auth.register"))
|
||||
|
||||
try:
|
||||
aw = AppWriteClient()
|
||||
aw.create_new_user(email,password,name)
|
||||
|
||||
login_valid, error = aw.log_user_in(email,password)
|
||||
if login_valid:
|
||||
flash("Account created and you are now logged in.", "success")
|
||||
return redirect(url_for("main.dashboard"))
|
||||
else:
|
||||
flash(str(error), "error")
|
||||
except Exception as e:
|
||||
flash(str(e), "error")
|
||||
return redirect(url_for("auth.register"))
|
||||
|
||||
return render_template("auth/register.html")
|
||||
|
||||
@auth_bp.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if request.method == "POST":
|
||||
email = request.form.get("email", "").strip()
|
||||
password = request.form.get("password", "")
|
||||
if not email or not password:
|
||||
flash("Email and password are required.", "error")
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
aw = AppWriteClient()
|
||||
login_valid, error = aw.log_user_in(email,password)
|
||||
try:
|
||||
if login_valid:
|
||||
username = session.get("user",{}).get("name","User")
|
||||
flash(f"Welcome Back {username}", "success")
|
||||
return redirect(url_for("main.dashboard"))
|
||||
else:
|
||||
flash(str(error), "error")
|
||||
except Exception as e:
|
||||
flash(str(e), "error")
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
# Get method
|
||||
|
||||
return render_template("auth/login.html")
|
||||
|
||||
@auth_bp.route("/logout", methods=["GET", "POST"])
|
||||
def logout():
|
||||
aw = AppWriteClient()
|
||||
aw.log_user_out()
|
||||
session.clear()
|
||||
flash("Signed out.", "success")
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
@auth_bp.route("/send", methods=["POST"])
|
||||
def send():
|
||||
"""
|
||||
Sends a verification email to the currently logged-in user.
|
||||
Appwrite will redirect the user back to /verify/callback with userId & secret.
|
||||
"""
|
||||
try:
|
||||
aw = AppWriteClient()
|
||||
aw.send_email_verification()
|
||||
flash("Verification email sent. Please check your inbox.", "info")
|
||||
except Exception as e:
|
||||
flash(f"Could not send verification email: {e}", "error")
|
||||
# Go back to where the user came from, or your dashboard
|
||||
return redirect(request.referrer or url_for("main.dashboard"))
|
||||
|
||||
@auth_bp.route("/callback", methods=["GET"])
|
||||
def callback():
|
||||
"""
|
||||
Completes verification after user clicks the email link.
|
||||
Requires the user to be logged in (Appwrite Account endpoints need a session).
|
||||
If not logged in, we stash the link params and send them to log in first.
|
||||
"""
|
||||
aw = AppWriteClient()
|
||||
user_id = request.args.get("userId")
|
||||
secret = request.args.get("secret")
|
||||
if not user_id or not secret:
|
||||
flash("Invalid verification link.", "error")
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
try:
|
||||
# If we don't currently have an Appwrite session, ask them to log in, then resume.
|
||||
if not aw.verify_email(user_id,secret):
|
||||
session["pending_verification"] = {"userId": user_id, "secret": secret}
|
||||
flash("Please log in to complete email verification.", "warning")
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
# We have a session; complete verification
|
||||
flash("Email verified! You're all set.", "success")
|
||||
return redirect(url_for("main.dashboard"))
|
||||
except Exception as e:
|
||||
flash(f"Verification failed: {e}", "error")
|
||||
return redirect(url_for("auth.login"))
|
||||
@@ -1,10 +0,0 @@
|
||||
from flask import Blueprint, redirect, url_for, render_template, session,flash
|
||||
from app.services.appwrite_client import AppWriteClient
|
||||
|
||||
aw = AppWriteClient()
|
||||
main_bp = Blueprint("main", __name__, url_prefix="/main")
|
||||
|
||||
|
||||
@main_bp.route("/dashboard")
|
||||
def dashboard():
|
||||
return render_template("main/dashboard.html", profile="", jwt_info="")
|
||||
@@ -1,10 +0,0 @@
|
||||
from flask import Blueprint, redirect, url_for, render_template, session,flash
|
||||
from app.services.appwrite_client import AppWriteClient
|
||||
|
||||
|
||||
public_bp = Blueprint("public", __name__, url_prefix="/")
|
||||
|
||||
|
||||
@public_bp.route("/")
|
||||
def home():
|
||||
return render_template("public/home.html")
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import os
|
||||
from typing import Optional, Dict, Any, Mapping, Union, List
|
||||
|
||||
from flask import session, redirect, url_for
|
||||
from flask import session, redirect, url_for, request
|
||||
from appwrite.client import Client
|
||||
from appwrite.services.account import Account
|
||||
from appwrite.id import ID
|
||||
@@ -60,6 +60,7 @@ class AppWriteClient:
|
||||
client = (Client()
|
||||
.set_endpoint(ENDPOINT)
|
||||
.set_project(PROJECT_ID)
|
||||
.set_forwarded_user_agent(request.headers.get('user-agent'))
|
||||
)
|
||||
|
||||
if session[self.session_key] is not None:
|
||||
@@ -82,6 +83,25 @@ class AppWriteClient:
|
||||
user = user_account.get()
|
||||
session['user']=user
|
||||
|
||||
def get_user_from_jwt_token(self, jwt_token:str):
|
||||
try:
|
||||
client = (Client()
|
||||
.set_endpoint(ENDPOINT)
|
||||
.set_project(PROJECT_ID)
|
||||
.set_jwt(jwt_token)
|
||||
)
|
||||
return Account(client).get()
|
||||
except Exception as e:
|
||||
return {}
|
||||
|
||||
def mint_jwt(self):
|
||||
try:
|
||||
client = self._get_user_client()
|
||||
account = Account(client)
|
||||
return account.create_jwt()
|
||||
except Exception as e:
|
||||
return ""
|
||||
|
||||
def log_user_in(self, email:str,password:str):
|
||||
admin_client = self._get_admin_client()
|
||||
try:
|
||||
|
||||
@@ -29,11 +29,10 @@
|
||||
<p class="mb-0"><span class="version">v 0.1.0</span></p>
|
||||
</footer>
|
||||
|
||||
<!-- App Write JS Client -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/appwrite@17.0.0"></script>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha256-CDOy6cOibCWEdsRiZuaHf8dSGGJRYuBGC+mjoJimHGw=" crossorigin="anonymous"></script>
|
||||
|
||||
{% include "_flash_sticky.html" %}
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha256-CDOy6cOibCWEdsRiZuaHf8dSGGJRYuBGC+mjoJimHGw=" crossorigin="anonymous"></script>
|
||||
<!-- <script src="/static/halfmoon/halfmoon-1.1.1.min.js"></script> -->
|
||||
|
||||
{% include "_flash_sticky.html" %}
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
<h1 class="mb-0">
|
||||
Code of Conquest Dashboard
|
||||
</h1>
|
||||
<p class="mb-0"></p>
|
||||
<img src="{{ url_for('static', filename='images/COC_Logo.png') }}" alt="logo" width="300" height="300">
|
||||
<p class="mb-0">
|
||||
{{jwt_info}}
|
||||
{{profile}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -5,8 +5,9 @@
|
||||
<h5 class="card-title mb-4">
|
||||
<i class="fa-solid fa-right-to-bracket me-2"></i> Welcome to Code of Conquest
|
||||
</h5>
|
||||
|
||||
<img src="{{ url_for('static', filename='images/COC_Logo.png') }}" alt="logo" width="300" height="300"><br />
|
||||
<p style="text-align: justify;">
|
||||
|
||||
In the world of Code of Conquest, the line between hero and villain blurs as you embark on a legendary adventure.
|
||||
This immersive game drops you into a realm of wonder and danger, where every decision, every action, and every
|
||||
roll of the dice determines the fate of your character.<br /><br />
|
||||
|
||||
@@ -85,7 +85,7 @@ def configure_logging(settings=None) -> None:
|
||||
return
|
||||
|
||||
if settings is None:
|
||||
from app.core.utils.settings import get_settings # lazy import
|
||||
from app.utils.settings import get_settings # lazy import
|
||||
settings = get_settings()
|
||||
|
||||
env = settings.env.value
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import time
|
||||
from flask import session
|
||||
from ..services.appwrite_client import AppwriteAccountClient
|
||||
|
||||
def ensure_fresh_appwrite_jwt(skew_seconds: int = 120) -> str:
|
||||
"""
|
||||
Returns a valid Appwrite JWT, refreshing it if it's missing or expiring soon.
|
||||
Relies on the saved Appwrite session cookie in Flask's session.
|
||||
"""
|
||||
jwt_info = session.get("appwrite_jwt")
|
||||
now = int(time.time())
|
||||
|
||||
if jwt_info and isinstance(jwt_info, dict):
|
||||
exp = int(jwt_info.get("expire", 0))
|
||||
# If token still safely valid, reuse it
|
||||
if exp - now > skew_seconds and "jwt" in jwt_info:
|
||||
return jwt_info["jwt"]
|
||||
|
||||
# Need to mint a new JWT using the user's Appwrite session cookie
|
||||
cookies = session.get("appwrite_cookies")
|
||||
if not cookies:
|
||||
raise RuntimeError("Missing Appwrite session; user must sign in again.")
|
||||
|
||||
aw = AppwriteAccountClient(cookies=cookies)
|
||||
new_jwt = aw.create_jwt() # -> {"jwt": "...", "expire": <unix>}
|
||||
session["appwrite_jwt"] = new_jwt
|
||||
return new_jwt["jwt"]
|
||||
Reference in New Issue
Block a user