modified: .gitignore
This commit is contained in:
@@ -93,7 +93,7 @@ PANEL_SCHEMA = [
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
group_id INT NOT NULL,
|
||||
role ENUM('admin','member') DEFAULT 'member',
|
||||
role ENUM('group_owner','group_admin','moderator','viewer','auditor','admin','member') DEFAULT 'viewer',
|
||||
permissions JSON,
|
||||
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uq_user_group (user_id, group_id),
|
||||
@@ -106,11 +106,13 @@ PANEL_SCHEMA = [
|
||||
group_id INT NOT NULL,
|
||||
invited_username VARCHAR(50) NOT NULL,
|
||||
invited_email VARCHAR(255) NOT NULL,
|
||||
role ENUM('admin','member') DEFAULT 'member',
|
||||
role ENUM('group_owner','group_admin','moderator','viewer','auditor','admin','member') DEFAULT 'viewer',
|
||||
token VARCHAR(128) UNIQUE NOT NULL,
|
||||
created_by_user_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at DATETIME NOT NULL,
|
||||
last_sent_at DATETIME NULL,
|
||||
send_count INT NOT NULL DEFAULT 0,
|
||||
accepted_at DATETIME NULL,
|
||||
revoked_at DATETIME NULL,
|
||||
UNIQUE KEY uq_group_pending_invite_email (group_id, invited_email, revoked_at, accepted_at),
|
||||
@@ -153,6 +155,27 @@ def init_databases():
|
||||
with panel.cursor() as cur:
|
||||
for stmt in PANEL_SCHEMA:
|
||||
cur.execute(stmt)
|
||||
# Best-effort migrations for existing installs.
|
||||
try:
|
||||
cur.execute(
|
||||
"ALTER TABLE group_members MODIFY role ENUM('group_owner','group_admin','moderator','viewer','auditor','admin','member') DEFAULT 'viewer'"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
cur.execute(
|
||||
"ALTER TABLE group_invites MODIFY role ENUM('group_owner','group_admin','moderator','viewer','auditor','admin','member') DEFAULT 'viewer'"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
cur.execute("ALTER TABLE group_invites ADD COLUMN last_sent_at DATETIME NULL")
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
cur.execute("ALTER TABLE group_invites ADD COLUMN send_count INT NOT NULL DEFAULT 0")
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
panel.close()
|
||||
|
||||
@@ -178,7 +201,7 @@ def create_user(username: str, email: str, password: str, is_site_admin: bool =
|
||||
)
|
||||
|
||||
|
||||
def create_user_for_group(username: str, email: str, password: str, group_id: int, role: str = "member") -> int:
|
||||
def create_user_for_group(username: str, email: str, password: str, group_id: int, role: str = "viewer") -> int:
|
||||
"""Create a non-site-admin user and assign them to a group atomically."""
|
||||
permissions = Config.DEFAULT_PERMISSIONS
|
||||
salt = generate_salt()
|
||||
@@ -210,8 +233,8 @@ def create_group_invite(group_id: int, username: str, email: str, role: str, cre
|
||||
expires_at = datetime.utcnow() + timedelta(hours=Config.INVITE_EXPIRY_HOURS)
|
||||
token = secrets.token_urlsafe(32)
|
||||
_panel_query(
|
||||
"INSERT INTO group_invites (group_id, invited_username, invited_email, role, token, created_by_user_id, expires_at) "
|
||||
"VALUES (%s,%s,%s,%s,%s,%s,%s)",
|
||||
"INSERT INTO group_invites (group_id, invited_username, invited_email, role, token, created_by_user_id, expires_at, last_sent_at, send_count) "
|
||||
"VALUES (%s,%s,%s,%s,%s,%s,%s,NULL,0)",
|
||||
(group_id, username, email, role, token, created_by_user_id, expires_at),
|
||||
write=True,
|
||||
)
|
||||
@@ -229,6 +252,15 @@ def list_active_group_invites(group_id: int):
|
||||
)
|
||||
|
||||
|
||||
def count_active_group_invites(group_id: int) -> int:
|
||||
row = _panel_query(
|
||||
"SELECT COUNT(*) AS c FROM group_invites WHERE group_id=%s AND accepted_at IS NULL AND revoked_at IS NULL AND expires_at > UTC_TIMESTAMP()",
|
||||
(group_id,),
|
||||
fetchone=True,
|
||||
)
|
||||
return int(row["c"]) if row else 0
|
||||
|
||||
|
||||
def get_active_invite_by_email(group_id: int, email: str):
|
||||
return _panel_query(
|
||||
"SELECT * FROM group_invites WHERE group_id=%s AND invited_email=%s "
|
||||
@@ -238,6 +270,23 @@ def get_active_invite_by_email(group_id: int, email: str):
|
||||
)
|
||||
|
||||
|
||||
def get_active_invite_by_username(group_id: int, username: str):
|
||||
return _panel_query(
|
||||
"SELECT * FROM group_invites WHERE group_id=%s AND invited_username=%s "
|
||||
"AND accepted_at IS NULL AND revoked_at IS NULL AND expires_at > UTC_TIMESTAMP()",
|
||||
(group_id, username),
|
||||
fetchone=True,
|
||||
)
|
||||
|
||||
|
||||
def get_group_invite_by_id(invite_id: int, group_id: int):
|
||||
return _panel_query(
|
||||
"SELECT * FROM group_invites WHERE id=%s AND group_id=%s",
|
||||
(invite_id, group_id),
|
||||
fetchone=True,
|
||||
)
|
||||
|
||||
|
||||
def get_invite_by_token(token: str):
|
||||
return _panel_query(
|
||||
"SELECT gi.*, g.name AS group_name, u.username AS created_by_username "
|
||||
@@ -258,6 +307,14 @@ def revoke_group_invite(invite_id: int, group_id: int):
|
||||
)
|
||||
|
||||
|
||||
def mark_group_invite_sent(invite_id: int, group_id: int):
|
||||
_panel_query(
|
||||
"UPDATE group_invites SET last_sent_at=UTC_TIMESTAMP(), send_count=send_count+1 WHERE id=%s AND group_id=%s",
|
||||
(invite_id, group_id),
|
||||
write=True,
|
||||
)
|
||||
|
||||
|
||||
def accept_group_invite(token: str, password: str) -> dict | None:
|
||||
invite = get_invite_by_token(token)
|
||||
if not invite:
|
||||
@@ -422,7 +479,7 @@ def get_group_members(group_id: int):
|
||||
)
|
||||
|
||||
|
||||
def add_group_member(user_id: int, group_id: int, role: str = "member", permissions: dict = None):
|
||||
def add_group_member(user_id: int, group_id: int, role: str = "viewer", permissions: dict = None):
|
||||
if permissions is None:
|
||||
permissions = Config.DEFAULT_PERMISSIONS
|
||||
_panel_query(
|
||||
|
||||
Reference in New Issue
Block a user