mirror of
https://github.com/chenasraf/nextcloud-forum.git
synced 2026-05-18 01:28:58 +00:00
Implement opt-in guest access system allowing unauthenticated users to view forum content with configurable permissions. Features Added: - Guest access toggle in admin settings for forum-wide control - Guest role with configurable category-level permissions (view/post/reply) - Role type system (admin, moderator, default, guest, custom) for enhanced access control - Public page support in routing with automatic redirect to login when disabled - Public settings API endpoint for unauthenticated access to forum metadata - Guest role permissions UI in admin panel with clear capability restrictions - Database migration with automatic role type assignment and guest role seeding Security & Permission Improvements: - Permission middleware now validates permissions on public pages instead of skipping checks - Admin/moderator roles have full access; guest/default roles restricted from moderation - Guest role cannot be assigned to authenticated users Breaking Changes: - Forum title/subtitle moved from system config to app config (auto-migrated) - Permission middleware behavior changed for PublicPage routes (now checks permissions)
164 lines
4.2 KiB
PHP
164 lines
4.2 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\Db;
|
|
|
|
use OCA\Forum\AppInfo\Application;
|
|
use OCP\AppFramework\Db\DoesNotExistException;
|
|
use OCP\AppFramework\Db\QBMapper;
|
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
|
use OCP\IDBConnection;
|
|
|
|
/**
|
|
* @template-extends QBMapper<Role>
|
|
*/
|
|
class RoleMapper extends QBMapper {
|
|
public function __construct(
|
|
IDBConnection $db,
|
|
) {
|
|
parent::__construct($db, Application::tableName('forum_roles'), Role::class);
|
|
}
|
|
|
|
/**
|
|
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
|
* @throws DoesNotExistException
|
|
*/
|
|
public function find(int $id): Role {
|
|
/* @var $qb IQueryBuilder */
|
|
$qb = $this->db->getQueryBuilder();
|
|
$qb->select('*')
|
|
->from($this->getTableName())
|
|
->where(
|
|
$qb->expr()
|
|
->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))
|
|
);
|
|
return $this->findEntity($qb);
|
|
}
|
|
|
|
/**
|
|
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
|
* @throws DoesNotExistException
|
|
*/
|
|
public function findByName(string $name): Role {
|
|
/* @var $qb IQueryBuilder */
|
|
$qb = $this->db->getQueryBuilder();
|
|
$qb->select('*')
|
|
->from($this->getTableName())
|
|
->where(
|
|
$qb->expr()
|
|
->eq('name', $qb->createNamedParameter($name, IQueryBuilder::PARAM_STR))
|
|
);
|
|
return $this->findEntity($qb);
|
|
}
|
|
|
|
/**
|
|
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
|
* @throws DoesNotExistException
|
|
*/
|
|
public function findByNameCaseInsensitive(string $name): Role {
|
|
/* @var $qb IQueryBuilder */
|
|
$qb = $this->db->getQueryBuilder();
|
|
$qb->select('*')
|
|
->from($this->getTableName())
|
|
->where(
|
|
$qb->expr()
|
|
->eq(
|
|
$qb->func()->lower('name'),
|
|
$qb->func()->lower($qb->createNamedParameter($name, IQueryBuilder::PARAM_STR))
|
|
)
|
|
);
|
|
return $this->findEntity($qb);
|
|
}
|
|
|
|
/**
|
|
* Find multiple roles by IDs at once
|
|
*
|
|
* @param array<int> $ids
|
|
* @return array<Role>
|
|
*/
|
|
public function findByIds(array $ids): array {
|
|
if (empty($ids)) {
|
|
return [];
|
|
}
|
|
|
|
/* @var $qb IQueryBuilder */
|
|
$qb = $this->db->getQueryBuilder();
|
|
$qb->select('*')
|
|
->from($this->getTableName())
|
|
->where(
|
|
$qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))
|
|
);
|
|
return $this->findEntities($qb);
|
|
}
|
|
|
|
/**
|
|
* @return array<Role>
|
|
*/
|
|
public function findAll(): array {
|
|
/* @var $qb IQueryBuilder */
|
|
$qb = $this->db->getQueryBuilder();
|
|
$qb->select('*')->from($this->getTableName());
|
|
return $this->findEntities($qb);
|
|
}
|
|
|
|
/**
|
|
* Find all roles assigned to a user using JOIN
|
|
* More efficient than fetching user roles and then querying each role
|
|
*
|
|
* @param string $userId
|
|
* @return array<Role>
|
|
*/
|
|
public function findByUserId(string $userId): array {
|
|
/* @var $qb IQueryBuilder */
|
|
$qb = $this->db->getQueryBuilder();
|
|
$qb->select('r.*')
|
|
->from($this->getTableName(), 'r')
|
|
->innerJoin('r', Application::tableName('forum_user_roles'), 'ur', 'r.id = ur.role_id')
|
|
->where(
|
|
$qb->expr()->eq('ur.user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
|
|
);
|
|
return $this->findEntities($qb);
|
|
}
|
|
|
|
/**
|
|
* Find the default role (for assigning to new users)
|
|
*
|
|
* @return Role
|
|
* @throws DoesNotExistException
|
|
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
|
*/
|
|
public function findDefaultRole(): Role {
|
|
/* @var $qb IQueryBuilder */
|
|
$qb = $this->db->getQueryBuilder();
|
|
$qb->select('*')
|
|
->from($this->getTableName())
|
|
->where(
|
|
$qb->expr()->eq('role_type', $qb->createNamedParameter(Role::ROLE_TYPE_DEFAULT, IQueryBuilder::PARAM_STR))
|
|
);
|
|
return $this->findEntity($qb);
|
|
}
|
|
|
|
/**
|
|
* Find a role by its type
|
|
*
|
|
* @param string $roleType One of: admin, moderator, default, guest, custom
|
|
* @return Role
|
|
* @throws DoesNotExistException
|
|
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
|
|
*/
|
|
public function findByRoleType(string $roleType): Role {
|
|
/* @var $qb IQueryBuilder */
|
|
$qb = $this->db->getQueryBuilder();
|
|
$qb->select('*')
|
|
->from($this->getTableName())
|
|
->where(
|
|
$qb->expr()->eq('role_type', $qb->createNamedParameter($roleType, IQueryBuilder::PARAM_STR))
|
|
);
|
|
return $this->findEntity($qb);
|
|
}
|
|
}
|