-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from Strong-AI-Lab/JVNAUTOSCI-111-Implement-a-…
…web-front-end-for-Von-suitable-for-local-or-server-use JVNAUTOSCI-111-Implement-a-web-front-end-for-Von-suitable-for-local-or-server-use
- Loading branch information
Showing
20 changed files
with
493 additions
and
20 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
from flask import Flask, render_template, redirect, url_for, request, flash | ||
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user | ||
|
||
from werkzeug.security import generate_password_hash, check_password_hash | ||
from bson.objectid import ObjectId | ||
import re | ||
|
||
from pymongo import MongoClient | ||
from flask_pymongo import PyMongo #needed? | ||
import argparse | ||
import os | ||
from web_interface.user_data import VonUser # work our why it doesn't like this import when it's in the same directory | ||
|
||
|
||
#For details, see https://naoinstitute.atlassian.net/browse/JVNAUTOSCI-111 | ||
# write a minimal local web page server, that includes login and identity tracking, and | ||
# is easy to redeploy on a remote server (e.g. one running on aws or google cloud or Azure). | ||
# I want to be able to easily call python backend code from the server. | ||
# Make sure the start code for the local server has an option to run in foreground or background. | ||
app = Flask(__name__) | ||
app.secret_key = os.getenv("VON_APP_SECRET_KEY") # Replace with a secure secret key in production | ||
|
||
# Configure Flask-Login | ||
login_manager = LoginManager() | ||
login_manager.init_app(app) | ||
login_manager.login_view = 'login' | ||
|
||
# User loader callback | ||
@login_manager.user_loader | ||
def load_user(user_id): | ||
user = VonUser.find_by_id(user_id) | ||
if user: | ||
return User(user.get_username()) | ||
return None | ||
|
||
# User class | ||
class User(UserMixin): | ||
def __init__(self, username): | ||
self.vonuser = VonUser(username) | ||
self.username = username | ||
self.id = self.vonuser.get_id() | ||
#str(mongo.db.users.find_one({"username": username})['_id']) | ||
|
||
# Routes | ||
@app.route('/') | ||
def home(): | ||
return render_template('home.html') | ||
|
||
@app.route('/login', methods=['GET', 'POST']) | ||
def login(): | ||
if request.method == 'POST': | ||
username = request.form['username'] | ||
password = request.form['password'] | ||
hpass=generate_password_hash(password, method='pbkdf2:sha256') | ||
|
||
# Verify username and password | ||
user = VonUser.find_by_username(username) | ||
if user and check_password_hash(hpass,password): # In production, use hashed passwords | ||
login_user(User(username)) | ||
return redirect(url_for('dashboard')) | ||
else: | ||
flash('Login Unsuccessful. Please try again or signup.', 'error') | ||
return redirect(url_for('login')) | ||
#return 'Invalid credentials', 401 | ||
|
||
return render_template('login.html') | ||
|
||
@app.route('/signup', methods=['GET', 'POST']) | ||
def signup(): | ||
if request.method == 'POST': | ||
# Get form data | ||
username = request.form['username'] | ||
email = request.form['email'] | ||
password = request.form['password'] | ||
confirm_password = request.form['confirm_password'] | ||
|
||
# Validate form data | ||
if not username or not email or not password or not confirm_password: | ||
flash('Please fill out all fields.', 'error') | ||
return redirect(url_for('signup')) | ||
|
||
if password != confirm_password: | ||
flash('Passwords do not match.', 'error') | ||
return redirect(url_for('signup')) | ||
|
||
existing_user = VonUser.find_by_username(username) | ||
# Check if user already exists | ||
if existing_user and username == existing_user.get_username(): | ||
flash('Username already exists.', 'error') | ||
return redirect(url_for('signup')) | ||
|
||
#Validate email format | ||
email_regex = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$' | ||
if not re.match(email_regex, email): | ||
flash('Invalid email format.', 'error') | ||
return redirect(url_for('signup')) | ||
|
||
hpass=generate_password_hash(password, method='pbkdf2:sha256') | ||
newUser=VonUser.create_user(username, email, hpass) #create_user is a class method | ||
if not newUser: | ||
flash('Error creating user.', 'error') | ||
return redirect(url_for('signup')) | ||
|
||
|
||
flash('Registration successful. Please log in.', 'success') | ||
return redirect(url_for('login')) | ||
|
||
return render_template('signup.html') | ||
|
||
|
||
@app.route('/dashboard') | ||
@login_required | ||
def dashboard(): | ||
return render_template('dashboard.html', user=current_user.username) | ||
|
||
@app.route('/logout') | ||
@login_required | ||
def logout(): | ||
logout_user() | ||
return redirect(url_for('home')) | ||
|
||
# Main function | ||
if __name__ == '__main__': | ||
parser = argparse.ArgumentParser(description='Run the Flask web server.') | ||
parser.add_argument('--host', default='127.0.0.1', help='Host to listen on.') | ||
parser.add_argument('--port', default=5000, type=int, help='Port to listen on.') | ||
parser.add_argument('--background', action='store_true', help='Run server in the background.') | ||
args = parser.parse_args() | ||
|
||
if args.background: | ||
from multiprocessing import Process | ||
|
||
|
||
def run_app(): | ||
app.run(host=args.host, port=args.port) | ||
|
||
p = Process(target=run_app) | ||
p.start() | ||
print(f"Server running in background on {args.host}:{args.port} (PID: {p.pid})") | ||
else: | ||
app.run(host=args.host, port=args.port) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Dashboard</title> | ||
</head> | ||
<body> | ||
<h1>Dashboard</h1> | ||
<p>Welcome, {{ user }}!</p> | ||
<p><a href="{{ url_for('logout') }}">Logout</a></p> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Von</title> | ||
</head> | ||
<body> | ||
<h1>Welcome to Von</h1> | ||
{% if current_user.is_authenticated %} | ||
<p>Hello, {{ current_user.username }}!</p> | ||
<p><a href="{{ url_for('dashboard') }}">Go to Dashboard</a></p> | ||
<p><a href="{{ url_for('logout') }}">Logout</a></p> | ||
{% else %} | ||
<p><a href="{{ url_for('login') }}">Login</a></p> | ||
{% endif %} | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Login</title> | ||
</head> | ||
<body> | ||
<h1>Login</h1> | ||
<!-- Display flash messages --> | ||
{% with messages = get_flashed_messages(with_categories=true) %} | ||
{% if messages %} | ||
<ul> | ||
{% for category, message in messages %} | ||
<li style="color: {% if category == 'error' %}red{% else %}green{% endif %};">{{ message }}</li> | ||
{% endfor %} | ||
</ul> | ||
{% endif %} | ||
{% endwith %} | ||
<!-- Login form --> | ||
<form action="{{ url_for('login') }}" method="post"> | ||
<label for="username">Username:</label><br> | ||
<input type="text" name="username" id="username" required autofocus><br><br> | ||
|
||
<label for="password">Password:</label><br> | ||
<input type="password" name="password" id="password" required><br><br> | ||
|
||
<button type="submit">Login</button> | ||
</form> | ||
<p>Don't have an account? <a href="{{ url_for('signup') }}">Sign up here</a>.</p> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Signup</title> | ||
</head> | ||
<body> | ||
<h1>Sign Up</h1> | ||
<!-- Display flash messages --> | ||
{% with messages = get_flashed_messages(with_categories=true) %} | ||
{% if messages %} | ||
<ul> | ||
{% for category, message in messages %} | ||
<li style="color: {% if category == 'error' %}red{% else %}green{% endif %};">{{ message }}</li> | ||
{% endfor %} | ||
</ul> | ||
{% endif %} | ||
{% endwith %} | ||
<!-- Signup form --> | ||
<form action="{{ url_for('signup') }}" method="post"> | ||
<label for="username">Username:</label><br> | ||
<input type="text" name="username" id="username" required autofocus><br><br> | ||
|
||
<label for="email">Email:</label><br> | ||
<input type="text" name="email" id="email" required><br><br> | ||
|
||
<label for="password">Password:</label><br> | ||
<input type="password" name="password" id="password" required><br><br> | ||
|
||
<label for="confirm_password">Confirm Password:</label><br> | ||
<input type="password" name="confirm_password" id="confirm_password" required><br><br> | ||
|
||
<button type="submit">Register</button> | ||
</form> | ||
<p>Already have an account? <a href="{{ url_for('login') }}">Log in here</a>.</p> | ||
</body> | ||
</html> |
Oops, something went wrong.