Skip to content

Commit

Permalink
Merge pull request #82 from leepeuker/add-privacy-levels
Browse files Browse the repository at this point in the history
Add privacy levels for users
  • Loading branch information
leepeuker authored Jul 28, 2022
2 parents c06f189 + 18151e7 commit 43f957a
Show file tree
Hide file tree
Showing 15 changed files with 306 additions and 103 deletions.
24 changes: 24 additions & 0 deletions db/migrations/20220728103556_AddPrivacyLevelToUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);

use Phinx\Migration\AbstractMigration;

final class AddPrivacyLevelToUser extends AbstractMigration
{
public function down() : void
{
$this->execute(
<<<SQL
ALTER TABLE user DROP COLUMN privacy_level;
SQL
);
}

public function up() : void
{
$this->execute(
<<<SQL
ALTER TABLE user ADD COLUMN privacy_level TINYINT UNSIGNED DEFAULT 1 AFTER password;
SQL
);
}
}
9 changes: 2 additions & 7 deletions settings/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@
);
$routeCollector->addRoute(
'POST',
'/user/name',
[\Movary\HttpController\SettingsController::class, 'updateName']
'/user/general',
[\Movary\HttpController\SettingsController::class, 'updateGeneral']
);
$routeCollector->addRoute(
'GET',
Expand Down Expand Up @@ -172,11 +172,6 @@
'/jobs/schedule/letterboxd-ratings-sync',
[\Movary\HttpController\JobController::class, 'scheduleLetterboxdRatingsImport']
);
$routeCollector->addRoute(
'POST',
'/user/date-format',
[\Movary\HttpController\SettingsController::class, 'updateDateFormatId']
);
$routeCollector->addRoute(
'DELETE',
'/user/plex-webhook-id',
Expand Down
34 changes: 32 additions & 2 deletions src/Application/User/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,41 @@ public function fetchAll() : array
return $this->repository->fetchAll();
}

public function fetchAllHavingWatchedMovie(int $movieId) : array
public function fetchAllHavingWatchedMovieInternVisibleUsernames(int $movieId) : array
{
return $this->repository->fetchAllHavingWatchedMovie($movieId);
return $this->repository->fetchAllHavingWatchedMovieInternVisibleUsernames($movieId);
}

public function fetchAllHavingWatchedMoviePublicVisibleUsernames(int $movieId) : array
{
return $this->repository->fetchAllHavingWatchedMoviePublicVisibleUsernames($movieId);
}

public function fetchAllHavingWatchedMovieWithPersonInternVisibleUsernames(int $personId) : array
{
return $this->repository->fetchAllHavingWatchedMovieWithPersonInternVisibleUsernames($personId);
}

public function fetchAllHavingWatchedMovieWithPersonPublicVisibleUsernames(int $personId) : array
{
return $this->repository->fetchAllHavingWatchedMovieWithPersonPublicVisibleUsernames($personId);
}

public function fetchAllHavingWatchedMoviesWithPerson(int $personId) : array
{
return $this->repository->fetchAllHavingWatchedMovieWithPerson($personId);
}

public function fetchAllInternVisibleUsernames() : array
{
return $this->repository->fetchAllInternVisibleUsernames();
}

public function fetchAllPublicVisibleUsernames() : array
{
return $this->repository->fetchAllPublicVisibleUsernames();
}

public function fetchDateFormatId(int $userId) : int
{
$dateFormat = $this->repository->findDateFormatId($userId);
Expand Down Expand Up @@ -153,6 +178,11 @@ public function updatePassword(int $userId, string $newPassword) : void
$this->repository->updatePassword($userId, $passwordHash);
}

public function updatePrivacyLevel(int $userId, int $privacyLevel) : void
{
$this->repository->updatePrivacyLevel($userId, $privacyLevel);
}

public function updateTraktClientId(int $userId, ?string $traktClientId) : void
{
$this->repository->updateTraktClientId($userId, $traktClientId);
Expand Down
7 changes: 7 additions & 0 deletions src/Application/User/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ private function __construct(
private readonly int $id,
private readonly string $name,
private readonly string $passwordHash,
private readonly int $privacyLevel,
private readonly bool $areCoreAccountChangesDisabled,
private readonly int $dateFormatId,
private readonly ?string $plexWebhookUuid,
Expand All @@ -22,6 +23,7 @@ public static function createFromArray(array $data) : self
(int)$data['id'],
$data['name'],
$data['password'],
$data['privacy_level'],
(bool)$data['core_account_changes_disabled'],
$data['date_format_id'],
$data['plex_webhook_uuid'],
Expand Down Expand Up @@ -60,6 +62,11 @@ public function getPlexWebhookId() : ?string
return $this->plexWebhookUuid;
}

public function getPrivacyLevel() : int
{
return $this->privacyLevel;
}

public function getTraktClientId() : ?string
{
return $this->traktClientId;
Expand Down
75 changes: 73 additions & 2 deletions src/Application/User/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,24 @@ public function fetchAll() : array
return $this->dbConnection->fetchAllAssociative('SELECT * FROM `user` ORDER BY name');
}

public function fetchAllHavingWatchedMovie(int $movieId) : array
public function fetchAllHavingWatchedMovieInternVisibleUsernames(int $movieId) : array
{
return $this->dbConnection->fetchAllAssociative(
'SELECT DISTINCT user.name
FROM `user`
JOIN movie_user_watch_dates muwd ON user.id = muwd.user_id
JOIN movie_user_watch_dates muwd ON user.id = muwd.user_id AND user.privacy_level >= 1
WHERE movie_id = ?
ORDER BY name',
[$movieId]
);
}

public function fetchAllHavingWatchedMoviePublicVisibleUsernames(int $movieId) : array
{
return $this->dbConnection->fetchAllAssociative(
'SELECT DISTINCT user.name
FROM `user`
JOIN movie_user_watch_dates muwd ON user.id = muwd.user_id AND user.privacy_level >= 2
WHERE movie_id = ?
ORDER BY name',
[$movieId]
Expand All @@ -80,6 +92,52 @@ public function fetchAllHavingWatchedMovieWithPerson(int $personId) : array
);
}

public function fetchAllHavingWatchedMovieWithPersonInternVisibleUsernames(int $personId) : array
{
return $this->dbConnection->fetchAllAssociative(
'SELECT DISTINCT user.name
FROM `user`
JOIN movie_user_watch_dates muwd ON user.id = muwd.user_id
JOIN movie_cast mc ON muwd.movie_id = mc.movie_id AND user.privacy_level >= 1
WHERE person_id = ?
ORDER BY name',
[$personId]
);
}

public function fetchAllHavingWatchedMovieWithPersonPublicVisibleUsernames(int $personId) : array
{
return $this->dbConnection->fetchAllAssociative(
'SELECT DISTINCT user.name
FROM `user`
JOIN movie_user_watch_dates muwd ON user.id = muwd.user_id
JOIN movie_cast mc ON muwd.movie_id = mc.movie_id AND user.privacy_level >= 2
WHERE person_id = ?
ORDER BY name',
[$personId]
);
}

public function fetchAllInternVisibleUsernames() : array
{
return $this->dbConnection->fetchAllAssociative(
'SELECT DISTINCT user.name
FROM `user`
WHERE privacy_level >= 1
ORDER BY name'
);
}

public function fetchAllPublicVisibleUsernames() : array
{
return $this->dbConnection->fetchAllAssociative(
'SELECT DISTINCT user.name
FROM `user`
WHERE privacy_level >= 2
ORDER BY name'
);
}

public function findAuthTokenExpirationDate(string $token) : ?DateTime
{
$expirationDate = $this->dbConnection->fetchOne('SELECT `expiration_date` FROM `user_auth_token` WHERE `token` = ?', [$token]);
Expand Down Expand Up @@ -268,6 +326,19 @@ public function updatePassword(int $userId, string $passwordHash) : void
);
}

public function updatePrivacyLevel(int $userId, int $privacyLevel) : void
{
$this->dbConnection->update(
'user',
[
'privacy_level' => $privacyLevel,
],
[
'id' => $userId,
]
);
}

public function updateTraktClientId(int $userId, ?string $traktClientId) : void
{
$this->dbConnection->update(
Expand Down
17 changes: 17 additions & 0 deletions src/Application/User/Service/Authentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@ public function isUserAuthenticated() : bool
return false;
}

public function isUserPageVisible(int $privacyLevel, int $userId) : bool
{
if ($privacyLevel === 2) {
return true;
}

if ($privacyLevel === 1 && $this->isUserAuthenticated() === true) {
return true;
}

if ($this->isUserAuthenticated() === true && $this->getCurrentUserId() === $userId) {
return true;
}

return false;
}

public function login(string $email, string $password, bool $rememberMe) : void
{
if ($this->isUserAuthenticated() === true) {
Expand Down
57 changes: 57 additions & 0 deletions src/Application/User/Service/UserPageAuthorizationChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php declare(strict_types=1);

namespace Movary\Application\User\Service;

use Movary\Application\User\Api;

class UserPageAuthorizationChecker
{
public function __construct(
private readonly Api $userApi,
private readonly Authentication $authenticationService
) {
}

public function fetchAllHavingWatchedMovieVisibleUsernamesForCurrentVisitor(int $movieId) : array
{
if ($this->authenticationService->isUserAuthenticated() === false) {
return $this->userApi->fetchAllHavingWatchedMoviePublicVisibleUsernames($movieId);
}

return $this->userApi->fetchAllHavingWatchedMovieInternVisibleUsernames($movieId);
}

public function fetchAllHavingWatchedMovieWithPersonVisibleUsernamesForCurrentVisitor(int $personId) : array
{
if ($this->authenticationService->isUserAuthenticated() === false) {
return $this->userApi->fetchAllHavingWatchedMovieWithPersonPublicVisibleUsernames($personId);
}

return $this->userApi->fetchAllHavingWatchedMovieWithPersonInternVisibleUsernames($personId);
}

public function fetchAllVisibleUsernamesForCurrentVisitor() : array
{
if ($this->authenticationService->isUserAuthenticated() === false) {
return $this->userApi->fetchAllPublicVisibleUsernames();
}

return $this->userApi->fetchAllInternVisibleUsernames();
}

public function findUserIdIfCurrentVisitorIsAllowedToSeeUser(string $username) : ?int
{
$user = $this->userApi->findUserByName($username);
if ($user === null) {
return null;
}

$userId = $user->getId();

if ($this->authenticationService->isUserPageVisible($user->getPrivacyLevel(), $userId) === false) {
return null;
}

return $user->getId();
}
}
7 changes: 4 additions & 3 deletions src/HttpController/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Movary\Application\Movie;
use Movary\Application\Movie\History\Service\Select;
use Movary\Application\User;
use Movary\Application\User\Service\UserPageAuthorizationChecker;
use Movary\ValueObject\Gender;
use Movary\ValueObject\Http\Request;
use Movary\ValueObject\Http\Response;
Expand All @@ -17,21 +18,21 @@ public function __construct(
private readonly Environment $twig,
private readonly Select $movieHistorySelectService,
private readonly Movie\Api $movieApi,
private readonly User\Api $userApi,
private readonly UserPageAuthorizationChecker $userPageAuthorizationChecker,
) {
}

public function render(Request $request) : Response
{
$userId = $this->userApi->findUserByName((string)$request->getRouteParameters()['username'])?->getId();
$userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']);
if ($userId === null) {
return Response::createNotFound();
}

return Response::create(
StatusCode::createOk(),
$this->twig->render('page/dashboard.html.twig', [
'users' => $this->userApi->fetchAll(),
'users' => $this->userPageAuthorizationChecker->fetchAllVisibleUsernamesForCurrentVisitor(),
'totalPlayCount' => $this->movieApi->fetchHistoryCount($userId),
'uniqueMoviesCount' => $this->movieApi->fetchHistoryCountUnique($userId),
'totalHoursWatched' => $this->movieHistorySelectService->fetchTotalHoursWatched($userId),
Expand Down
8 changes: 4 additions & 4 deletions src/HttpController/HistoryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
use Movary\Application\Movie;
use Movary\Application\Movie\History\Service\Select;
use Movary\Application\Service\Tmdb\SyncMovie;
use Movary\Application\User;
use Movary\Application\User\Service\Authentication;
use Movary\Application\User\Service\UserPageAuthorizationChecker;
use Movary\Util\Json;
use Movary\ValueObject\Date;
use Movary\ValueObject\Http\Request;
Expand All @@ -27,7 +27,7 @@ public function __construct(
private readonly Movie\Api $movieApi,
private readonly SyncMovie $tmdbMovieSyncService,
private readonly Authentication $authenticationService,
private readonly User\Api $userApi,
private readonly UserPageAuthorizationChecker $userPageAuthorizationChecker,
) {
}

Expand Down Expand Up @@ -82,7 +82,7 @@ public function logMovie(Request $request) : Response

public function renderHistory(Request $request) : Response
{
$userId = $this->userApi->findUserByName((string)$request->getRouteParameters()['username'])?->getId();
$userId = $this->userPageAuthorizationChecker->findUserIdIfCurrentVisitorIsAllowedToSeeUser((string)$request->getRouteParameters()['username']);
if ($userId === null) {
return Response::createNotFound();
}
Expand All @@ -106,7 +106,7 @@ public function renderHistory(Request $request) : Response
return Response::create(
StatusCode::createOk(),
$this->twig->render('page/history.html.twig', [
'users' => $this->userApi->fetchAll(),
'users' => $this->userPageAuthorizationChecker->fetchAllVisibleUsernamesForCurrentVisitor(),
'historyEntries' => $historyPaginated,
'paginationElements' => $paginationElements,
'searchTerm' => $searchTerm,
Expand Down
Loading

0 comments on commit 43f957a

Please sign in to comment.