Enable blocking and unblocking of users.
This commit is contained in:
46
app.py
46
app.py
@@ -7,6 +7,7 @@ from sqlalchemy import func
|
||||
from functools import wraps
|
||||
from flask_mail import Mail, Message
|
||||
from dotenv import load_dotenv
|
||||
from werkzeug.security import check_password_hash
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
@@ -96,17 +97,21 @@ def login():
|
||||
|
||||
user = User.query.filter_by(username=username).first()
|
||||
|
||||
if user is None or not user.check_password(password):
|
||||
if user and user.check_password(password): # Use the check_password method
|
||||
# Check if user is blocked
|
||||
if user.is_blocked:
|
||||
flash('Your account has been disabled. Please contact an administrator.', 'error')
|
||||
return render_template('login.html')
|
||||
|
||||
# Continue with normal login process
|
||||
session['user_id'] = user.id
|
||||
session['username'] = user.username
|
||||
session['is_admin'] = user.is_admin
|
||||
|
||||
flash('Login successful!', 'success')
|
||||
return redirect(url_for('home'))
|
||||
else:
|
||||
flash('Invalid username or password', 'error')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
if not user.is_verified:
|
||||
flash('Please verify your email address before logging in. Check your inbox for the verification link.', 'warning')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
session.clear()
|
||||
session['user_id'] = user.id
|
||||
return redirect(url_for('home'))
|
||||
|
||||
return render_template('login.html', title='Login')
|
||||
|
||||
@@ -655,5 +660,26 @@ def test():
|
||||
def inject_current_year():
|
||||
return {'current_year': datetime.now().year}
|
||||
|
||||
@app.route('/admin/users/toggle-status/<int:user_id>')
|
||||
@admin_required
|
||||
def toggle_user_status(user_id):
|
||||
user = User.query.get_or_404(user_id)
|
||||
|
||||
# Prevent blocking yourself
|
||||
if user.id == session.get('user_id'):
|
||||
flash('You cannot block your own account', 'error')
|
||||
return redirect(url_for('admin_users'))
|
||||
|
||||
# Toggle the blocked status
|
||||
user.is_blocked = not user.is_blocked
|
||||
db.session.commit()
|
||||
|
||||
if user.is_blocked:
|
||||
flash(f'User {user.username} has been blocked', 'success')
|
||||
else:
|
||||
flash(f'User {user.username} has been unblocked', 'success')
|
||||
|
||||
return redirect(url_for('admin_users'))
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
@@ -99,6 +99,11 @@ def migrate_database():
|
||||
print("Adding token_expiry column to user table...")
|
||||
cursor.execute("ALTER TABLE user ADD COLUMN token_expiry TIMESTAMP")
|
||||
|
||||
# Add is_blocked column to user table if it doesn't exist
|
||||
if 'is_blocked' not in user_columns:
|
||||
print("Adding is_blocked column to user table...")
|
||||
cursor.execute("ALTER TABLE user ADD COLUMN is_blocked BOOLEAN DEFAULT 0")
|
||||
|
||||
# Commit changes and close connection
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@@ -22,6 +22,9 @@ class User(db.Model):
|
||||
time_entries = db.relationship('TimeEntry', backref='user', lazy=True)
|
||||
work_config = db.relationship('WorkConfig', backref='user', lazy=True, uselist=False)
|
||||
|
||||
# New field for blocking users
|
||||
is_blocked = db.Column(db.Boolean, default=False)
|
||||
|
||||
def set_password(self, password):
|
||||
self.password_hash = generate_password_hash(password)
|
||||
|
||||
|
||||
@@ -504,3 +504,22 @@ input[type="time"]::-webkit-datetime-edit {
|
||||
color: #666;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* User status badges */
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 3px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.85em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-active {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-blocked {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th>Status</th>
|
||||
<th>Created</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
@@ -33,11 +34,21 @@
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.email }}</td>
|
||||
<td>{% if user.is_admin %}Admin{% else %}User{% endif %}</td>
|
||||
<td>
|
||||
<span class="status-badge {% if user.is_blocked %}status-blocked{% else %}status-active{% endif %}">
|
||||
{% if user.is_blocked %}Blocked{% else %}Active{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ user.created_at.strftime('%Y-%m-%d') }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('edit_user', user_id=user.id) }}" class="btn btn-sm btn-primary">Edit</a>
|
||||
{% if user.id != g.user.id %}
|
||||
<button class="btn btn-sm btn-danger" onclick="confirmDelete({{ user.id }}, '{{ user.username }}')">Delete</button>
|
||||
{% if user.is_blocked %}
|
||||
<a href="{{ url_for('toggle_user_status', user_id=user.id) }}" class="btn btn-sm btn-success">Unblock</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('toggle_user_status', user_id=user.id) }}" class="btn btn-sm btn-warning">Block</a>
|
||||
{% endif %}
|
||||
<button class="btn btn-sm btn-danger" onclick="confirmDelete({{ user.id }}, '{{ user.username }}')">Delete</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user