castopod/modules/Auth/Helpers/auth_helper.php

297 lines
8.1 KiB
PHP

<?php
declare(strict_types=1);
/**
* @copyright 2020 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
use App\Entities\Podcast;
use App\Models\ActorModel;
use App\Models\PodcastModel;
use CodeIgniter\Shield\Entities\User;
use Modules\Auth\Auth;
use Modules\Fediverse\Entities\Actor;
use Modules\Fediverse\Models\NotificationModel;
if (! function_exists('auth')) {
/**
* Provides convenient access to the main Auth class for CodeIgniter Shield.
*
* @param string|null $alias Authenticator alias
*/
function auth(?string $alias = null): Auth
{
/** @var Auth $auth */
$auth = service('auth');
return $auth->setAuthenticator($alias);
}
}
if (! function_exists('set_interact_as_actor')) {
/**
* Sets the actor id of which the user is acting as
*/
function set_interact_as_actor(int $actorId): void
{
if (auth()->loggedIn()) {
session()
->set('interact_as_actor_id', $actorId);
}
}
}
if (! function_exists('remove_interact_as_actor')) {
/**
* Removes the actor id of which the user is acting as
*/
function remove_interact_as_actor(): void
{
session()->remove('interact_as_actor_id');
}
}
if (! function_exists('interact_as_actor_id')) {
/**
* Sets the podcast id of which the user is acting as
*/
function interact_as_actor_id(): ?int
{
return session()->get('interact_as_actor_id');
}
}
if (! function_exists('interact_as_actor')) {
/**
* Get the actor the user is currently interacting as
*/
function interact_as_actor(): Actor | false
{
if (! auth()->loggedIn()) {
return false;
}
$session = session();
if (! $session->has('interact_as_actor_id')) {
return false;
}
return model(ActorModel::class, false)->getActorById($session->get('interact_as_actor_id'));
}
}
if (! function_exists('can_user_interact')) {
function can_user_interact(): bool
{
return (bool) interact_as_actor();
}
}
if (! function_exists('add_podcast_group')) {
function add_podcast_group(User $user, int $podcastId, string $group): User
{
$podcastGroup = 'podcast#' . $podcastId . '-' . $group;
return $user->addGroup($podcastGroup);
}
}
if (! function_exists('get_instance_group')) {
function get_instance_group(User $user): ?string
{
$instanceGroups = array_filter($user->getGroups() ?? [], static function ($group): bool {
return ! str_starts_with($group, 'podcast#');
});
if ($instanceGroups === []) {
return null;
}
$instanceGroup = array_shift($instanceGroups);
// Verify that a user belongs to one group only!
if ($instanceGroups !== []) {
// remove any other group the user belongs to
$user->removeGroup(...$instanceGroups);
}
return $instanceGroup;
}
}
if (! function_exists('set_instance_group')) {
function set_instance_group(User $user, string $group): User
{
// remove old instance group
if (get_instance_group($user)) {
$user->removeGroup(get_instance_group($user));
}
// set new group
return $user->addGroup($group);
}
}
if (! function_exists('get_podcast_group')) {
function get_podcast_group(User $user, int $podcastId): ?string
{
$podcastGroups = array_filter($user->getGroups() ?? [], static function ($group) use ($podcastId): bool {
return str_starts_with($group, "podcast#{$podcastId}");
});
if ($podcastGroups === []) {
return null;
}
$podcastGroup = array_shift($podcastGroups);
// Verify that a user belongs to one group only!
if ($podcastGroups !== []) {
// remove any other group the user belongs to
$user->removeGroup(...$podcastGroups);
}
// strip the `podcast#{id}.` prefix when returning group
return substr($podcastGroup, strlen('podcast#' . $podcastId . '-'));
}
}
if (! function_exists('set_podcast_group')) {
function set_podcast_group(User $user, int $podcastId, string $group): User
{
// remove old instance group
$user->removeGroup("podcast#{$podcastId}-" . get_podcast_group($user, $podcastId));
// set new group
return add_podcast_group($user, $podcastId, $group);
}
}
if (! function_exists('get_podcast_groups')) {
/**
* @return string[]
*/
function get_user_podcast_ids(User $user): array
{
$podcastGroups = array_filter($user->getGroups() ?? [], static function ($group): bool {
return str_starts_with($group, 'podcast#');
});
$userPodcastIds = [];
// extract all podcast ids from groups
foreach ($podcastGroups as $podcastGroup) {
$userPodcastIds[] = substr($podcastGroup, strpos($podcastGroup, '#') + 1, 1);
}
return $userPodcastIds;
}
}
if (! function_exists('can_podcast')) {
function can_podcast(User $user, int $podcastId, string $permission): bool
{
return $user->can('podcast#' . $podcastId . '.' . $permission);
}
}
if (! function_exists('get_user_podcasts')) {
/**
* Returns the podcasts the user is contributing to
*
* @return Podcast[]
*/
function get_user_podcasts(User $user): array
{
return (new PodcastModel())->getUserPodcasts($user->id, get_user_podcast_ids($user));
}
}
if (! function_exists('get_podcasts_user_can_interact_with')) {
/**
* @return Podcast[]
*/
function get_podcasts_user_can_interact_with(User $user): array
{
$userPodcasts = (new PodcastModel())->getUserPodcasts($user->id, get_user_podcast_ids($user));
$hasInteractAsPrivilege = interact_as_actor_id() === null;
if ($userPodcasts === []) {
if ($hasInteractAsPrivilege) {
remove_interact_as_actor();
}
return [];
}
$isInteractAsPrivilegeLost = true;
$podcastsUserCanInteractWith = [];
foreach ($userPodcasts as $userPodcast) {
if (can_podcast($user, $userPodcast->id, 'interact-as')) {
if (interact_as_actor_id() === $userPodcast->actor_id) {
$isInteractAsPrivilegeLost = false;
}
$podcastsUserCanInteractWith[] = $userPodcast;
}
}
if ($podcastsUserCanInteractWith === []) {
if (interact_as_actor_id() !== null) {
remove_interact_as_actor();
}
return [];
}
// check if user has lost the interact as privilege for current podcast actor.
// --> Remove interact as if there's no podcast actor to interact as
// or set the first podcast actor the user can interact as
if ($isInteractAsPrivilegeLost) {
set_interact_as_actor($podcastsUserCanInteractWith[0]->actor_id);
}
return $podcastsUserCanInteractWith;
}
}
if (! function_exists('get_actor_ids_with_unread_notifications')) {
/**
* Returns the ids of the user's actors that have unread notifications
*
* @return int[]
*/
function get_actor_ids_with_unread_notifications(User $user): array
{
if (($userPodcasts = get_user_podcasts($user)) === []) {
return [];
}
$unreadNotifications = (new NotificationModel())->whereIn(
'target_actor_id',
array_column($userPodcasts, 'actor_id')
)
->where('read_at', null)
->findAll();
return array_column($unreadNotifications, 'target_actor_id');
}
}
if (! function_exists('get_group_title')) {
/**
* @return array<'title'|'description', string>
*/
function get_group_info(string $group, ?int $podcastId = null): array
{
if ($podcastId === null) {
return setting('AuthGroups.instanceGroups')[$group];
}
return setting('AuthGroups.podcastGroups')[$group];
}
}