fix world

This commit is contained in:
2026-05-03 14:19:34 +03:00
parent 11f30f4c6a
commit cf23f38a6e
4 changed files with 62 additions and 27 deletions

43
db.py
View File

@@ -218,25 +218,58 @@ def init_db():
) )
''') ''')
# Clan members — links Grepolis player_ids to a clan # Clan members — links Grepolis player_ids to a clan.
# UNIQUE on (clan_id, player_id, world_id) so the same player
# appearing in multiple worlds creates separate rows.
c.execute(''' c.execute('''
CREATE TABLE IF NOT EXISTS clan_members ( CREATE TABLE IF NOT EXISTS clan_members (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
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,
world_id TEXT, world_id TEXT NOT NULL DEFAULT '',
features TEXT NOT NULL DEFAULT 'farm,admin', 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, world_id)
) )
''') ''')
# Migration: if clan_members still has the old UNIQUE(clan_id, player_id) constraint
# (without world_id), recreate the table with the correct 3-column constraint.
try:
tbl_sql = c.execute(
"SELECT sql FROM sqlite_master WHERE type='table' AND name='clan_members'"
).fetchone()
if tbl_sql and 'player_id, world_id' not in (tbl_sql['sql'] or ''):
c.execute('''
CREATE TABLE IF NOT EXISTS _clan_members_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
clan_id INTEGER NOT NULL REFERENCES clans(id),
player_id TEXT NOT NULL,
player_name TEXT,
world_id TEXT NOT NULL DEFAULT '',
features TEXT NOT NULL DEFAULT 'farm,admin',
joined_at TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE(clan_id, player_id, world_id)
)
''')
c.execute('''
INSERT OR IGNORE INTO _clan_members_new
(id, clan_id, player_id, player_name, world_id, features, joined_at)
SELECT id, clan_id, player_id, player_name,
COALESCE(world_id, ''), features, joined_at
FROM clan_members
''')
c.execute('DROP TABLE clan_members')
c.execute('ALTER TABLE _clan_members_new RENAME TO clan_members')
except Exception as _e:
print(f'clan_members migration skipped: {_e}')
# Migration: Auto-assign existing users to their clan_id if they are the owner # Migration: Auto-assign existing users to their clan_id if they are the owner
try: try:
c.execute(''' c.execute('''
UPDATE users UPDATE users
SET clan_id = (SELECT id FROM clans WHERE owner_id = users.id) 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) WHERE clan_id IS NULL AND EXISTS (SELECT 1 FROM clans WHERE owner_id = users.id)
''') ''')
except Exception: except Exception:

View File

@@ -30,16 +30,17 @@ def _get_clan_from_request():
# Helper — auto-register a player_id under a clan on first push. # Helper — auto-register a player_id under a clan on first push.
# ------------------------------------------------------------------ # ------------------------------------------------------------------
def _auto_register_member(clan_id, player_id, player_name, world_id=''): def _auto_register_member(clan_id, player_id, player_name, world_id=''):
world_id = world_id or ''
conn = get_db() conn = get_db()
conn.execute(''' conn.execute('''
INSERT OR IGNORE INTO clan_members (clan_id, player_id, player_name, world_id) INSERT OR IGNORE INTO clan_members (clan_id, player_id, player_name, world_id)
VALUES (?, ?, ?, ?) VALUES (?, ?, ?, ?)
''', (clan_id, str(player_id), player_name or '', world_id or '')) ''', (clan_id, str(player_id), player_name or '', world_id))
# Update name and world on every push (they can change) # Update name on every push (it can change); world_id is part of the key so no overwrite risk
conn.execute(''' conn.execute('''
UPDATE clan_members SET player_name = ?, world_id = ? UPDATE clan_members SET player_name = ?
WHERE clan_id = ? AND player_id = ? WHERE clan_id = ? AND player_id = ? AND world_id = ?
''', (player_name or '', world_id or '', clan_id, str(player_id))) ''', (player_name or '', clan_id, str(player_id), world_id))
conn.commit() conn.commit()
conn.close() conn.close()

View File

@@ -127,12 +127,13 @@ def options():
if clan: if clan:
rows = conn.execute( rows = conn.execute(
'''SELECT cm.id, cm.player_id, cm.player_name, cm.world_id, cm.joined_at, cm.features, '''SELECT cm.id, cm.player_id, cm.player_name, cm.world_id, cm.joined_at, cm.features,
ts.updated_at MAX(ts.updated_at) as updated_at
FROM clan_members cm FROM clan_members cm
LEFT JOIN town_state ts ON ts.player_id = cm.player_id LEFT JOIN town_state ts ON ts.player_id = cm.player_id
AND ts.world_id = cm.world_id
WHERE cm.clan_id = ? WHERE cm.clan_id = ?
GROUP BY cm.player_id GROUP BY cm.player_id, cm.world_id
ORDER BY cm.joined_at DESC''', ORDER BY cm.player_name ASC, cm.world_id ASC''',
(clan['id'],) (clan['id'],)
).fetchall() ).fetchall()
@@ -212,17 +213,17 @@ def regenerate_key():
return redirect(url_for('auth.options')) return redirect(url_for('auth.options'))
@auth.route('/auth/clan/remove-member/<player_id>', methods=['POST']) @auth.route('/auth/clan/remove-member/<player_id>/<path:world_id>', methods=['POST'])
@login_required @login_required
def remove_member(player_id): def remove_member(player_id, world_id):
conn = get_db() conn = get_db()
clan = conn.execute( clan = conn.execute(
'SELECT id FROM clans WHERE owner_id = ?', (current_user.id,) 'SELECT id FROM clans WHERE owner_id = ?', (current_user.id,)
).fetchone() ).fetchone()
if clan: if clan:
conn.execute( conn.execute(
'DELETE FROM clan_members WHERE clan_id = ? AND player_id = ?', 'DELETE FROM clan_members WHERE clan_id = ? AND player_id = ? AND world_id = ?',
(clan['id'], player_id) (clan['id'], player_id, world_id)
) )
conn.commit() conn.commit()
conn.close() conn.close()
@@ -232,12 +233,12 @@ def remove_member(player_id):
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# POST /auth/clan/update-features/<player_id> # POST /auth/clan/update-features/<player_id>
# ------------------------------------------------------------------ # ------------------------------------------------------------------
@auth.route('/auth/clan/update-features/<player_id>', methods=['POST']) @auth.route('/auth/clan/update-features/<player_id>/<path:world_id>', methods=['POST'])
@login_required @login_required
def update_member_features(player_id): def update_member_features(player_id, world_id):
farm = 'farm' if request.form.get('farm') else None farm = 'farm' if request.form.get('farm') else None
admin = 'admin' if request.form.get('admin') else None admin = 'admin' if request.form.get('admin') else None
atk_planner = 'attack_planner' if request.form.get('attack_planner') else None atk_planner = 'attack_planner' if request.form.get('attack_planner') else None
atk_planner_admin = 'attack_planner_admin' if request.form.get('attack_planner_admin') else None atk_planner_admin = 'attack_planner_admin' if request.form.get('attack_planner_admin') else None
features = ','.join(f for f in [farm, admin, atk_planner, atk_planner_admin] if f) or '' features = ','.join(f for f in [farm, admin, atk_planner, atk_planner_admin] if f) or ''
@@ -248,8 +249,8 @@ def update_member_features(player_id):
).fetchone() ).fetchone()
if clan: if clan:
conn.execute( conn.execute(
'UPDATE clan_members SET features = ? WHERE clan_id = ? AND player_id = ?', 'UPDATE clan_members SET features = ? WHERE clan_id = ? AND player_id = ? AND world_id = ?',
(features, clan['id'], player_id) (features, clan['id'], player_id, world_id)
) )
conn.commit() conn.commit()
conn.close() conn.close()

View File

@@ -287,7 +287,7 @@
</td> </td>
<td> <td>
{% if clan.owner_id == current_user.id %} {% 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 }}/{{ m.world_id }}" style="display:inline;">
<div class="toggle-group"> <div class="toggle-group">
<label class="toggle-label"> <label class="toggle-label">
<input type="checkbox" name="farm" onchange="this.form.submit()" {{ 'checked' if m.feat_farm }}> 🌾 Farm <input type="checkbox" name="farm" onchange="this.form.submit()" {{ 'checked' if m.feat_farm }}> 🌾 Farm
@@ -316,8 +316,8 @@
<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 %} {% 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 }}/{{ m.world_id }}"
onsubmit="return confirm('Αφαίρεση παίκτη {{ m.player_name }}?');"> onsubmit="return confirm('Αφαίρεση {{ m.player_name }} ({{ m.world_id }})?');">
<button type="submit" class="btn-danger">Αφαίρεση</button> <button type="submit" class="btn-danger">Αφαίρεση</button>
</form> </form>
{% endif %} {% endif %}