Added signup form and functionality
This commit is contained in:
@ -3,6 +3,7 @@ from flask_login import login_user, logout_user
|
||||
from app.models.users import User
|
||||
from datetime import datetime, timedelta
|
||||
from app.models import db
|
||||
import re
|
||||
|
||||
import sys
|
||||
|
||||
@ -43,3 +44,40 @@ def logout():
|
||||
logout_user()
|
||||
flash('You have been logged out.', 'info')
|
||||
return redirect(url_for('main.login_route'))
|
||||
|
||||
def signup():
|
||||
username = request.form.get('username')
|
||||
email = request.form.get('email')
|
||||
password = request.form.get('password')
|
||||
|
||||
# Server-side validation
|
||||
if len(username) < 5:
|
||||
flash('Username must be at least 5 characters long', 'danger')
|
||||
return redirect(url_for('main.login_route'))
|
||||
|
||||
email_regex = r'^[a-zA-Z][a-zA-Z0-9._-]*@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
||||
if not re.match(email_regex, email):
|
||||
flash('Please enter a valid email address', 'danger')
|
||||
return redirect(url_for('main.login_route'))
|
||||
|
||||
password_regex = r'^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{8,}$'
|
||||
if not re.match(password_regex, password):
|
||||
flash('Password must be at least 8 characters long and contain a number and a special character', 'danger')
|
||||
return redirect(url_for('main.login_route'))
|
||||
|
||||
# Check if username or email already exists
|
||||
if User.query.filter_by(username=username).first():
|
||||
flash('Username already exists', 'danger')
|
||||
return redirect(url_for('main.login_route'))
|
||||
|
||||
if User.query.filter_by(email=email).first():
|
||||
flash('Email already exists', 'danger')
|
||||
return redirect(url_for('main.login_route'))
|
||||
|
||||
# Create new user
|
||||
new_user = User(username=username, email=email, password=password)
|
||||
db.session.add(new_user)
|
||||
db.session.commit()
|
||||
|
||||
flash('Account created successfully! Please login.', 'success')
|
||||
return redirect(url_for('main.login_route'))
|
@ -7,4 +7,5 @@ class User(db.Model, UserMixin):
|
||||
username = db.Column(db.String(80), unique=True, nullable=False)
|
||||
email = db.Column(db.String(120), unique=True, nullable=False)
|
||||
password = db.Column(db.String(120), nullable=False)
|
||||
|
||||
failed_login_attempts = db.Column(db.Integer, default=0, nullable=False)
|
||||
last_failed_login_attempt = db.Column(db.DateTime, default=None, nullable=True)
|
||||
|
@ -1,8 +1,9 @@
|
||||
from flask import Blueprint
|
||||
from flask_login import login_required
|
||||
from app.controllers.auth_controller import login, logout
|
||||
from app.controllers.auth_controller import login, logout, signup
|
||||
from app.controllers.home_controller import home
|
||||
|
||||
|
||||
main = Blueprint('main', __name__)
|
||||
|
||||
@main.route('/')
|
||||
@ -17,3 +18,7 @@ def login_route():
|
||||
@login_required
|
||||
def logout_route():
|
||||
return logout()
|
||||
|
||||
@main.route('/signup', methods=['POST'])
|
||||
def signup_route():
|
||||
return signup()
|
@ -50,8 +50,8 @@
|
||||
border: 1px solid #D9D9D9;
|
||||
border-radius: 6px;
|
||||
background-color: #D9D9D9;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
color: rgb(0, 0, 0);
|
||||
font-size: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@ -81,19 +81,6 @@
|
||||
letter-spacing: 3px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.login-container {
|
||||
width: 95%;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.error-message p {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.signup-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -105,6 +92,19 @@
|
||||
color: #8f8f8f;
|
||||
margin-top: 14px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.signup u:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error-message p {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
@ -112,14 +112,13 @@
|
||||
{% block content %}
|
||||
<div class="spotlight"></div>
|
||||
<div class="container">
|
||||
<div class="login-signup-container">
|
||||
|
||||
</div>
|
||||
<div class="login-container">
|
||||
<!-- Login Form -->
|
||||
<div id="loginForm">
|
||||
<h2>Login</h2>
|
||||
<p class="login-description">Enter your credentials below to login to your account</p>
|
||||
|
||||
<form method="POST" action="{{ url_for('main.login_route') }}">
|
||||
<form method="POST" action="{{ url_for('main.login_route') }}" id="login-form">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
@ -133,9 +132,37 @@
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<div class="signup-container">
|
||||
<p class="signup">Dont have an account? <u>Sign up</u></p>
|
||||
<p class="signup">Don't have an account? <u onclick="toggleForms()">Sign up</u></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Signup Form -->
|
||||
<div id="signupForm" class="hidden">
|
||||
<h2>Sign Up</h2>
|
||||
<p class="login-description">Create your account to get started</p>
|
||||
|
||||
<form method="POST" action="{{ url_for('main.signup_route') }}" id="signup-form" onsubmit="return validateForm()">
|
||||
<div class="form-group">
|
||||
<label for="signup-username">Username</label>
|
||||
<input type="text" id="signup-username" name="username" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="signup-email">Email</label>
|
||||
<input type="email" id="signup-email" name="email" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="signup-password">Password</label>
|
||||
<input type="password" id="signup-password" name="password" required class="password-input">
|
||||
</div>
|
||||
|
||||
<button type="submit">Sign Up</button>
|
||||
</form>
|
||||
<div class="signup-container">
|
||||
<p class="signup">Already have an account? <u onclick="toggleForms()">Login</u></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
@ -148,4 +175,61 @@
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleForms() {
|
||||
const loginForm = document.getElementById('loginForm');
|
||||
const signupForm = document.getElementById('signupForm');
|
||||
loginForm.classList.toggle('hidden');
|
||||
signupForm.classList.toggle('hidden');
|
||||
}
|
||||
|
||||
function validateForm() {
|
||||
const username = document.getElementById('signup-username').value;
|
||||
const email = document.getElementById('signup-email').value;
|
||||
const password = document.getElementById('signup-password').value;
|
||||
|
||||
// Username validation
|
||||
if (username.length < 5) {
|
||||
flash('Username must be at least 5 characters long');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Email validation
|
||||
const emailRegex = /^[a-zA-Z][a-zA-Z0-9._-]*@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
flash('Please enter a valid email address');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password validation
|
||||
const passwordRegex = /^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{8,}$/;
|
||||
if (!passwordRegex.test(password)) {
|
||||
flash('Password must be at least 8 characters long and contain a number and a special character');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function flash(message) {
|
||||
const errorDiv = document.querySelector('.error-message');
|
||||
if (!errorDiv) {
|
||||
const newErrorDiv = document.createElement('div');
|
||||
newErrorDiv.className = 'error-message';
|
||||
const p = document.createElement('p');
|
||||
p.className = 'text-danger';
|
||||
p.textContent = message;
|
||||
newErrorDiv.appendChild(p);
|
||||
document.querySelector('.login-container').appendChild(newErrorDiv);
|
||||
} else {
|
||||
const p = errorDiv.querySelector('p') || document.createElement('p');
|
||||
p.className = 'text-danger';
|
||||
p.textContent = message;
|
||||
if (!errorDiv.contains(p)) {
|
||||
errorDiv.appendChild(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user