mj add another admin
This commit is contained in:
7
app.py
7
app.py
@@ -21,17 +21,18 @@ login_manager.login_view = 'auth.login'
|
|||||||
login_manager.login_message = 'Παρακαλώ συνδεθείτε για να συνεχίσετε.'
|
login_manager.login_message = 'Παρακαλώ συνδεθείτε για να συνεχίσετε.'
|
||||||
|
|
||||||
class User(UserMixin):
|
class User(UserMixin):
|
||||||
def __init__(self, id, username):
|
def __init__(self, id, username, clan_id):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.username = username
|
self.username = username
|
||||||
|
self.clan_id = clan_id
|
||||||
|
|
||||||
@login_manager.user_loader
|
@login_manager.user_loader
|
||||||
def load_user(user_id):
|
def load_user(user_id):
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
row = conn.execute('SELECT id, username FROM users WHERE id = ?', (user_id,)).fetchone()
|
row = conn.execute('SELECT id, username, clan_id FROM users WHERE id = ?', (user_id,)).fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
if row:
|
if row:
|
||||||
return User(row['id'], row['username'])
|
return User(row['id'], row['username'], row['clan_id'])
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Make current_user available in all templates
|
# Make current_user available in all templates
|
||||||
|
|||||||
13
db.py
13
db.py
@@ -77,6 +77,7 @@ def init_db():
|
|||||||
'ALTER TABLE commands ADD COLUMN player_id TEXT',
|
'ALTER TABLE commands ADD COLUMN player_id TEXT',
|
||||||
'ALTER TABLE farm_settings ADD COLUMN bandit_camp_enabled INTEGER NOT NULL DEFAULT 0',
|
'ALTER TABLE farm_settings ADD COLUMN bandit_camp_enabled INTEGER NOT NULL DEFAULT 0',
|
||||||
"ALTER TABLE clan_members ADD COLUMN features TEXT NOT NULL DEFAULT 'farm,admin'",
|
"ALTER TABLE clan_members ADD COLUMN features TEXT NOT NULL DEFAULT 'farm,admin'",
|
||||||
|
'ALTER TABLE users ADD COLUMN clan_id INTEGER REFERENCES clans(id)',
|
||||||
]:
|
]:
|
||||||
try:
|
try:
|
||||||
c.execute(_col)
|
c.execute(_col)
|
||||||
@@ -89,6 +90,7 @@ def init_db():
|
|||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
username TEXT NOT NULL UNIQUE,
|
username TEXT NOT NULL UNIQUE,
|
||||||
password_hash TEXT NOT NULL,
|
password_hash TEXT NOT NULL,
|
||||||
|
clan_id INTEGER REFERENCES clans(id),
|
||||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
@@ -111,11 +113,22 @@ def init_db():
|
|||||||
clan_id INTEGER NOT NULL REFERENCES clans(id),
|
clan_id INTEGER NOT NULL REFERENCES clans(id),
|
||||||
player_id TEXT NOT NULL,
|
player_id TEXT NOT NULL,
|
||||||
player_name TEXT,
|
player_name TEXT,
|
||||||
|
features TEXT NOT NULL DEFAULT 'farm,admin',
|
||||||
joined_at TEXT NOT NULL DEFAULT (datetime('now')),
|
joined_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
UNIQUE(clan_id, player_id)
|
UNIQUE(clan_id, player_id)
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# Migration: Auto-assign existing users to their clan_id if they are the owner
|
||||||
|
try:
|
||||||
|
c.execute('''
|
||||||
|
UPDATE users
|
||||||
|
SET clan_id = (SELECT id FROM clans WHERE owner_id = users.id)
|
||||||
|
WHERE clan_id IS NULL AND EXISTS (SELECT 1 FROM clans WHERE owner_id = users.id)
|
||||||
|
''')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ auth = Blueprint('auth', __name__)
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
def _make_user(row):
|
def _make_user(row):
|
||||||
from app import User
|
from app import User
|
||||||
return User(row['id'], row['username'])
|
return User(row['id'], row['username'], row['clan_id'])
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -30,7 +30,7 @@ def login():
|
|||||||
|
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
row = conn.execute(
|
row = conn.execute(
|
||||||
'SELECT id, username, password_hash FROM users WHERE username = ?', (username,)
|
'SELECT id, username, password_hash, clan_id FROM users WHERE username = ?', (username,)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ def register():
|
|||||||
)
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
row = conn.execute(
|
row = conn.execute(
|
||||||
'SELECT id, username, password_hash FROM users WHERE username = ?', (username,)
|
'SELECT id, username, password_hash, clan_id FROM users WHERE username = ?', (username,)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
user = _make_user(row)
|
user = _make_user(row)
|
||||||
@@ -108,10 +108,21 @@ def logout():
|
|||||||
def options():
|
def options():
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
|
|
||||||
|
# Load clan based on current user's clan_id
|
||||||
|
clan = None
|
||||||
|
if current_user.clan_id:
|
||||||
clan = conn.execute(
|
clan = conn.execute(
|
||||||
'SELECT * FROM clans WHERE owner_id = ?', (current_user.id,)
|
'SELECT * FROM clans WHERE id = ?', (current_user.clan_id,)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
|
# Fetch website admins (users belonging to this clan other than current user)
|
||||||
|
admins = []
|
||||||
|
if clan and clan['owner_id'] == current_user.id:
|
||||||
|
admins = conn.execute(
|
||||||
|
'SELECT id, username, created_at FROM users WHERE clan_id = ? AND id != ? ORDER BY created_at ASC',
|
||||||
|
(clan['id'], current_user.id)
|
||||||
|
).fetchall()
|
||||||
|
|
||||||
members = []
|
members = []
|
||||||
if clan:
|
if clan:
|
||||||
rows = conn.execute(
|
rows = conn.execute(
|
||||||
@@ -146,7 +157,7 @@ def options():
|
|||||||
})
|
})
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
return render_template('options.html', clan=clan, members=members)
|
return render_template('options.html', clan=clan, members=members, admins=admins)
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -166,12 +177,17 @@ def create_clan():
|
|||||||
|
|
||||||
if not existing:
|
if not existing:
|
||||||
key = generate_clan_key()
|
key = generate_clan_key()
|
||||||
conn.execute(
|
cursor = conn.execute(
|
||||||
'INSERT INTO clans (owner_id, name, clan_key) VALUES (?, ?, ?)',
|
'INSERT INTO clans (owner_id, name, clan_key) VALUES (?, ?, ?)',
|
||||||
(current_user.id, clan_name, key)
|
(current_user.id, clan_name, key)
|
||||||
)
|
)
|
||||||
|
clan_id = cursor.lastrowid
|
||||||
|
conn.execute('UPDATE users SET clan_id = ? WHERE id = ?', (clan_id, current_user.id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
|
# Update the current_user object dynamically to reflect the new clan_id without re-login
|
||||||
|
current_user.clan_id = clan_id
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
return redirect(url_for('auth.options'))
|
return redirect(url_for('auth.options'))
|
||||||
|
|
||||||
@@ -233,3 +249,55 @@ def update_member_features(player_id):
|
|||||||
conn.close()
|
conn.close()
|
||||||
return redirect(url_for('auth.options'))
|
return redirect(url_for('auth.options'))
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# POST /auth/clan/add-admin
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@auth.route('/auth/clan/add-admin', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def add_admin():
|
||||||
|
username = request.form.get('admin_username', '').strip()
|
||||||
|
if not username:
|
||||||
|
return redirect(url_for('auth.options'))
|
||||||
|
|
||||||
|
conn = get_db()
|
||||||
|
clan = conn.execute(
|
||||||
|
'SELECT id FROM clans WHERE owner_id = ?', (current_user.id,)
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
if clan:
|
||||||
|
# Check if user exists
|
||||||
|
user = conn.execute('SELECT id, clan_id FROM users WHERE username = ?', (username,)).fetchone()
|
||||||
|
if user:
|
||||||
|
# If user already belongs to a clan, we could show an error, but let's just overwrite for now
|
||||||
|
# or maybe only if clan_id is NULL
|
||||||
|
conn.execute('UPDATE users SET clan_id = ? WHERE id = ?', (clan['id'], user['id']))
|
||||||
|
conn.commit()
|
||||||
|
flash(f"Ο χρήστης {username} προστέθηκε ως διαχειριστής.", "success")
|
||||||
|
else:
|
||||||
|
flash(f"Ο χρήστης {username} δεν βρέθηκε.", "error")
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
return redirect(url_for('auth.options'))
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# POST /auth/clan/remove-admin/<admin_id>
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@auth.route('/auth/clan/remove-admin/<int:admin_id>', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def remove_admin(admin_id):
|
||||||
|
conn = get_db()
|
||||||
|
clan = conn.execute(
|
||||||
|
'SELECT id FROM clans WHERE owner_id = ?', (current_user.id,)
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
if clan:
|
||||||
|
conn.execute('UPDATE users SET clan_id = NULL WHERE id = ? AND clan_id = ?', (admin_id, clan['id']))
|
||||||
|
conn.commit()
|
||||||
|
flash("Ο διαχειριστής αφαιρέθηκε.", "success")
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
return redirect(url_for('auth.options'))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,14 @@ dashboard = Blueprint('dashboard', __name__)
|
|||||||
def index():
|
def index():
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
|
|
||||||
# Get the logged-in user's clan
|
# Get the clan the logged-in user belongs to
|
||||||
clan = conn.execute(
|
clan_id = current_user.clan_id
|
||||||
'SELECT id FROM clans WHERE owner_id = ?', (current_user.id,)
|
|
||||||
).fetchone()
|
|
||||||
|
|
||||||
if not clan:
|
if not clan_id:
|
||||||
# User has no clan yet — send them to options to create one
|
# User has no clan yet — send them to options to create/join one
|
||||||
conn.close()
|
conn.close()
|
||||||
return render_template('index.html', players=[], no_clan=True)
|
return render_template('index.html', players=[], no_clan=True)
|
||||||
|
|
||||||
clan_id = clan['id']
|
|
||||||
|
|
||||||
# Only fetch players that are members of this clan
|
# Only fetch players that are members of this clan
|
||||||
rows = conn.execute('''
|
rows = conn.execute('''
|
||||||
SELECT ts.player, ts.player_id, MAX(ts.updated_at) as last_seen, MAX(ts.world_id) as world_id
|
SELECT ts.player, ts.player_id, MAX(ts.updated_at) as last_seen, MAX(ts.world_id) as world_id
|
||||||
|
|||||||
@@ -175,7 +175,18 @@
|
|||||||
<div class="page-title">Ρυθμίσεις Clan</div>
|
<div class="page-title">Ρυθμίσεις Clan</div>
|
||||||
<div class="page-subtitle">Διαχείριση της ομάδας σας και του κλειδιού πρόσβασης</div>
|
<div class="page-subtitle">Διαχείριση της ομάδας σας και του κλειδιού πρόσβασης</div>
|
||||||
|
|
||||||
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
|
{% if messages %}
|
||||||
|
{% for category, message in messages %}
|
||||||
|
<div class="warn-box" style="margin-bottom: 20px; color: {% if category == 'error' %}#f85149{% else %}#3fb950{% endif %}; border-color: {% if category == 'error' %}rgba(248,81,73,0.3){% else %}rgba(63,185,80,0.3){% endif %}; background: {% if category == 'error' %}rgba(248,81,73,0.1){% else %}rgba(63,185,80,0.1){% endif %};">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
{% if clan %}
|
{% if clan %}
|
||||||
|
{% if clan.owner_id == current_user.id %}
|
||||||
<!-- ===================== Clan Key Section ===================== -->
|
<!-- ===================== Clan Key Section ===================== -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">🔑 Clan Key</div>
|
<div class="card-title">🔑 Clan Key</div>
|
||||||
@@ -195,6 +206,49 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ===================== Website Admins Section ===================== -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-title">👨💻 Website Admins</div>
|
||||||
|
<p style="color:#8b949e; font-size:0.875rem; margin-bottom:14px;">
|
||||||
|
Προσθέστε το username άλλων παικτών που έχουν ήδη εγγραφεί στο site για να τους δώσετε πρόσβαση στο dashboard σας.
|
||||||
|
</p>
|
||||||
|
<form method="POST" action="/auth/clan/add-admin" class="inline-form" style="margin-bottom: 20px;">
|
||||||
|
<input type="text" name="admin_username" placeholder="π.χ. player123" required>
|
||||||
|
<button type="submit" class="btn-primary">Προσθήκη Admin</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if admins %}
|
||||||
|
<table class="members-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Admin Username</th>
|
||||||
|
<th>Ημερομηνία Προσθήκης</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for a in admins %}
|
||||||
|
<tr>
|
||||||
|
<td><div class="player-name">{{ a.username }}</div></td>
|
||||||
|
<td style="color:#8b949e; font-size:0.8rem;">{{ a.created_at[:10] }}</td>
|
||||||
|
<td style="text-align:right;">
|
||||||
|
<form method="POST" action="/auth/clan/remove-admin/{{ a.id }}" onsubmit="return confirm('Αφαίρεση του admin {{ a.username }}?');">
|
||||||
|
<button type="submit" class="btn-danger">Αφαίρεση</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<div class="empty-state" style="padding: 16px 0;">
|
||||||
|
Δεν έχετε προσθέσει κανέναν website admin ακόμη.
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<!-- ===================== Members Section ===================== -->
|
<!-- ===================== Members Section ===================== -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">👥 Μέλη Clan — {{ clan.name }}</div>
|
<div class="card-title">👥 Μέλη Clan — {{ clan.name }}</div>
|
||||||
@@ -224,6 +278,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
{% if clan.owner_id == current_user.id %}
|
||||||
<form method="POST" action="/auth/clan/update-features/{{ m.player_id }}" style="display:inline;">
|
<form method="POST" action="/auth/clan/update-features/{{ m.player_id }}" style="display:inline;">
|
||||||
<div class="toggle-group">
|
<div class="toggle-group">
|
||||||
<label class="toggle-label">
|
<label class="toggle-label">
|
||||||
@@ -234,13 +289,21 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<div class="toggle-group" style="opacity: 0.8;">
|
||||||
|
<span class="toggle-label" style="cursor:default; border-color: {{ '#3fb950' if m.feat_farm else '#30363d' }}; color: {{ '#3fb950' if m.feat_farm else '#8b949e' }};">🌾 Farm</span>
|
||||||
|
<span class="toggle-label" style="cursor:default; border-color: {{ '#3fb950' if m.feat_admin else '#30363d' }}; color: {{ '#3fb950' if m.feat_admin else '#8b949e' }};">🏛 Admin</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td style="color:#8b949e; font-size:0.8rem;">{{ m.joined_at }}</td>
|
<td style="color:#8b949e; font-size:0.8rem;">{{ m.joined_at }}</td>
|
||||||
<td style="text-align:right;">
|
<td style="text-align:right;">
|
||||||
|
{% if clan.owner_id == current_user.id %}
|
||||||
<form method="POST" action="/auth/clan/remove-member/{{ m.player_id }}"
|
<form method="POST" action="/auth/clan/remove-member/{{ m.player_id }}"
|
||||||
onsubmit="return confirm('Αφαίρεση παίκτη {{ m.player_name }}?');">
|
onsubmit="return confirm('Αφαίρεση παίκτη {{ m.player_name }}?');">
|
||||||
<button type="submit" class="btn-danger">Αφαίρεση</button>
|
<button type="submit" class="btn-danger">Αφαίρεση</button>
|
||||||
</form>
|
</form>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
Reference in New Issue
Block a user