mirror of
https://github.com/chenasraf/nextcloud-forum.git
synced 2026-05-18 01:28:58 +00:00
251 lines
6.9 KiB
PHP
251 lines
6.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
// SPDX-FileCopyrightText: Chen Asraf <contact@casraf.dev>
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
namespace OCA\Forum\Service;
|
|
|
|
use OCA\Forum\Db\BBCodeMapper;
|
|
use OCA\Forum\Db\RoleMapper;
|
|
use OCA\Forum\Db\UserRoleMapper;
|
|
use OCA\Forum\Db\UserStatsMapper;
|
|
use OCP\AppFramework\Db\DoesNotExistException;
|
|
use OCP\IL10N;
|
|
use OCP\IUserManager;
|
|
|
|
/**
|
|
* Service for user enrichment and display logic
|
|
* Handles Nextcloud user lookups and deleted user display
|
|
*/
|
|
class UserService {
|
|
public function __construct(
|
|
private IUserManager $userManager,
|
|
private UserStatsMapper $userStatsMapper,
|
|
private RoleMapper $roleMapper,
|
|
private UserRoleMapper $userRoleMapper,
|
|
private BBCodeMapper $bbCodeMapper,
|
|
private BBCodeService $bbCodeService,
|
|
private IL10N $l10n,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Get display name for a user
|
|
* Returns "Deleted User" if user doesn't exist in Nextcloud
|
|
*/
|
|
public function getUserDisplayName(string $userId): string {
|
|
$user = $this->userManager->get($userId);
|
|
if ($user !== null) {
|
|
return $user->getDisplayName();
|
|
}
|
|
|
|
// User doesn't exist in Nextcloud - return generic deleted user name
|
|
return $this->l10n->t('Deleted user');
|
|
}
|
|
|
|
/**
|
|
* Check if a user has been deleted
|
|
* Checks both Nextcloud user existence and user_stats deleted_at flag
|
|
*/
|
|
public function isUserDeleted(string $userId): bool {
|
|
// First check if user exists in Nextcloud
|
|
$user = $this->userManager->get($userId);
|
|
if ($user === null) {
|
|
return true;
|
|
}
|
|
|
|
// Check if marked as deleted in user_stats
|
|
try {
|
|
$stats = $this->userStatsMapper->find($userId);
|
|
return $stats->getDeletedAt() !== null;
|
|
} catch (DoesNotExistException $e) {
|
|
// No stats record, user is not deleted (just hasn't posted yet)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enrich user data with display name, deleted status, roles, and signature
|
|
*
|
|
* @param string $userId
|
|
* @param array|null $roles Optional pre-fetched roles array
|
|
* @param array|null $bbcodes Optional pre-fetched BBCode definitions for parsing signatures
|
|
* @return array{userId: string, displayName: string, isDeleted: bool, roles: array, signature: ?string, signatureRaw: ?string}
|
|
*/
|
|
public function enrichUserData(string $userId, ?array $roles = null, ?array $bbcodes = null): array {
|
|
$isDeleted = $this->isUserDeleted($userId);
|
|
$displayName = $this->getUserDisplayName($userId);
|
|
|
|
// If roles not provided, fetch them
|
|
if ($roles === null) {
|
|
$userRoles = $this->userRoleMapper->findByUserId($userId);
|
|
$roles = [];
|
|
foreach ($userRoles as $userRole) {
|
|
try {
|
|
$role = $this->roleMapper->find($userRole->getRoleId());
|
|
$roles[] = $role->jsonSerialize();
|
|
} catch (\Exception $e) {
|
|
// Role not found, skip
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get signature from user stats
|
|
$signatureRaw = null;
|
|
$signature = null;
|
|
try {
|
|
$stats = $this->userStatsMapper->find($userId);
|
|
$signatureRaw = $stats->getSignature();
|
|
if ($signatureRaw !== null && $signatureRaw !== '') {
|
|
// Parse BBCode in signature
|
|
if ($bbcodes === null) {
|
|
$bbcodes = $this->bbCodeMapper->findAllEnabled();
|
|
}
|
|
$signature = $this->bbCodeService->parse($signatureRaw, $bbcodes);
|
|
}
|
|
} catch (DoesNotExistException $e) {
|
|
// No stats record, no signature
|
|
}
|
|
|
|
return [
|
|
'userId' => $userId,
|
|
'displayName' => $displayName,
|
|
'isDeleted' => $isDeleted,
|
|
'roles' => $roles,
|
|
'signature' => $signature,
|
|
'signatureRaw' => $signatureRaw,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Enrich multiple users at once (for performance)
|
|
*
|
|
* @param array<string> $userIds
|
|
* @param array<string, array> $rolesMap Optional pre-fetched roles map (userId => roles[])
|
|
* @param array|null $bbcodes Optional pre-fetched BBCode definitions for parsing signatures
|
|
* @return array<string, array{userId: string, displayName: string, isDeleted: bool, roles: array, signature: ?string, signatureRaw: ?string}>
|
|
*/
|
|
public function enrichMultipleUsers(array $userIds, ?array $rolesMap = null, ?array $bbcodes = null): array {
|
|
$result = [];
|
|
|
|
// If roles not provided, fetch them all at once
|
|
if ($rolesMap === null) {
|
|
$rolesMap = $this->fetchRolesForUsers($userIds);
|
|
}
|
|
|
|
// Fetch all user stats at once for signatures
|
|
$signaturesMap = $this->fetchSignaturesForUsers($userIds);
|
|
|
|
// Fetch BBCodes once for parsing all signatures (if not provided)
|
|
if ($bbcodes === null) {
|
|
$bbcodes = $this->bbCodeMapper->findAllEnabled();
|
|
}
|
|
|
|
foreach ($userIds as $userId) {
|
|
$isDeleted = $this->isUserDeleted($userId);
|
|
$displayName = $this->getUserDisplayName($userId);
|
|
|
|
$signatureRaw = $signaturesMap[$userId] ?? null;
|
|
$signature = null;
|
|
if ($signatureRaw !== null && $signatureRaw !== '') {
|
|
$signature = $this->bbCodeService->parse($signatureRaw, $bbcodes);
|
|
}
|
|
|
|
$result[$userId] = [
|
|
'userId' => $userId,
|
|
'displayName' => $displayName,
|
|
'isDeleted' => $isDeleted,
|
|
'roles' => $rolesMap[$userId] ?? [],
|
|
'signature' => $signature,
|
|
'signatureRaw' => $signatureRaw,
|
|
];
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Fetch roles for multiple users efficiently
|
|
*
|
|
* @param array<string> $userIds
|
|
* @return array<string, array> Map of userId => roles[]
|
|
*/
|
|
private function fetchRolesForUsers(array $userIds): array {
|
|
if (empty($userIds)) {
|
|
return [];
|
|
}
|
|
|
|
$rolesMap = [];
|
|
|
|
// Initialize all user IDs with empty arrays
|
|
foreach ($userIds as $userId) {
|
|
$rolesMap[$userId] = [];
|
|
}
|
|
|
|
// Fetch all user roles for these users
|
|
$userRoles = $this->userRoleMapper->findByUserIds($userIds);
|
|
|
|
// Group by user ID and fetch role details
|
|
$roleIds = [];
|
|
$userRolesByUser = [];
|
|
foreach ($userRoles as $userRole) {
|
|
$userId = $userRole->getUserId();
|
|
$roleId = $userRole->getRoleId();
|
|
|
|
if (!isset($userRolesByUser[$userId])) {
|
|
$userRolesByUser[$userId] = [];
|
|
}
|
|
$userRolesByUser[$userId][] = $roleId;
|
|
$roleIds[$roleId] = true;
|
|
}
|
|
|
|
// Fetch all roles at once
|
|
$roles = [];
|
|
$roleEntities = $this->roleMapper->findByIds(array_keys($roleIds));
|
|
foreach ($roleEntities as $role) {
|
|
$roles[$role->getId()] = $role->jsonSerialize();
|
|
}
|
|
|
|
// Map roles to users
|
|
foreach ($userRolesByUser as $userId => $userRoleIds) {
|
|
foreach ($userRoleIds as $roleId) {
|
|
if (isset($roles[$roleId])) {
|
|
$rolesMap[$userId][] = $roles[$roleId];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $rolesMap;
|
|
}
|
|
|
|
/**
|
|
* Fetch signatures for multiple users efficiently
|
|
*
|
|
* @param array<string> $userIds
|
|
* @return array<string, ?string> Map of userId => signature (raw)
|
|
*/
|
|
private function fetchSignaturesForUsers(array $userIds): array {
|
|
if (empty($userIds)) {
|
|
return [];
|
|
}
|
|
|
|
$signaturesMap = [];
|
|
|
|
// Initialize all user IDs with null
|
|
foreach ($userIds as $userId) {
|
|
$signaturesMap[$userId] = null;
|
|
}
|
|
|
|
// Fetch all user stats for these users
|
|
$userStats = $this->userStatsMapper->findByUserIds($userIds);
|
|
|
|
// Extract signatures
|
|
foreach ($userStats as $stats) {
|
|
$signaturesMap[$stats->getUserId()] = $stats->getSignature();
|
|
}
|
|
|
|
return $signaturesMap;
|
|
}
|
|
}
|