1
0

Большое обновление

1. Создание личных проектов
2. Управление командой
3. Приглашение участников
4. Уведомления

и многое другое...
This commit is contained in:
2026-01-18 20:17:02 +07:00
parent 250eac70a7
commit 190b4d0a5e
51 changed files with 6179 additions and 426 deletions

View File

@@ -0,0 +1,237 @@
<?php
class ProjectInvite {
const STATUS_PENDING = 'pending';
const STATUS_ACCEPTED = 'accepted';
const STATUS_DECLINED = 'declined';
// ==================== СОЗДАНИЕ ПРИГЛАШЕНИЯ ====================
/**
* Создать приглашение в проект
*/
public static function create(int $project_id, int $to_user_id, int $from_user_id, bool $is_admin = false, ?array $permissions = null): array {
// Нельзя пригласить себя
if ($to_user_id === $from_user_id) {
return ['success' => false, 'errors' => ['invite' => 'Нельзя пригласить себя в проект']];
}
// Проверяем, что пользователь существует
$user = Database::get('accounts', ['id'], ['id' => $to_user_id]);
if (!$user) {
return ['success' => false, 'errors' => ['invite' => 'Пользователь не найден']];
}
// Проверяем, что пользователь ещё не участник проекта
if (ProjectAccess::isMember($project_id, $to_user_id)) {
return ['success' => false, 'errors' => ['invite' => 'Пользователь уже участник проекта']];
}
// Проверяем, нет ли уже pending-приглашения
if (self::hasPending($project_id, $to_user_id)) {
return ['success' => false, 'errors' => ['invite' => 'Пользователь уже приглашён, ожидается ответ']];
}
// Права по умолчанию
$perms = $permissions ?? ProjectAccess::DEFAULT_PERMISSIONS;
// Сохраняем is_admin в permissions для передачи при accept
$inviteData = [
'is_admin' => $is_admin,
'permissions' => $perms
];
Database::insert('project_invites', [
'id_project' => $project_id,
'id_from_user' => $from_user_id,
'id_to_user' => $to_user_id,
'status' => self::STATUS_PENDING,
'permissions' => json_encode($inviteData),
'created_at' => date('Y-m-d H:i:s')
]);
return ['success' => true, 'id' => Database::id()];
}
// ==================== ПРОВЕРКИ ====================
/**
* Есть ли pending-приглашение для пользователя в проект
*/
public static function hasPending(int $project_id, int $to_user_id): bool {
return Database::has('project_invites', [
'id_project' => $project_id,
'id_to_user' => $to_user_id,
'status' => self::STATUS_PENDING
]);
}
/**
* Получить количество pending-приглашений для пользователя
*/
public static function getPendingCount(int $user_id): int {
return Database::count('project_invites', [
'id_to_user' => $user_id,
'status' => self::STATUS_PENDING
]);
}
// ==================== ПОЛУЧЕНИЕ ПРИГЛАШЕНИЙ ====================
/**
* Получить все pending-приглашения для пользователя (входящие)
*/
public static function getMyPending(int $user_id): array {
$invites = Database::select('project_invites', [
'[>]project' => ['id_project' => 'id'],
'[>]accounts' => ['id_from_user' => 'id']
], [
'project_invites.id',
'project_invites.id_project',
'project_invites.created_at',
'project_invites.permissions',
'project.name(project_name)',
'accounts.name(from_user_name)',
'accounts.username(from_user_username)',
'accounts.avatar_url(from_user_avatar)'
], [
'project_invites.id_to_user' => $user_id,
'project_invites.status' => self::STATUS_PENDING,
'ORDER' => ['project_invites.created_at' => 'DESC']
]);
return array_map(function($invite) {
$permData = $invite['permissions'] ? json_decode($invite['permissions'], true) : [];
return [
'id' => (int)$invite['id'],
'project_id' => (int)$invite['id_project'],
'project_name' => $invite['project_name'],
'from_user' => [
'name' => $invite['from_user_name'],
'username' => $invite['from_user_username'],
'avatar_url' => $invite['from_user_avatar']
],
'is_admin' => $permData['is_admin'] ?? false,
'created_at' => $invite['created_at']
];
}, $invites);
}
/**
* Получить pending-приглашения для проекта (для админа)
*/
public static function getProjectPending(int $project_id): array {
$invites = Database::select('project_invites', [
'[>]accounts' => ['id_to_user' => 'id']
], [
'project_invites.id',
'project_invites.id_to_user',
'project_invites.created_at',
'project_invites.permissions',
'accounts.name',
'accounts.username',
'accounts.avatar_url'
], [
'project_invites.id_project' => $project_id,
'project_invites.status' => self::STATUS_PENDING,
'ORDER' => ['project_invites.created_at' => 'DESC']
]);
return array_map(function($invite) {
$permData = $invite['permissions'] ? json_decode($invite['permissions'], true) : [];
return [
'id' => (int)$invite['id'],
'id_user' => (int)$invite['id_to_user'],
'name' => $invite['name'],
'username' => $invite['username'],
'avatar_url' => $invite['avatar_url'],
'is_admin' => $permData['is_admin'] ?? false,
'created_at' => $invite['created_at'],
'status' => 'pending'
];
}, $invites);
}
// ==================== ОТВЕТ НА ПРИГЛАШЕНИЕ ====================
/**
* Принять приглашение
*/
public static function accept(int $invite_id, int $user_id): array {
$invite = Database::get('project_invites', '*', [
'id' => $invite_id,
'id_to_user' => $user_id,
'status' => self::STATUS_PENDING
]);
if (!$invite) {
return ['success' => false, 'errors' => ['invite' => 'Приглашение не найдено или уже обработано']];
}
$project_id = (int)$invite['id_project'];
$permData = $invite['permissions'] ? json_decode($invite['permissions'], true) : [];
$is_admin = $permData['is_admin'] ?? false;
$permissions = $permData['permissions'] ?? ProjectAccess::DEFAULT_PERMISSIONS;
// Добавляем в project_members
Database::insert('project_members', [
'id_project' => $project_id,
'id_user' => $user_id,
'is_admin' => $is_admin ? 1 : 0,
'permissions' => json_encode($permissions),
'created_at' => date('Y-m-d H:i:s')
]);
// Обновляем статус приглашения
Database::update('project_invites', [
'status' => self::STATUS_ACCEPTED,
'responded_at' => date('Y-m-d H:i:s')
], ['id' => $invite_id]);
return ['success' => true, 'project_id' => $project_id];
}
/**
* Отклонить приглашение
*/
public static function decline(int $invite_id, int $user_id): array {
$invite = Database::get('project_invites', ['id'], [
'id' => $invite_id,
'id_to_user' => $user_id,
'status' => self::STATUS_PENDING
]);
if (!$invite) {
return ['success' => false, 'errors' => ['invite' => 'Приглашение не найдено или уже обработано']];
}
Database::update('project_invites', [
'status' => self::STATUS_DECLINED,
'responded_at' => date('Y-m-d H:i:s')
], ['id' => $invite_id]);
return ['success' => true];
}
/**
* Отменить приглашение (для админа)
*/
public static function cancel(int $invite_id, int $project_id): array {
$invite = Database::get('project_invites', ['id'], [
'id' => $invite_id,
'id_project' => $project_id,
'status' => self::STATUS_PENDING
]);
if (!$invite) {
return ['success' => false, 'errors' => ['invite' => 'Приглашение не найдено']];
}
Database::delete('project_invites', ['id' => $invite_id]);
return ['success' => true];
}
}
?>