Moved authentification code into js/auth.js

This commit is contained in:
Josh-Dev-Quest 2026-03-28 13:36:17 +01:00
parent fec4f513c8
commit e3724a4842
No known key found for this signature in database
8 changed files with 330 additions and 364 deletions

View File

@ -6,109 +6,120 @@ import os
from datetime import datetime
app = Flask(__name__)
app.secret_key = 'your-secret-key-here-change-in-production' # needed for sessions
app.secret_key = "your-secret-key-here-change-in-production" # needed for sessions
CORS(app, supports_credentials=True) # allow cookies
# Directories
DATA_DIR = 'data'
USERS_FILE = os.path.join(DATA_DIR, 'users.json')
DATA_DIR = "data"
USERS_FILE = os.path.join(DATA_DIR, "users.json")
os.makedirs(DATA_DIR, exist_ok=True)
# ==================== User helpers ====================
def load_users():
try:
if os.path.exists(USERS_FILE):
with open(USERS_FILE, 'r') as f:
with open(USERS_FILE, "r") as f:
return json.load(f)
except Exception as e:
print(f"Error loading users: {e}")
return []
def save_users(users):
try:
with open(USERS_FILE, 'w') as f:
with open(USERS_FILE, "w") as f:
json.dump(users, f, indent=2)
except Exception as e:
print(f"Error saving users: {e}")
def get_next_user_id(users):
if not users:
return 1
return max(u['id'] for u in users) + 1
return max(u["id"] for u in users) + 1
def get_user_by_username(username):
users = load_users()
return next((u for u in users if u['username'] == username), None)
return next((u for u in users if u["username"] == username), None)
def get_user_by_id(user_id):
users = load_users()
return next((u for u in users if u['id'] == user_id), None)
return next((u for u in users if u["id"] == user_id), None)
# ==================== Peruser data helpers ====================
def get_user_data_dir(user_id):
user_dir = os.path.join(DATA_DIR, 'users', str(user_id))
user_dir = os.path.join(DATA_DIR, "users", str(user_id))
os.makedirs(user_dir, exist_ok=True)
return user_dir
def load_user_journeys(user_id):
file_path = os.path.join(get_user_data_dir(user_id), 'journeys.json')
file_path = os.path.join(get_user_data_dir(user_id), "journeys.json")
try:
if os.path.exists(file_path):
with open(file_path, 'r') as f:
with open(file_path, "r") as f:
return json.load(f)
except Exception as e:
print(f"Error loading journeys for user {user_id}: {e}")
return []
def save_user_journeys(user_id, journeys):
file_path = os.path.join(get_user_data_dir(user_id), 'journeys.json')
file_path = os.path.join(get_user_data_dir(user_id), "journeys.json")
try:
with open(file_path, 'w') as f:
with open(file_path, "w") as f:
json.dump(journeys, f, indent=2)
except Exception as e:
print(f"Error saving journeys for user {user_id}: {e}")
def load_user_posts(user_id):
file_path = os.path.join(get_user_data_dir(user_id), 'posts.json')
file_path = os.path.join(get_user_data_dir(user_id), "posts.json")
try:
if os.path.exists(file_path):
with open(file_path, 'r') as f:
with open(file_path, "r") as f:
return json.load(f)
except Exception as e:
print(f"Error loading posts for user {user_id}: {e}")
return []
def save_user_posts(user_id, posts):
file_path = os.path.join(get_user_data_dir(user_id), 'posts.json')
file_path = os.path.join(get_user_data_dir(user_id), "posts.json")
try:
with open(file_path, 'w') as f:
with open(file_path, "w") as f:
json.dump(posts, f, indent=2)
except Exception as e:
print(f"Error saving posts for user {user_id}: {e}")
# ==================== Authentication endpoints ====================
@app.route('/api/register', methods=['POST'])
@app.route("/api/register", methods=["POST"])
def register():
data = request.get_json()
username = data.get('username')
password = data.get('password')
username = data.get("username")
password = data.get("password")
if not username or not password:
return jsonify({'error': 'Username and password required'}), 400
return jsonify({"error": "Username and password required"}), 400
# Check if username already exists
if get_user_by_username(username):
return jsonify({'error': 'Username already taken'}), 409
return jsonify({"error": "Username already taken"}), 409
users = load_users()
new_id = get_next_user_id(users)
hashed = generate_password_hash(password)
new_user = {
'id': new_id,
'username': username,
'password_hash': hashed,
'created_at': datetime.now().isoformat()
"id": new_id,
"username": username,
"password_hash": hashed,
"created_at": datetime.now().isoformat(),
}
users.append(new_user)
save_users(users)
@ -118,59 +129,58 @@ def register():
save_user_posts(new_id, [])
# Log the user in automatically
session['user_id'] = new_id
session["user_id"] = new_id
return jsonify({
'id': new_id,
'username': username,
'message': 'Registration successful'
}), 201
return jsonify(
{"id": new_id, "username": username, "message": "Registration successful"}
), 201
@app.route('/api/login', methods=['POST'])
@app.route("/api/login", methods=["POST"])
def login():
data = request.get_json()
username = data.get('username')
password = data.get('password')
username = data.get("username")
password = data.get("password")
user = get_user_by_username(username)
if not user or not check_password_hash(user['password_hash'], password):
return jsonify({'error': 'Invalid username or password'}), 401
if not user or not check_password_hash(user["password_hash"], password):
return jsonify({"error": "Invalid username or password"}), 401
session['user_id'] = user['id']
return jsonify({
'id': user['id'],
'username': user['username'],
'message': 'Login successful'
})
session["user_id"] = user["id"]
return jsonify(
{"id": user["id"], "username": user["username"], "message": "Login successful"}
)
@app.route('/api/logout', methods=['POST'])
@app.route("/api/logout", methods=["POST"])
def logout():
session.pop('user_id', None)
return jsonify({'message': 'Logged out'})
session.pop("user_id", None)
return jsonify({"message": "Logged out"})
@app.route('/api/me', methods=['GET'])
@app.route("/api/me", methods=["GET"])
def me():
user_id = session.get('user_id')
user_id = session.get("user_id")
if not user_id:
return jsonify({'error': 'Not logged in'}), 401
return jsonify({"error": "Not logged in"}), 401
user = get_user_by_id(user_id)
if not user:
# Should not happen, but clean session
session.pop('user_id', None)
return jsonify({'error': 'User not found'}), 401
return jsonify({
'id': user['id'],
'username': user['username']
})
session.pop("user_id", None)
return jsonify({"error": "User not found"}), 401
return jsonify({"id": user["id"], "username": user["username"]})
# ==================== Journey endpoints (protected, userspecific) ====================
def require_login():
if 'user_id' not in session:
if "user_id" not in session:
return False
return True
def get_current_user_id():
return session.get('user_id')
return session.get("user_id")
def get_journeys_for_current_user():
user_id = get_current_user_id()
@ -178,91 +188,98 @@ def get_journeys_for_current_user():
return None
return load_user_journeys(user_id)
@app.route('/api/journeys', methods=['GET'])
@app.route("/api/journeys", methods=["GET"])
def get_journeys():
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
journeys = get_journeys_for_current_user()
return jsonify(journeys)
def get_next_journey_id(journeys):
if not journeys:
return 1
return max(j['id'] for j in journeys) + 1
return max(j["id"] for j in journeys) + 1
@app.route('/api/journeys', methods=['POST'])
@app.route("/api/journeys", methods=["POST"])
def create_journey():
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
data = request.get_json()
if not data:
return jsonify({'error': 'No data provided'}), 400
return jsonify({"error": "No data provided"}), 400
title = data.get('title')
title = data.get("title")
if not title:
return jsonify({'error': 'Journey title is required'}), 400
return jsonify({"error": "Journey title is required"}), 400
user_id = get_current_user_id()
journeys = get_journeys_for_current_user()
new_id = get_next_journey_id(journeys)
new_journey = {
'id': new_id,
'title': title,
'description': data.get('description', ''),
'markers': data.get('markers', []),
'created_at': datetime.now().isoformat()
"id": new_id,
"title": title,
"description": data.get("description", ""),
"markers": data.get("markers", []),
"created_at": datetime.now().isoformat(),
}
journeys.append(new_journey)
save_user_journeys(user_id, journeys)
return jsonify(new_journey), 201
@app.route('/api/journeys/<int:journey_id>', methods=['GET'])
@app.route("/api/journeys/<int:journey_id>", methods=["GET"])
def get_journey(journey_id):
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
journeys = get_journeys_for_current_user()
journey = next((j for j in journeys if j['id'] == journey_id), None)
journey = next((j for j in journeys if j["id"] == journey_id), None)
if journey is None:
return jsonify({'error': 'Journey not found'}), 404
return jsonify({"error": "Journey not found"}), 404
return jsonify(journey)
@app.route('/api/journeys/<int:journey_id>', methods=['PUT'])
@app.route("/api/journeys/<int:journey_id>", methods=["PUT"])
def update_journey(journey_id):
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
journeys = get_journeys_for_current_user()
journey = next((j for j in journeys if j['id'] == journey_id), None)
journey = next((j for j in journeys if j["id"] == journey_id), None)
if journey is None:
return jsonify({'error': 'Journey not found'}), 404
return jsonify({"error": "Journey not found"}), 404
data = request.get_json()
if not data:
return jsonify({'error': 'No data provided'}), 400
return jsonify({"error": "No data provided"}), 400
if 'title' in data:
journey['title'] = data['title']
if 'description' in data:
journey['description'] = data['description']
if 'markers' in data:
journey['markers'] = data['markers']
if "title" in data:
journey["title"] = data["title"]
if "description" in data:
journey["description"] = data["description"]
if "markers" in data:
journey["markers"] = data["markers"]
save_user_journeys(get_current_user_id(), journeys)
return jsonify(journey)
@app.route('/api/journeys/<int:journey_id>', methods=['DELETE'])
@app.route("/api/journeys/<int:journey_id>", methods=["DELETE"])
def delete_journey(journey_id):
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
journeys = get_journeys_for_current_user()
journey = next((j for j in journeys if j['id'] == journey_id), None)
journey = next((j for j in journeys if j["id"] == journey_id), None)
if journey is None:
return jsonify({'error': 'Journey not found'}), 404
return jsonify({"error": "Journey not found"}), 404
journeys = [j for j in journeys if j['id'] != journey_id]
journeys = [j for j in journeys if j["id"] != journey_id]
save_user_journeys(get_current_user_id(), journeys)
return jsonify({'message': 'Journey deleted successfully', 'journey': journey})
return jsonify({"message": "Journey deleted successfully", "journey": journey})
# ==================== Blog Post endpoints (protected, userspecific) ====================
def get_posts_for_current_user():
@ -271,97 +288,105 @@ def get_posts_for_current_user():
return None
return load_user_posts(user_id)
def get_next_post_id(posts):
if not posts:
return 1
return max(p['id'] for p in posts) + 1
return max(p["id"] for p in posts) + 1
@app.route('/api/blog-posts', methods=['GET'])
@app.route("/api/blog-posts", methods=["GET"])
def get_blog_posts():
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
posts = get_posts_for_current_user()
return jsonify(posts)
@app.route('/api/blog-posts/<int:post_id>', methods=['GET'])
@app.route("/api/blog-posts/<int:post_id>", methods=["GET"])
def get_blog_post(post_id):
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
posts = get_posts_for_current_user()
post = next((p for p in posts if p['id'] == post_id), None)
post = next((p for p in posts if p["id"] == post_id), None)
if not post:
return jsonify({'error': 'Post not found'}), 404
return jsonify({"error": "Post not found"}), 404
return jsonify(post)
@app.route('/api/blog-posts', methods=['POST'])
@app.route("/api/blog-posts", methods=["POST"])
def create_blog_post():
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
data = request.get_json()
title = data.get('title')
title = data.get("title")
if not title:
return jsonify({'error': 'Title required'}), 400
return jsonify({"error": "Title required"}), 400
user_id = get_current_user_id()
posts = get_posts_for_current_user()
new_id = get_next_post_id(posts)
new_post = {
'id': new_id,
'title': title,
'content': data.get('content', ''),
'journeyId': data.get('journeyId'),
'image': data.get('image'),
'created_at': datetime.now().isoformat()
"id": new_id,
"title": title,
"content": data.get("content", ""),
"journeyId": data.get("journeyId"),
"image": data.get("image"),
"created_at": datetime.now().isoformat(),
}
posts.append(new_post)
save_user_posts(user_id, posts)
return jsonify(new_post), 201
@app.route('/api/blog-posts/<int:post_id>', methods=['PUT'])
@app.route("/api/blog-posts/<int:post_id>", methods=["PUT"])
def update_blog_post(post_id):
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
posts = get_posts_for_current_user()
post = next((p for p in posts if p['id'] == post_id), None)
post = next((p for p in posts if p["id"] == post_id), None)
if not post:
return jsonify({'error': 'Post not found'}), 404
return jsonify({"error": "Post not found"}), 404
data = request.get_json()
if 'title' in data:
post['title'] = data['title']
if 'content' in data:
post['content'] = data['content']
if 'journeyId' in data:
post['journeyId'] = data['journeyId']
if 'image' in data:
post['image'] = data['image']
if "title" in data:
post["title"] = data["title"]
if "content" in data:
post["content"] = data["content"]
if "journeyId" in data:
post["journeyId"] = data["journeyId"]
if "image" in data:
post["image"] = data["image"]
save_user_posts(get_current_user_id(), posts)
return jsonify(post)
@app.route('/api/blog-posts/<int:post_id>', methods=['DELETE'])
@app.route("/api/blog-posts/<int:post_id>", methods=["DELETE"])
def delete_blog_post(post_id):
if not require_login():
return jsonify({'error': 'Authentication required'}), 401
return jsonify({"error": "Authentication required"}), 401
posts = get_posts_for_current_user()
post = next((p for p in posts if p['id'] == post_id), None)
post = next((p for p in posts if p["id"] == post_id), None)
if not post:
return jsonify({'error': 'Post not found'}), 404
return jsonify({"error": "Post not found"}), 404
posts = [p for p in posts if p['id'] != post_id]
posts = [p for p in posts if p["id"] != post_id]
save_user_posts(get_current_user_id(), posts)
return jsonify({'message': 'Post deleted'})
return jsonify({"message": "Post deleted"})
# ==================== Health and root ====================
@app.route('/api/journeys/health', methods=['GET'])
@app.route("/api/journeys/health", methods=["GET"])
def health_check():
return jsonify({'status': 'healthy', 'timestamp': datetime.now().isoformat()})
return jsonify({"status": "healthy", "timestamp": datetime.now().isoformat()})
@app.route('/')
@app.route("/")
def index():
return '''
return """
<!DOCTYPE html>
<html>
<head><title>Journey Mapper API</title></head>
@ -371,7 +396,8 @@ def index():
<p>Authentication required: register, login, then use session cookies.</p>
</body>
</html>
'''
"""
if __name__ == '__main__':
app.run(debug=True, port=5000)
if __name__ == "__main__":
app.run(debug=True, port=5000)

View File

@ -1 +1,42 @@
[]
[
{
"id": 1,
"title": "test",
"description": "11",
"markers": [
{
"lat": 48.356249029540734,
"lng": 4.866943359375,
"title": "New Marker",
"date": "",
"description": "",
"videoUrl": ""
},
{
"lat": 46.961510504873104,
"lng": 9.371337890625002,
"title": "New Marker",
"date": "",
"description": "",
"videoUrl": ""
},
{
"lat": 45.51404592560427,
"lng": 11.656494140625002,
"title": "New Marker",
"date": "",
"description": "",
"videoUrl": ""
},
{
"lat": 43.52465500687188,
"lng": 11.162109375,
"title": "New Marker",
"date": "",
"description": "",
"videoUrl": ""
}
],
"created_at": "2026-03-27T21:49:26.885353"
}
]

View File

@ -1 +1,10 @@
[]
[
{
"id": 1,
"title": "test",
"content": "ksafladjsfk",
"journeyId": "1",
"image": null,
"created_at": "2026-03-27T21:23:39.755057"
}
]

View File

@ -220,62 +220,9 @@
</main>
<div id="toast" class="toast"></div>
<script src="js/auth.js"></script>
<script>
// ==================== AUTH ====================
const API_BASE = 'http://127.0.0.1:5000/api';
let currentUser = null;
async function checkAuthAndRedirect() {
try {
const res = await fetch(`${API_BASE}/me`, { credentials: 'include' });
if (res.ok) {
currentUser = await res.json();
return true;
} else {
window.location.href = 'login.html';
return false;
}
} catch (err) {
window.location.href = 'login.html';
return false;
}
}
function updateUserMenu() {
const container = document.getElementById('user-menu');
if (currentUser) {
container.innerHTML = `
<span class="username"><i class="fas fa-user"></i> ${escapeHtml(currentUser.username)}</span>
<button id="logout-btn" class="logout-btn"><i class="fas fa-sign-out-alt"></i> Logout</button>
`;
document.getElementById('logout-btn')?.addEventListener('click', logout);
}
}
async function logout() {
await fetch(`${API_BASE}/logout`, { method: 'POST', credentials: 'include' });
window.location.href = 'login.html';
}
function escapeHtml(str) {
if (!str) return '';
return str.replace(/[&<>]/g, function(m) {
if (m === '&') return '&amp;';
if (m === '<') return '&lt;';
if (m === '>') return '&gt;';
return m;
});
}
function showToast(msg, isError = false) {
const toast = document.getElementById('toast');
toast.textContent = msg;
toast.style.backgroundColor = isError ? 'var(--red-7)' : 'var(--green-7)';
toast.style.display = 'block';
setTimeout(() => { toast.style.display = 'none'; }, 3000);
}
// ==================== BLOG POSTS ====================
async function loadPosts() {
try {

View File

@ -238,63 +238,11 @@
</main>
<div id="toast" class="toast"></div>
<script src="js/auth.js"></script>
<script>
// ==================== AUTH ====================
const API_BASE = 'http://127.0.0.1:5000/api';
let currentUser = null;
let currentPostId = null;
async function checkAuthAndRedirect() {
try {
const res = await fetch(`${API_BASE}/me`, { credentials: 'include' });
if (res.ok) {
currentUser = await res.json();
return true;
} else {
window.location.href = 'login.html';
return false;
}
} catch (err) {
window.location.href = 'login.html';
return false;
}
}
function updateUserMenu() {
const container = document.getElementById('user-menu');
if (currentUser) {
container.innerHTML = `
<span class="username"><i class="fas fa-user"></i> ${escapeHtml(currentUser.username)}</span>
<button id="logout-btn" class="logout-btn"><i class="fas fa-sign-out-alt"></i> Logout</button>
`;
document.getElementById('logout-btn')?.addEventListener('click', logout);
}
}
async function logout() {
await fetch(`${API_BASE}/logout`, { method: 'POST', credentials: 'include' });
window.location.href = 'login.html';
}
function escapeHtml(str) {
if (!str) return '';
return str.replace(/[&<>]/g, function(m) {
if (m === '&') return '&amp;';
if (m === '<') return '&lt;';
if (m === '>') return '&gt;';
return m;
});
}
function showToast(message, isError = false) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.style.backgroundColor = isError ? 'var(--red-7)' : 'var(--green-7)';
toast.style.display = 'block';
setTimeout(() => { toast.style.display = 'none'; }, 3000);
}
// ==================== POST CRUD ====================
const urlParams = new URLSearchParams(window.location.search);
const postId = urlParams.get('id');

67
js/auth.js Normal file
View File

@ -0,0 +1,67 @@
const API_BASE = "http://127.0.0.1:5000/api";
let currentUser = null;
async function checkAuth() {
try {
const res = await fetch(`${API_BASE}/me`, { credentials: "include" });
if (res.ok) {
currentUser = await res.json();
return true;
}
return false;
} catch (err) {
return false;
}
}
async function checkAuthAndRedirect() {
const ok = await checkAuth();
if (!ok) {
window.location.href = "login.html";
return false;
}
return true;
}
function updateUserMenu() {
const container = document.getElementById("user-menu");
if (!container) return;
if (currentUser) {
container.innerHTML = `
<span class="username"><i class="fas fa-user"></i> ${escapeHtml(currentUser.username)}</span>
<button id="logout-btn" class="logout-btn"><i class="fas fa-sign-out-alt"></i> Logout</button>
`;
document.getElementById("logout-btn")?.addEventListener("click", logout);
} else {
container.innerHTML = `<button id="login-open-btn" class="login-btn"><i class="fas fa-sign-in-alt"></i> Login</button>`;
document.getElementById("login-open-btn")?.addEventListener("click", () => {
window.location.href = "login.html";
});
}
}
async function logout() {
await fetch(`${API_BASE}/logout`, { method: "POST", credentials: "include" });
window.location.href = "login.html";
}
function escapeHtml(str) {
if (!str) return "";
return str.replace(/[&<>]/g, function (m) {
if (m === "&") return "&amp;";
if (m === "<") return "&lt;";
if (m === ">") return "&gt;";
return m;
});
}
function showToast(msg, isError = false) {
const toast = document.getElementById("toast");
if (!toast) return;
toast.textContent = msg;
toast.style.backgroundColor = isError ? "var(--red-7)" : "var(--green-7)";
toast.style.display = "block";
setTimeout(() => {
toast.style.display = "none";
}, 3000);
}

View File

@ -154,51 +154,8 @@
</div>
<div id="toast" class="toast"></div>
<script src="js/auth.js"></script>
<script>
const API_BASE = 'http://127.0.0.1:5000/api';
function showToast(msg, isError = false) {
const toast = document.getElementById('toast');
toast.textContent = msg;
toast.style.backgroundColor = isError ? 'var(--red-7)' : 'var(--green-7)';
toast.style.display = 'block';
setTimeout(() => { toast.style.display = 'none'; }, 3000);
}
async function login(username, password) {
try {
const res = await fetch(`${API_BASE}/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
credentials: 'include'
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Login failed');
showToast(`Welcome, ${data.username}!`);
window.location.href = 'map-page.html';
} catch (err) {
showToast(err.message, true);
}
}
async function register(username, password) {
try {
const res = await fetch(`${API_BASE}/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
credentials: 'include'
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Registration failed');
showToast(`Registered as ${data.username}. Logging in...`);
window.location.href = 'map-page.html';
} catch (err) {
showToast(err.message, true);
}
}
document.addEventListener('DOMContentLoaded', () => {
// Tab switching
document.querySelectorAll('.auth-tab').forEach(tab => {
@ -211,30 +168,56 @@
});
});
// Login button
document.getElementById('login-submit').addEventListener('click', () => {
document.getElementById('login-submit').addEventListener('click', async () => {
const username = document.getElementById('login-username').value.trim();
const password = document.getElementById('login-password').value;
if (!username || !password) {
showToast('Please enter username and password', true);
return;
}
login(username, password);
try {
const res = await fetch(`${API_BASE}/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
credentials: 'include'
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Login failed');
showToast(`Welcome, ${data.username}`);
window.location.href = 'map-page.html';
} catch (err) {
showToast(err.message, true);
}
});
// Register button
document.getElementById('register-submit').addEventListener('click', () => {
const username = document.getElementById('register-username').value.trim();
const password = document.getElementById('register-password').value;
if (!username || !password) {
showToast('Please enter username and password', true);
return;
}
if (password.length < 4) {
showToast('Password must be at least 4 characters', true);
return;
}
register(username, password);
});
});
document.getElementById('register-submit').addEventListener('click', async () => {
const username = document.getElementById('register-username').value.trim();
const password = document.getElementById('register-password').value;
if (!username || !password) {
showToast('Please enter username and password', true);
return;
}
if (password.length < 4) {
showToast('Password must be at least 4 characters', true);
return;
}
try {
const res = await fetch(`${API_BASE}/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
credentials: 'include'
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Registration failed');
showToast(`Registered as ${data.username}. Logging in...`);
window.location.href = 'map-page.html';
} catch (err) {
showToast(err.message, true);
}
});
});
</script>
</body>
</html>
</html>

View File

@ -876,65 +876,10 @@
</main>
</div>
<div id="toast" class="toast"><p id="toast-message"></p></div>
<script src="js/auth.js"></script>
<script>
// ==================== AUTH & REDIRECT ====================
const API_BASE = "http://127.0.0.1:5000/api";
let currentUser = null;
async function checkAuth() {
try {
const res = await fetch(`${API_BASE}/me`, {
credentials: "include",
});
if (res.ok) {
currentUser = await res.json();
return true;
} else {
window.location.href = "login.html";
return false;
}
} catch (err) {
window.location.href = "login.html";
return false;
}
}
function updateUserMenu() {
const container = document.getElementById("user-menu");
if (currentUser) {
container.innerHTML = `
<span class="username"><i class="fas fa-user"></i> ${escapeHtml(currentUser.username)}</span>
<button id="logout-btn" class="logout-btn"><i class="fas fa-sign-out-alt"></i> Logout</button>
`;
document
.getElementById("logout-btn")
?.addEventListener("click", logout);
}
}
async function logout() {
await fetch(`${API_BASE}/logout`, {
method: "POST",
credentials: "include",
});
window.location.href = "login.html";
}
function escapeHtml(str) {
if (!str) return "";
return str.replace(/[&<>]/g, function (m) {
if (m === "&") return "&amp;";
if (m === "<") return "&lt;";
if (m === ">") return "&gt;";
return m;
});
}
// ==================== MAP CODE (from your file, but with credentials added) ====================
// ==================== MAP CODE ====================
(function () {
// ==================== CONFIG ====================
// API_BASE is already defined outside
// ==================== STATE =====================
let map;
let currentJourney = {
@ -1462,7 +1407,7 @@
// ==================== AUTHENTICATION CHECK ====================
document.addEventListener("DOMContentLoaded", async () => {
const authenticated = await checkAuth();
const authenticated = await checkAuthAndRedirect();
if (authenticated) {
updateUserMenu();
window.startMap(); // call the map initializer from the IIFE