Refactor admin/user isolation logic and model methods

Moved admin/user isolation checks and related methods from Domain and NotificationGroup models to User model for better separation of concerns. Replaced direct database queries in controllers and services with new model methods. Added methods for assigning unassigned domains/groups, searching domains, and clearing old notification logs. Updated views for improved UI consistency.
This commit is contained in:
Hosteroid
2025-10-20 17:25:02 +03:00
parent 6fbed15c7d
commit 0d4a38aae8
10 changed files with 163 additions and 126 deletions

View File

@@ -8,6 +8,14 @@ class Domain extends Model
{
protected static string $table = 'domains';
/**
* Get User model instance
*/
private function getUserModel(): \App\Models\User
{
return new \App\Models\User();
}
/**
* Get all domains with their notification group
*/
@@ -17,7 +25,7 @@ class Domain extends Model
FROM domains d
LEFT JOIN notification_groups ng ON d.notification_group_id = ng.id";
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$sql .= " WHERE d.user_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
@@ -44,7 +52,7 @@ class Domain extends Model
$params = [$days];
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$sql .= " AND d.user_id = ?";
$params[] = $userId;
}
@@ -68,7 +76,7 @@ class Domain extends Model
$params = [$status];
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$sql .= " AND d.user_id = ?";
$params[] = $userId;
}
@@ -132,7 +140,7 @@ class Domain extends Model
$params = [];
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$sql .= " AND d.user_id = ?";
$params[] = $userId;
}
@@ -162,7 +170,7 @@ class Domain extends Model
$whereClause = "WHERE is_active = 1";
$params = [];
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$whereClause .= " AND user_id = ?";
$params[] = $userId;
}
@@ -183,7 +191,7 @@ class Domain extends Model
$inactiveWhereClause = "WHERE is_active = 0";
$inactiveParams = [];
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$inactiveWhereClause .= " AND user_id = ?";
$inactiveParams[] = $userId;
}
@@ -297,7 +305,7 @@ class Domain extends Model
$sql = "SELECT DISTINCT tags FROM domains WHERE tags IS NOT NULL AND tags != ''";
$params = [];
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$sql .= " AND user_id = ?";
$params[] = $userId;
}
@@ -320,28 +328,62 @@ class Domain extends Model
return $allTags;
}
/**
* Check if user is admin
* Assign all domains without user_id to a specific user
*/
private function isAdmin(?int $userId): bool
public function assignUnassignedDomainsToUser(int $userId): int
{
if (!$userId) {
return false;
}
$stmt = $this->db->prepare("SELECT role FROM users WHERE id = ?");
$stmt = $this->db->prepare("UPDATE domains SET user_id = ? WHERE user_id IS NULL");
$stmt->execute([$userId]);
$user = $stmt->fetch();
return $user && $user['role'] === 'admin';
return $stmt->rowCount();
}
/**
* Get first admin user
* Search domains for suggestions (quick search)
*/
public function getFirstAdminUser(): ?array
public function searchSuggestions(string $query, int $limit = 5): array
{
$stmt = $this->db->query("SELECT * FROM users WHERE role = 'admin' ORDER BY id ASC LIMIT 1");
return $stmt->fetch() ?: null;
$sql = "SELECT d.id, d.domain_name, d.registrar, d.expiration_date, d.status, ng.name as group_name
FROM domains d
LEFT JOIN notification_groups ng ON d.notification_group_id = ng.id
WHERE d.domain_name LIKE ?
OR d.registrar LIKE ?
ORDER BY d.domain_name ASC
LIMIT ?";
$searchTerm = '%' . $query . '%';
$stmt = $this->db->prepare($sql);
$stmt->execute([$searchTerm, $searchTerm, $limit]);
return $stmt->fetchAll();
}
/**
* Search domains with user isolation support
*/
public function searchDomains(string $query, ?int $userId = null, int $limit = 50): array
{
$sql = "SELECT d.*, ng.name as group_name
FROM domains d
LEFT JOIN notification_groups ng ON d.notification_group_id = ng.id
WHERE (d.domain_name LIKE ?
OR d.registrar LIKE ?
OR ng.name LIKE ?)";
$params = ['%' . $query . '%', '%' . $query . '%', '%' . $query . '%'];
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$sql .= " AND d.user_id = ?";
$params[] = $userId;
}
$sql .= " ORDER BY d.domain_name ASC LIMIT ?";
$params[] = $limit;
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
}

View File

@@ -8,6 +8,14 @@ class NotificationGroup extends Model
{
protected static string $table = 'notification_groups';
/**
* Get User model instance
*/
private function getUserModel(): \App\Models\User
{
return new \App\Models\User();
}
/**
* Get all groups with channel count
*/
@@ -20,7 +28,7 @@ class NotificationGroup extends Model
LEFT JOIN notification_channels nc ON ng.id = nc.notification_group_id
LEFT JOIN domains d ON ng.id = d.notification_group_id";
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$sql .= " WHERE ng.user_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
@@ -44,7 +52,7 @@ class NotificationGroup extends Model
}
// Check if user has access to this group
if ($userId && !$this->isAdmin($userId) && $group['user_id'] != $userId) {
if ($userId && !$this->getUserModel()->isAdmin($userId) && $group['user_id'] != $userId) {
return null;
}
@@ -54,7 +62,7 @@ class NotificationGroup extends Model
// Get domains (filtered by user if needed)
$domainModel = new Domain();
if ($userId && !$this->isAdmin($userId)) {
if ($userId && !$this->getUserModel()->isAdmin($userId)) {
$group['domains'] = $domainModel->where('notification_group_id', $id, $userId);
} else {
$group['domains'] = $domainModel->where('notification_group_id', $id);
@@ -77,28 +85,15 @@ class NotificationGroup extends Model
return $this->delete($id);
}
/**
* Check if user is admin
*/
private function isAdmin(?int $userId): bool
{
if (!$userId) {
return false;
}
$stmt = $this->db->prepare("SELECT role FROM users WHERE id = ?");
$stmt->execute([$userId]);
$user = $stmt->fetch();
return $user && $user['role'] === 'admin';
}
/**
* Get first admin user
* Assign all notification groups without user_id to a specific user
*/
public function getFirstAdminUser(): ?array
public function assignUnassignedGroupsToUser(int $userId): int
{
$stmt = $this->db->query("SELECT * FROM users WHERE role = 'admin' ORDER BY id ASC LIMIT 1");
return $stmt->fetch() ?: null;
$stmt = $this->db->prepare("UPDATE notification_groups SET user_id = ? WHERE user_id IS NULL");
$stmt->execute([$userId]);
return $stmt->rowCount();
}
}

View File

@@ -284,5 +284,17 @@ class Setting extends Model
return $result;
}
/**
* Clear old notification logs
*/
public function clearOldNotificationLogs(int $daysOld = 30): int
{
$stmt = $this->db->prepare(
"DELETE FROM notification_logs WHERE sent_at < DATE_SUB(NOW(), INTERVAL ? DAY)"
);
$stmt->execute([$daysOld]);
return $stmt->rowCount();
}
}

View File

@@ -284,5 +284,58 @@ class User extends Model
$user = $this->find($userId);
return $user && $user['email_verified'];
}
/**
* Check if user is admin
*/
public function isAdmin(?int $userId): bool
{
if (!$userId) {
return false;
}
$stmt = $this->db->prepare("SELECT role FROM users WHERE id = ?");
$stmt->execute([$userId]);
$user = $stmt->fetch();
return $user && $user['role'] === 'admin';
}
/**
* Get first admin user
*/
public function getFirstAdminUser(): ?array
{
$stmt = $this->db->query("SELECT * FROM users WHERE role = 'admin' ORDER BY id ASC LIMIT 1");
return $stmt->fetch() ?: null;
}
/**
* Get all admin users
*/
public function getAllAdmins(): array
{
return $this->where('role', 'admin');
}
/**
* Count admin users
*/
public function countAdmins(): int
{
$stmt = $this->db->query("SELECT COUNT(*) as count FROM users WHERE role = 'admin'");
$result = $stmt->fetch();
return (int)$result['count'];
}
/**
* Find user by verification token (debug version - includes all users regardless of verification status)
*/
public function findByVerificationTokenDebug(string $token): ?array
{
$stmt = $this->db->prepare("SELECT id, email, email_verified, email_verification_token FROM users WHERE email_verification_token = ?");
$stmt->execute([$token]);
$result = $stmt->fetch();
return $result ?: null;
}
}