exec("ALTER TABLE users ADD COLUMN profile_pic TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE users ADD COLUMN waha_endpoint TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE users ADD COLUMN waha_chat_id TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE users ADD COLUMN waha_session TEXT DEFAULT 'default'"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE users ADD COLUMN waha_api_key TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE users ADD COLUMN waha_template_task TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE users ADD COLUMN waha_template_note TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE users ADD COLUMN waha_template_password TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE users ADD COLUMN waha_template_file TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN notify_channels TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN waha_endpoint TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN waha_chat_id TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN waha_api_key TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN waha_session TEXT DEFAULT 'default'"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN waha_template_task TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN waha_template_note TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN waha_template_password TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN waha_template_file TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE groups ADD COLUMN profile_pic TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("CREATE TABLE IF NOT EXISTS system_config (k TEXT PRIMARY KEY, v TEXT)"); $pdo->exec("INSERT OR IGNORE INTO system_config (k, v) VALUES ('completed_days', '7')"); $pdo->exec("INSERT OR IGNORE INTO system_config (k, v) VALUES ('archived_days', '90')"); } catch(Exception $e) {} // ── Handle POST ─────────────────────────────────────────────────────────────── $success_msg = ''; $error_msg = ''; if($_SERVER['REQUEST_METHOD'] === 'POST') { if(isset($_POST['create_user'])) { $username = trim($_POST['username']); $pass = password_hash($_POST['password'], PASSWORD_DEFAULT); $is_admin = isset($_POST['is_admin']) ? 1 : 0; try { $stmt = $pdo->prepare("INSERT INTO users (username, password_hash, is_admin) VALUES (?, ?, ?)"); $stmt->execute([$username, $pass, $is_admin]); $success_msg = "User '{$username}' created successfully!"; } catch(Exception $e) { $error_msg = "Error: Username may already exist."; } } if(isset($_POST['delete_user'])) { $del_id = (int)$_POST['del_user_id']; if($del_id != $user_id) { $pdo->prepare("DELETE FROM users WHERE id=?")->execute([$del_id]); $success_msg = "User deleted."; } else { $error_msg = "You cannot delete your own account."; } } if(isset($_POST['toggle_admin'])) { $tid = (int)$_POST['toggle_user_id']; $newVal = (int)$_POST['new_admin_val']; if($tid != $user_id) { $pdo->prepare("UPDATE users SET is_admin=? WHERE id=?")->execute([$newVal, $tid]); $success_msg = "User admin status updated."; } } if(isset($_POST['create_group'])) { try { $name = trim($_POST['group_name']); $pic_path = null; if(isset($_FILES['group_pic']) && $_FILES['group_pic']['error'] === UPLOAD_ERR_OK) { $ext = pathinfo($_FILES['group_pic']['name'], PATHINFO_EXTENSION); $pic_path = 'uploads/group_' . time() . '_' . uniqid() . '.' . $ext; move_uploaded_file($_FILES['group_pic']['tmp_name'], $pic_path); } $stmt = $pdo->prepare("INSERT INTO groups (name, profile_pic) VALUES (?, ?)"); $stmt->execute([$name, $pic_path]); $success_msg = "Group '{$name}' created!"; } catch(Exception $e) { $error_msg = "Error: Group name may already exist."; } } if(isset($_POST['delete_group'])) { $gid = (int)$_POST['del_group_id']; $pdo->prepare("DELETE FROM groups WHERE id=?")->execute([$gid]); $success_msg = "Group deleted."; } if(isset($_POST['assign_group'])) { $stmt = $pdo->prepare("INSERT OR IGNORE INTO user_groups (user_id, group_id) VALUES (?, ?)"); $stmt->execute([$_POST['user_id'], $_POST['group_id']]); $success_msg = "User assigned to group."; } if(isset($_POST['remove_from_group'])) { $pdo->prepare("DELETE FROM user_groups WHERE user_id=? AND group_id=?")->execute([$_POST['user_id'], $_POST['group_id']]); $success_msg = "User removed from group."; } if(isset($_POST['update_user_channels'])) { $ch = $_POST['channels'] ?? []; $ch_str = is_array($ch) ? implode(',', $ch) : ''; $waha_ep = trim($_POST['waha_endpoint'] ?? ''); $waha_cid = trim($_POST['waha_chat_id'] ?? ''); $waha_ses = trim($_POST['waha_session'] ?? '') ?: 'default'; $waha_key = trim($_POST['waha_api_key'] ?? ''); $tpl_task = trim($_POST['waha_template_task'] ?? ''); $tpl_note = trim($_POST['waha_template_note'] ?? ''); $tpl_pass = trim($_POST['waha_template_password'] ?? ''); $tpl_file = trim($_POST['waha_template_file'] ?? ''); $stmt = $pdo->prepare("UPDATE users SET notify_channels=?, telegram_id=?, email=?, whatsapp_number=?, waha_endpoint=?, waha_chat_id=?, waha_template_task=?, waha_template_note=?, waha_template_password=?, waha_template_file=?, waha_session=?, waha_api_key=? WHERE id=?"); $stmt->execute([$ch_str, $_POST['telegram_id'], $_POST['email'], $_POST['whatsapp_number'], $waha_ep ?: null, $waha_cid ?: null, $tpl_task ?: null, $tpl_note ?: null, $tpl_pass ?: null, $tpl_file ?: null, $waha_ses, $waha_key ?: null, $_POST['user_id']]); $success_msg = "User notification preferences updated!"; } if(isset($_POST['update_group_channels'])) { $ch = $_POST['channels'] ?? []; $ch_str = is_array($ch) ? implode(',', $ch) : ''; $waha_ep = trim($_POST['waha_endpoint'] ?? ''); $waha_cid = trim($_POST['waha_chat_id'] ?? ''); $waha_ses = trim($_POST['waha_session'] ?? '') ?: 'default'; $waha_key = trim($_POST['waha_api_key'] ?? ''); $tpl_task = trim($_POST['waha_template_task'] ?? ''); $tpl_note = trim($_POST['waha_template_note'] ?? ''); $tpl_pass = trim($_POST['waha_template_password'] ?? ''); $tpl_file = trim($_POST['waha_template_file'] ?? ''); $group_id = $_POST['group_id']; $name = trim($_POST['group_name'] ?? ''); // Handle profile pic update $pic_sql = ""; $pic_params = []; if(isset($_POST['remove_pic']) && $_POST['remove_pic'] == '1') { $old = query("SELECT profile_pic FROM groups WHERE id=?", [$group_id])->fetch(); if($old && $old['profile_pic'] && file_exists($old['profile_pic'])) @unlink($old['profile_pic']); $pic_sql = ", profile_pic = NULL"; } elseif(isset($_FILES['group_pic']) && $_FILES['group_pic']['error'] === UPLOAD_ERR_OK) { $old = query("SELECT profile_pic FROM groups WHERE id=?", [$group_id])->fetch(); if($old && $old['profile_pic'] && file_exists($old['profile_pic'])) @unlink($old['profile_pic']); $ext = pathinfo($_FILES['group_pic']['name'], PATHINFO_EXTENSION); $new_path = 'uploads/group_' . time() . '_' . uniqid() . '.' . $ext; move_uploaded_file($_FILES['group_pic']['tmp_name'], $new_path); $pic_sql = ", profile_pic = ?"; $pic_params[] = $new_path; } $sql = "UPDATE groups SET notify_channels=?, waha_endpoint=?, waha_chat_id=?, waha_template_task=?, waha_template_note=?, waha_template_password=?, waha_template_file=?, waha_session=?, waha_api_key=?, name=? $pic_sql WHERE id=?"; try { $stmt = $pdo->prepare($sql); $stmt->execute(array_merge([$ch_str, $waha_ep ?: null, $waha_cid ?: null, $tpl_task ?: null, $tpl_note ?: null, $tpl_pass ?: null, $tpl_file ?: null, $waha_ses, $waha_key ?: null, $name], $pic_params, [$group_id])); $success_msg = "Group settings updated!"; } catch(Exception $e) { $error_msg = "Error: Group name may already exist."; } } if(isset($_POST['update_sys_config'])) { $stmt = $pdo->prepare("UPDATE system_config SET v=? WHERE k=?"); $stmt->execute([$_POST['completed_days'] ?? 7, 'completed_days']); $stmt->execute([$_POST['archived_days'] ?? 90, 'archived_days']); $success_msg = "System configuration saved!"; } } // ── Fetch Data ──────────────────────────────────────────────────────────────── $users = query("SELECT id, username, is_admin, notify_channels, telegram_id, email, whatsapp_number, profile_pic, waha_endpoint, waha_chat_id, waha_template_task, waha_template_note, waha_template_password, waha_template_file, waha_session, waha_api_key FROM users ORDER BY is_admin DESC, username ASC")->fetchAll(); $all_groups = query("SELECT * FROM groups ORDER BY name")->fetchAll(); $conf_comp = query("SELECT v FROM system_config WHERE k='completed_days'")->fetchColumn() ?: 7; $conf_arch = query("SELECT v FROM system_config WHERE k='archived_days'")->fetchColumn() ?: 90; $waha_endpoint = query("SELECT v FROM system_config WHERE k='waha_endpoint'")->fetchColumn() ?: ''; $waha_chat_id = query("SELECT v FROM system_config WHERE k='waha_chat_id'")->fetchColumn() ?: ''; $waha_template = query("SELECT v FROM system_config WHERE k='waha_template'")->fetchColumn() ?: ''; // Activity stats for admin $total_users = count($users); $total_groups = count($all_groups); $total_tasks = query("SELECT COUNT(*) FROM tasks")->fetchColumn(); $total_notes = 0; try { $total_notes = query("SELECT COUNT(*) FROM notes")->fetchColumn(); } catch(Exception $e) {} $total_passwords = query("SELECT COUNT(*) FROM passwords")->fetchColumn(); $total_projects = query("SELECT COUNT(*) FROM projects")->fetchColumn(); // Activity log (recent, all users) $recent_activity = []; try { $recent_activity = $pdo->query("SELECT al.*, u.username FROM activity_log al LEFT JOIN users u ON al.user_id=u.id ORDER BY al.created_at DESC LIMIT 20")->fetchAll(); } catch(Exception $e) {} $active_tab = $_GET['tab'] ?? 'overview'; ?>

Admin Panel

ADMIN

🕓 Recent Platform Activity

No activity recorded yet.

·

Create New User

All Users ()

fetchAll(); ?>
htmlspecialchars($g['name']), $groups_of_u)) ?> No groups
(You)

Create Group

Assign User to Group

All Groups ()

No groups created yet.

prepare("SELECT u.id, u.username FROM users u JOIN user_groups ug ON u.id=ug.user_id WHERE ug.group_id=?"); $stmt->execute([$g['id']]); $g_users = $stmt->fetchAll(); ?>
member

No members yet.

User Notification Channels

Configure notification channels per user. WAHA settings appear when WhatsApp is enabled.

WAHA WhatsApp API Settings
Variables: {action} {module} {item} {user} {attachment_count} {due_date} {created_date} {updated_date} {assignor} {assignee}

Group Notification Channels

Configure notification channels for an entire group. WAHA settings appear when WhatsApp is enabled.

Group
WAHA WhatsApp API Settings
Variables: {action} {module} {item} {user} {attachment_count} {due_date} {created_date} {updated_date} {assignor} {assignee}

Kanban Auto-Archive Settings

Control how long tasks stay in Completed or Archived states before being moved/deleted.

Default: 7 days (before auto-moving to Archive)
Default: 90 days (before permanent deletion)

Danger Zone

These actions are irreversible. Proceed with extreme caution.