Skip to content

Commit

Permalink
Merge branch 'BookStackApp:release' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
paulhollmann authored Apr 11, 2024
2 parents f7acac1 + 606f9d9 commit d08a452
Show file tree
Hide file tree
Showing 537 changed files with 7,431 additions and 4,150 deletions.
24 changes: 23 additions & 1 deletion .github/translators.txt
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ balmag :: Hungarian
Antti-Jussi Nygård (ajnyga) :: Finnish
Eduard Ereza Martínez (Ereza) :: Catalan
Jabir Lang (amar.almrad) :: Arabic
Jaroslav Koblizek (foretix) :: Czech; French
Jaroslav Kobližek (foretix) :: Czech; French
Wiktor Adamczyk (adamczyk.wiktor) :: Polish
Abdulmajeed Alshuaibi (4Majeed) :: Arabic
NotSmartZakk :: Czech
Expand All @@ -388,3 +388,25 @@ diegobenitez :: Spanish
Marc Hagen (MarcHagen) :: Dutch
Kasper Alsøe (zeonos) :: Danish
sultani :: Persian
renge :: Korean
TheGatesDev (thegatesdev) :: Dutch
Irdi (irdiOL) :: Albanian
KateBarber :: Welsh
Twister (theuncles75) :: Hebrew
algernon19 :: Hungarian
Ivan Krstic (ikrstic) :: Serbian (Cyrillic)
Show :: Russian
xBahamut :: Portuguese, Brazilian
Pavle Knežević (pavleknezzevic) :: Serbian (Cyrillic)
Vanja Cvelbar (b100w11) :: Slovenian
simonpct :: French
Honza Nagy (honza.nagy) :: Czech
asd20752 :: Norwegian Bokmal
Jan Picka (polipones) :: Czech
diogoalex991 :: Portuguese
Ehsan Sadeghi (ehsansadeghi) :: Persian
ka_picit :: Danish
cracrayol :: French
CapuaSC :: Dutch
Guardian75 :: German Informal
mr-kanister :: German
31 changes: 12 additions & 19 deletions app/Access/Oidc/OidcOAuthProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,9 @@ protected function getScopeSeparator(): string

/**
* Checks a provider response for errors.
*
* @param ResponseInterface $response
* @param array|string $data Parsed response data
*
* @throws IdentityProviderException
*
* @return void
*/
protected function checkResponse(ResponseInterface $response, $data)
protected function checkResponse(ResponseInterface $response, $data): void
{
if ($response->getStatusCode() >= 400 || isset($data['error'])) {
throw new IdentityProviderException(
Expand All @@ -105,13 +99,8 @@ protected function checkResponse(ResponseInterface $response, $data)
/**
* Generates a resource owner object from a successful resource owner
* details request.
*
* @param array $response
* @param AccessToken $token
*
* @return ResourceOwnerInterface
*/
protected function createResourceOwner(array $response, AccessToken $token)
protected function createResourceOwner(array $response, AccessToken $token): ResourceOwnerInterface
{
return new GenericResourceOwner($response, '');
}
Expand All @@ -121,14 +110,18 @@ protected function createResourceOwner(array $response, AccessToken $token)
*
* The grant that was used to fetch the response can be used to provide
* additional context.
*
* @param array $response
* @param AbstractGrant $grant
*
* @return OidcAccessToken
*/
protected function createAccessToken(array $response, AbstractGrant $grant)
protected function createAccessToken(array $response, AbstractGrant $grant): OidcAccessToken
{
return new OidcAccessToken($response);
}

/**
* Get the method used for PKCE code verifier hashing, which is passed
* in the "code_challenge_method" parameter in the authorization request.
*/
protected function getPkceMethod(): string
{
return static::PKCE_METHOD_S256;
}
}
12 changes: 11 additions & 1 deletion app/Access/Oidc/OidcService.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public function __construct(

/**
* Initiate an authorization flow.
* Provides back an authorize redirect URL, in addition to other
* details which may be required for the auth flow.
*
* @throws OidcException
*
Expand All @@ -42,8 +44,12 @@ public function login(): array
{
$settings = $this->getProviderSettings();
$provider = $this->getProvider($settings);

$url = $provider->getAuthorizationUrl();
session()->put('oidc_pkce_code', $provider->getPkceCode() ?? '');

return [
'url' => $provider->getAuthorizationUrl(),
'url' => $url,
'state' => $provider->getState(),
];
}
Expand All @@ -63,6 +69,10 @@ public function processAuthorizeResponse(?string $authorizationCode): User
$settings = $this->getProviderSettings();
$provider = $this->getProvider($settings);

// Set PKCE code flashed at login
$pkceCode = session()->pull('oidc_pkce_code', '');
$provider->setPkceCode($pkceCode);

// Try to exchange authorization code for access token
$accessToken = $provider->getAccessToken('authorization_code', [
'code' => $authorizationCode,
Expand Down
27 changes: 14 additions & 13 deletions app/Access/RegistrationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,14 @@

class RegistrationService
{
protected $userRepo;
protected $emailConfirmationService;

/**
* RegistrationService constructor.
*/
public function __construct(UserRepo $userRepo, EmailConfirmationService $emailConfirmationService)
{
$this->userRepo = $userRepo;
$this->emailConfirmationService = $emailConfirmationService;
public function __construct(
protected UserRepo $userRepo,
protected EmailConfirmationService $emailConfirmationService,
) {
}

/**
* Check whether or not registrations are allowed in the app settings.
* Check if registrations are allowed in the app settings.
*
* @throws UserRegistrationException
*/
Expand Down Expand Up @@ -84,6 +78,7 @@ public function findOrRegister(string $name, string $email, string $externalId):
public function registerUser(array $userData, ?SocialAccount $socialAccount = null, bool $emailConfirmed = false): User
{
$userEmail = $userData['email'];
$authSystem = $socialAccount ? $socialAccount->driver : auth()->getDefaultDriver();

// Email restriction
$this->ensureEmailDomainAllowed($userEmail);
Expand All @@ -94,6 +89,12 @@ public function registerUser(array $userData, ?SocialAccount $socialAccount = nu
throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $userEmail]), '/login');
}

/** @var ?bool $shouldRegister */
$shouldRegister = Theme::dispatch(ThemeEvents::AUTH_PRE_REGISTER, $authSystem, $userData);
if ($shouldRegister === false) {
throw new UserRegistrationException(trans('errors.auth_pre_register_theme_prevention'), '/login');
}

// Create the user
$newUser = $this->userRepo->createWithoutActivity($userData, $emailConfirmed);
$newUser->attachDefaultRole();
Expand All @@ -104,7 +105,7 @@ public function registerUser(array $userData, ?SocialAccount $socialAccount = nu
}

Activity::add(ActivityType::AUTH_REGISTER, $socialAccount ?? $newUser);
Theme::dispatch(ThemeEvents::AUTH_REGISTER, $socialAccount ? $socialAccount->driver : auth()->getDefaultDriver(), $newUser);
Theme::dispatch(ThemeEvents::AUTH_REGISTER, $authSystem, $newUser);

// Start email confirmation flow if required
if ($this->emailConfirmationService->confirmationRequired() && !$emailConfirmed) {
Expand Down Expand Up @@ -138,7 +139,7 @@ protected function ensureEmailDomainAllowed(string $userEmail): void
}

$restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
$userEmailDomain = $domain = mb_substr(mb_strrchr($userEmail, '@'), 1);
$userEmailDomain = mb_substr(mb_strrchr($userEmail, '@'), 1);
if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
$redirect = $this->registrationAllowed() ? '/register' : '/login';

Expand Down
14 changes: 8 additions & 6 deletions app/Activity/ActivityQueries.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Tools\MixedEntityListLoader;
use BookStack\Permissions\PermissionApplicator;
use BookStack\Users\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;

class ActivityQueries
{
protected PermissionApplicator $permissions;

public function __construct(PermissionApplicator $permissions)
{
$this->permissions = $permissions;
public function __construct(
protected PermissionApplicator $permissions,
protected MixedEntityListLoader $listLoader,
) {
}

/**
Expand All @@ -29,11 +29,13 @@ public function latest(int $count = 20, int $page = 0): array
$activityList = $this->permissions
->restrictEntityRelationQuery(Activity::query(), 'activities', 'entity_id', 'entity_type')
->orderBy('created_at', 'desc')
->with(['user', 'entity'])
->with(['user'])
->skip($count * $page)
->take($count)
->get();

$this->listLoader->loadIntoRelations($activityList->all(), 'entity', false);

return $this->filterSimilar($activityList);
}

Expand Down
26 changes: 5 additions & 21 deletions app/Activity/CommentRepo.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use BookStack\Activity\Models\Comment;
use BookStack\Entities\Models\Entity;
use BookStack\Facades\Activity as ActivityService;
use League\CommonMark\CommonMarkConverter;
use BookStack\Util\HtmlDescriptionFilter;

class CommentRepo
{
Expand All @@ -20,13 +20,12 @@ public function getById(int $id): Comment
/**
* Create a new comment on an entity.
*/
public function create(Entity $entity, string $text, ?int $parent_id): Comment
public function create(Entity $entity, string $html, ?int $parent_id): Comment
{
$userId = user()->id;
$comment = new Comment();

$comment->text = $text;
$comment->html = $this->commentToHtml($text);
$comment->html = HtmlDescriptionFilter::filterFromString($html);
$comment->created_by = $userId;
$comment->updated_by = $userId;
$comment->local_id = $this->getNextLocalId($entity);
Expand All @@ -42,11 +41,10 @@ public function create(Entity $entity, string $text, ?int $parent_id): Comment
/**
* Update an existing comment.
*/
public function update(Comment $comment, string $text): Comment
public function update(Comment $comment, string $html): Comment
{
$comment->updated_by = user()->id;
$comment->text = $text;
$comment->html = $this->commentToHtml($text);
$comment->html = HtmlDescriptionFilter::filterFromString($html);
$comment->save();

ActivityService::add(ActivityType::COMMENT_UPDATE, $comment);
Expand All @@ -64,20 +62,6 @@ public function delete(Comment $comment): void
ActivityService::add(ActivityType::COMMENT_DELETE, $comment);
}

/**
* Convert the given comment Markdown to HTML.
*/
public function commentToHtml(string $commentText): string
{
$converter = new CommonMarkConverter([
'html_input' => 'strip',
'max_nesting_level' => 10,
'allow_unsafe_links' => false,
]);

return $converter->convert($commentText);
}

/**
* Get the next local ID relative to the linked entity.
*/
Expand Down
24 changes: 14 additions & 10 deletions app/Activity/Controllers/CommentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
namespace BookStack\Activity\Controllers;

use BookStack\Activity\CommentRepo;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Queries\PageQueries;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;

class CommentController extends Controller
{
public function __construct(
protected CommentRepo $commentRepo
protected CommentRepo $commentRepo,
protected PageQueries $pageQueries,
) {
}

Expand All @@ -22,12 +23,12 @@ public function __construct(
*/
public function savePageComment(Request $request, int $pageId)
{
$this->validate($request, [
'text' => ['required', 'string'],
$input = $this->validate($request, [
'html' => ['required', 'string'],
'parent_id' => ['nullable', 'integer'],
]);

$page = Page::visible()->find($pageId);
$page = $this->pageQueries->findVisibleById($pageId);
if ($page === null) {
return response('Not found', 404);
}
Expand All @@ -39,7 +40,7 @@ public function savePageComment(Request $request, int $pageId)

// Create a new comment.
$this->checkPermission('comment-create-all');
$comment = $this->commentRepo->create($page, $request->get('text'), $request->get('parent_id'));
$comment = $this->commentRepo->create($page, $input['html'], $input['parent_id'] ?? null);

return view('comments.comment-branch', [
'readOnly' => false,
Expand All @@ -57,17 +58,20 @@ public function savePageComment(Request $request, int $pageId)
*/
public function update(Request $request, int $commentId)
{
$this->validate($request, [
'text' => ['required', 'string'],
$input = $this->validate($request, [
'html' => ['required', 'string'],
]);

$comment = $this->commentRepo->getById($commentId);
$this->checkOwnablePermission('page-view', $comment->entity);
$this->checkOwnablePermission('comment-update', $comment);

$comment = $this->commentRepo->update($comment, $request->get('text'));
$comment = $this->commentRepo->update($comment, $input['html']);

return view('comments.comment', ['comment' => $comment, 'readOnly' => false]);
return view('comments.comment', [
'comment' => $comment,
'readOnly' => false,
]);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions app/Activity/Controllers/FavouriteController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace BookStack\Activity\Controllers;

use BookStack\Entities\Queries\TopFavourites;
use BookStack\Entities\Queries\QueryTopFavourites;
use BookStack\Entities\Tools\MixedEntityRequestHelper;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
Expand All @@ -17,11 +17,11 @@ public function __construct(
/**
* Show a listing of all favourite items for the current user.
*/
public function index(Request $request)
public function index(Request $request, QueryTopFavourites $topFavourites)
{
$viewCount = 20;
$page = intval($request->get('page', 1));
$favourites = (new TopFavourites())->run($viewCount + 1, (($page - 1) * $viewCount));
$favourites = $topFavourites->run($viewCount + 1, (($page - 1) * $viewCount));

$hasMoreLink = ($favourites->count() > $viewCount) ? url('/favourites?page=' . ($page + 1)) : null;

Expand Down
Loading

0 comments on commit d08a452

Please sign in to comment.