Replace old team system with work teams (equipos de trabajo)

- New migration 003_teams.sql: teams, team_user, team_server tables
- New Team model with CRUD, members, and server assignment
- New TeamController with full team management
- New views: teams/index, teams/create, teams/show
- Server model: getUserRole and getAccessibleServerIds now include team-based access
- Sidebar: Teams link under Administration (admin+ only)
- Routes: old /team routes removed, new /teams routes added
- Removed old ServerController team methods and views
- Fixed sidebar empty accessible IDs returning all servers
- Fixed dashboard and API to show empty when no accessible servers
This commit is contained in:
2026-06-07 07:08:26 -04:00
parent 5f5de248c6
commit 5607a3e507
14 changed files with 941 additions and 418 deletions

155
src/Models/Team.php Normal file
View File

@@ -0,0 +1,155 @@
<?php
declare(strict_types=1);
namespace ServerManager\Models;
use ServerManager\Core\Database;
use ServerManager\Core\Session;
class Team
{
private Database $db;
public function __construct()
{
$this->db = Database::getInstance();
}
public function findAll(): array
{
return $this->db->fetchAll(
'SELECT t.*,
(SELECT COUNT(*) FROM team_user WHERE team_id = t.id) AS member_count,
(SELECT COUNT(*) FROM team_server WHERE team_id = t.id) AS server_count
FROM teams t
ORDER BY t.name ASC'
);
}
public function findById(int $id): ?array
{
$team = $this->db->fetch(
'SELECT t.*,
(SELECT COUNT(*) FROM team_user WHERE team_id = t.id) AS member_count,
(SELECT COUNT(*) FROM team_server WHERE team_id = t.id) AS server_count
FROM teams t WHERE t.id = ?',
[$id]
);
return $team ?: null;
}
public function create(array $data): int
{
$data['created_by'] = (int) Session::get('user_id');
$data['created_at'] = date('Y-m-d H:i:s');
$data['updated_at'] = date('Y-m-d H:i:s');
return $this->db->insert('teams', $data);
}
public function update(int $id, array $data): bool
{
$data['updated_at'] = date('Y-m-d H:i:s');
return $this->db->update('teams', $data, 'id = ?', [$id]) > 0;
}
public function delete(int $id): bool
{
return $this->db->delete('teams', 'id = ?', [$id]) > 0;
}
public function getMembers(int $teamId): array
{
return $this->db->fetchAll(
'SELECT tu.*, u.username, u.email
FROM team_user tu
JOIN users u ON tu.user_id = u.id
WHERE tu.team_id = ?
ORDER BY u.username ASC',
[$teamId]
);
}
public function addMember(int $teamId, int $userId): bool
{
$existing = $this->db->fetch(
'SELECT id FROM team_user WHERE team_id = ? AND user_id = ?',
[$teamId, $userId]
);
if ($existing) {
return false;
}
$this->db->insert('team_user', [
'team_id' => $teamId,
'user_id' => $userId,
]);
return true;
}
public function removeMember(int $teamId, int $userId): bool
{
return $this->db->delete(
'team_user',
'team_id = ? AND user_id = ?',
[$teamId, $userId]
) > 0;
}
public function getServers(int $teamId): array
{
return $this->db->fetchAll(
'SELECT ts.*, s.name AS server_name, s.ip_address
FROM team_server ts
JOIN servers s ON ts.server_id = s.id
WHERE ts.team_id = ?
ORDER BY s.name ASC',
[$teamId]
);
}
public function addServer(int $teamId, int $serverId, string $role): bool
{
if (!in_array($role, ['viewer', 'manager'], true)) {
return false;
}
$existing = $this->db->fetch(
'SELECT id FROM team_server WHERE team_id = ? AND server_id = ?',
[$teamId, $serverId]
);
if ($existing) {
return false;
}
$this->db->insert('team_server', [
'team_id' => $teamId,
'server_id' => $serverId,
'role' => $role,
]);
return true;
}
public function removeServer(int $teamId, int $serverId): bool
{
return $this->db->delete(
'team_server',
'team_id = ? AND server_id = ?',
[$teamId, $serverId]
) > 0;
}
public function updateServerRole(int $teamId, int $serverId, string $role): bool
{
if (!in_array($role, ['viewer', 'manager'], true)) {
return false;
}
return $this->db->update(
'team_server',
['role' => $role],
'team_id = ? AND server_id = ?',
[$teamId, $serverId]
) > 0;
}
}