Merge branch 'development' into release

This commit is contained in:
Dan Brown 2023-06-30 11:05:57 +01:00
commit becc630acf
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
687 changed files with 6947 additions and 3664 deletions

View File

@ -37,8 +37,10 @@ MAIL_FROM=bookstack@example.com
# SMTP mail options
# These settings can be checked using the "Send a Test Email"
# feature found in the "Settings > Maintenance" area of the system.
# For more detailed documentation on mail options, refer to:
# https://www.bookstackapp.com/docs/admin/email-webhooks/#email-configuration
MAIL_HOST=localhost
MAIL_PORT=1025
MAIL_PORT=587
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

View File

@ -69,23 +69,19 @@ DB_PASSWORD=database_user_password
# certificate itself (Common Name or Subject Alternative Name).
MYSQL_ATTR_SSL_CA="/path/to/ca.pem"
# Mail system to use
# Can be 'smtp' or 'sendmail'
# Mail configuration
# Refer to https://www.bookstackapp.com/docs/admin/email-webhooks/#email-configuration
MAIL_DRIVER=smtp
# Mail sending options
MAIL_FROM=mail@bookstackapp.com
MAIL_FROM_NAME=BookStack
# SMTP mail options
MAIL_HOST=localhost
MAIL_PORT=1025
MAIL_PORT=587
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_VERIFY_SSL=true
# Command to use when email is sent via sendmail
MAIL_SENDMAIL_COMMAND="/usr/sbin/sendmail -bs"
# Cache & Session driver to use

View File

@ -333,3 +333,11 @@ Patrick Dantas (pa-tiq) :: Portuguese, Brazilian
Michal (michalgurcik) :: Slovak
Nepomacs :: German
Rubens (rubenix) :: Catalan
m4z :: German; German Informal
TheRazvy :: Romanian
Yossi Zilber (lortens) :: Hebrew; Uzbek
desdinova :: French
Ingus Rūķis (ingus.rukis) :: Latvian
Eugene Pershin (SilentEugene) :: Russian
周盛道 (zhoushengdao) :: Chinese Simplified
hamidreza amini (hamidrezaamini2022) :: Persian

View File

@ -1,14 +1,14 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Auth\Access\EmailConfirmationService;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\UserRepo;
use BookStack\Access\EmailConfirmationService;
use BookStack\Access\LoginService;
use BookStack\Exceptions\ConfirmationEmailException;
use BookStack\Exceptions\UserTokenExpiredException;
use BookStack\Exceptions\UserTokenNotFoundException;
use BookStack\Http\Controllers\Controller;
use BookStack\Http\Controller;
use BookStack\Users\UserRepo;
use Exception;
use Illuminate\Http\Request;

View File

@ -1,9 +1,9 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Actions\ActivityType;
use BookStack\Http\Controllers\Controller;
use BookStack\Activity\ActivityType;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

View File

@ -1,10 +1,10 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\User;
use BookStack\Access\LoginService;
use BookStack\Exceptions\NotFoundException;
use BookStack\Users\Models\User;
trait HandlesPartialLogins
{

View File

@ -1,13 +1,13 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\SocialAuthService;
use BookStack\Access\LoginService;
use BookStack\Access\SocialAuthService;
use BookStack\Exceptions\LoginAttemptEmailNeededException;
use BookStack\Exceptions\LoginAttemptException;
use BookStack\Facades\Activity;
use BookStack\Http\Controllers\Controller;
use BookStack\Http\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

View File

@ -1,14 +1,14 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Actions\ActivityType;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\Mfa\BackupCodeService;
use BookStack\Auth\Access\Mfa\MfaSession;
use BookStack\Auth\Access\Mfa\MfaValue;
use BookStack\Access\LoginService;
use BookStack\Access\Mfa\BackupCodeService;
use BookStack\Access\Mfa\MfaSession;
use BookStack\Access\Mfa\MfaValue;
use BookStack\Activity\ActivityType;
use BookStack\Exceptions\NotFoundException;
use BookStack\Http\Controllers\Controller;
use BookStack\Http\Controller;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;

View File

@ -1,10 +1,10 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Actions\ActivityType;
use BookStack\Auth\Access\Mfa\MfaValue;
use BookStack\Http\Controllers\Controller;
use BookStack\Access\Mfa\MfaValue;
use BookStack\Activity\ActivityType;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
class MfaController extends Controller

View File

@ -1,15 +1,15 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Actions\ActivityType;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\Mfa\MfaSession;
use BookStack\Auth\Access\Mfa\MfaValue;
use BookStack\Auth\Access\Mfa\TotpService;
use BookStack\Auth\Access\Mfa\TotpValidationRule;
use BookStack\Access\LoginService;
use BookStack\Access\Mfa\MfaSession;
use BookStack\Access\Mfa\MfaValue;
use BookStack\Access\Mfa\TotpService;
use BookStack\Access\Mfa\TotpValidationRule;
use BookStack\Activity\ActivityType;
use BookStack\Exceptions\NotFoundException;
use BookStack\Http\Controllers\Controller;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;

View File

@ -1,10 +1,10 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Auth\Access\Oidc\OidcException;
use BookStack\Auth\Access\Oidc\OidcService;
use BookStack\Http\Controllers\Controller;
use BookStack\Access\Oidc\OidcException;
use BookStack\Access\Oidc\OidcService;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
class OidcController extends Controller

View File

@ -1,13 +1,13 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\RegistrationService;
use BookStack\Auth\Access\SocialAuthService;
use BookStack\Access\LoginService;
use BookStack\Access\RegistrationService;
use BookStack\Access\SocialAuthService;
use BookStack\Exceptions\StoppedAuthenticationException;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Http\Controllers\Controller;
use BookStack\Http\Controller;
use Illuminate\Contracts\Validation\Validator as ValidatorContract;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

View File

@ -1,11 +1,11 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Actions\ActivityType;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\User;
use BookStack\Http\Controllers\Controller;
use BookStack\Access\LoginService;
use BookStack\Activity\ActivityType;
use BookStack\Http\Controller;
use BookStack\Users\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

View File

@ -1,9 +1,9 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Auth\Access\Saml2Service;
use BookStack\Http\Controllers\Controller;
use BookStack\Access\Saml2Service;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

View File

@ -1,15 +1,15 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\RegistrationService;
use BookStack\Auth\Access\SocialAuthService;
use BookStack\Access\LoginService;
use BookStack\Access\RegistrationService;
use BookStack\Access\SocialAuthService;
use BookStack\Exceptions\SocialDriverNotConfigured;
use BookStack\Exceptions\SocialSignInAccountNotUsed;
use BookStack\Exceptions\SocialSignInException;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Http\Controllers\Controller;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Laravel\Socialite\Contracts\User as SocialUser;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use Illuminate\Cache\RateLimiter;
use Illuminate\Http\Request;

View File

@ -1,12 +1,12 @@
<?php
namespace BookStack\Http\Controllers\Auth;
namespace BookStack\Access\Controllers;
use BookStack\Auth\Access\UserInviteService;
use BookStack\Auth\UserRepo;
use BookStack\Access\UserInviteService;
use BookStack\Exceptions\UserTokenExpiredException;
use BookStack\Exceptions\UserTokenNotFoundException;
use BookStack\Http\Controllers\Controller;
use BookStack\Http\Controller;
use BookStack\Users\UserRepo;
use Exception;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

View File

@ -1,10 +1,10 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Auth\User;
use BookStack\Exceptions\ConfirmationEmailException;
use BookStack\Notifications\ConfirmEmail;
use BookStack\Users\Models\User;
class EmailConfirmationService extends UserTokenService
{

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;

View File

@ -1,9 +1,9 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Auth\Role;
use BookStack\Auth\User;
use BookStack\Users\Models\Role;
use BookStack\Users\Models\User;
use Illuminate\Support\Collection;
class GroupSyncService

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Guards;
namespace BookStack\Access\Guards;
/**
* Saml2 Session Guard.

View File

@ -1,8 +1,8 @@
<?php
namespace BookStack\Auth\Access\Guards;
namespace BookStack\Access\Guards;
use BookStack\Auth\Access\RegistrationService;
use BookStack\Access\RegistrationService;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\StatefulGuard;

View File

@ -1,15 +1,15 @@
<?php
namespace BookStack\Auth\Access\Guards;
namespace BookStack\Access\Guards;
use BookStack\Auth\Access\LdapService;
use BookStack\Auth\Access\RegistrationService;
use BookStack\Auth\User;
use BookStack\Access\LdapService;
use BookStack\Access\RegistrationService;
use BookStack\Exceptions\JsonDebugException;
use BookStack\Exceptions\LdapException;
use BookStack\Exceptions\LoginAttemptEmailNeededException;
use BookStack\Exceptions\LoginAttemptException;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Users\Models\User;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Session\Session;
use Illuminate\Support\Str;

110
app/Access/Ldap.php Normal file
View File

@ -0,0 +1,110 @@
<?php
namespace BookStack\Access;
/**
* Class Ldap
* An object-orientated thin abstraction wrapper for common PHP LDAP functions.
* Allows the standard LDAP functions to be mocked for testing.
*/
class Ldap
{
/**
* Connect to an LDAP server.
*
* @return resource|\LDAP\Connection|false
*/
public function connect(string $hostName)
{
return ldap_connect($hostName);
}
/**
* Set the value of an LDAP option for the given connection.
*
* @param resource|\LDAP\Connection|null $ldapConnection
*/
public function setOption($ldapConnection, int $option, mixed $value): bool
{
return ldap_set_option($ldapConnection, $option, $value);
}
/**
* Start TLS on the given LDAP connection.
*/
public function startTls($ldapConnection): bool
{
return ldap_start_tls($ldapConnection);
}
/**
* Set the version number for the given LDAP connection.
*
* @param resource|\LDAP\Connection $ldapConnection
*/
public function setVersion($ldapConnection, int $version): bool
{
return $this->setOption($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, $version);
}
/**
* Search LDAP tree using the provided filter.
*
* @param resource|\LDAP\Connection $ldapConnection
*
* @return resource|\LDAP\Result
*/
public function search($ldapConnection, string $baseDn, string $filter, array $attributes = null)
{
return ldap_search($ldapConnection, $baseDn, $filter, $attributes);
}
/**
* Get entries from an LDAP search result.
*
* @param resource|\LDAP\Connection $ldapConnection
* @param resource|\LDAP\Result $ldapSearchResult
*/
public function getEntries($ldapConnection, $ldapSearchResult): array|false
{
return ldap_get_entries($ldapConnection, $ldapSearchResult);
}
/**
* Search and get entries immediately.
*
* @param resource|\LDAP\Connection $ldapConnection
*/
public function searchAndGetEntries($ldapConnection, string $baseDn, string $filter, array $attributes = null): array|false
{
$search = $this->search($ldapConnection, $baseDn, $filter, $attributes);
return $this->getEntries($ldapConnection, $search);
}
/**
* Bind to LDAP directory.
*
* @param resource|\LDAP\Connection $ldapConnection
*/
public function bind($ldapConnection, string $bindRdn = null, string $bindPassword = null): bool
{
return ldap_bind($ldapConnection, $bindRdn, $bindPassword);
}
/**
* Explode an LDAP dn string into an array of components.
*/
public function explodeDn(string $dn, int $withAttrib): array|false
{
return ldap_explode_dn($dn, $withAttrib);
}
/**
* Escape a string for use in an LDAP filter.
*/
public function escape(string $value, string $ignore = '', int $flags = 0): string
{
return ldap_escape($value, $ignore, $flags);
}
}

View File

@ -1,11 +1,11 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Auth\User;
use BookStack\Exceptions\JsonDebugException;
use BookStack\Exceptions\LdapException;
use BookStack\Uploads\UserAvatars;
use BookStack\Users\Models\User;
use ErrorException;
use Illuminate\Support\Facades\Log;
@ -15,26 +15,19 @@ use Illuminate\Support\Facades\Log;
*/
class LdapService
{
protected Ldap $ldap;
protected GroupSyncService $groupSyncService;
protected UserAvatars $userAvatars;
/**
* @var resource
* @var resource|\LDAP\Connection
*/
protected $ldapConnection;
protected array $config;
protected bool $enabled;
/**
* LdapService constructor.
*/
public function __construct(Ldap $ldap, UserAvatars $userAvatars, GroupSyncService $groupSyncService)
{
$this->ldap = $ldap;
$this->userAvatars = $userAvatars;
$this->groupSyncService = $groupSyncService;
public function __construct(
protected Ldap $ldap,
protected UserAvatars $userAvatars,
protected GroupSyncService $groupSyncService
) {
$this->config = config('services.ldap');
$this->enabled = config('auth.method') === 'ldap';
}
@ -59,7 +52,7 @@ class LdapService
// Clean attributes
foreach ($attributes as $index => $attribute) {
if (strpos($attribute, 'BIN;') === 0) {
if (str_starts_with($attribute, 'BIN;')) {
$attributes[$index] = substr($attribute, strlen('BIN;'));
}
}
@ -82,7 +75,7 @@ class LdapService
* Get the details of a user from LDAP using the given username.
* User found via configurable user filter.
*
* @throws LdapException
* @throws LdapException|JsonDebugException
*/
public function getUserDetails(string $userName): ?array
{
@ -126,7 +119,7 @@ class LdapService
*/
protected function getUserResponseProperty(array $userDetails, string $propertyKey, $defaultValue)
{
$isBinary = strpos($propertyKey, 'BIN;') === 0;
$isBinary = str_starts_with($propertyKey, 'BIN;');
$propertyKey = strtolower($propertyKey);
$value = $defaultValue;
@ -170,11 +163,11 @@ class LdapService
* Bind the system user to the LDAP connection using the given credentials
* otherwise anonymous access is attempted.
*
* @param resource $connection
* @param resource|\LDAP\Connection $connection
*
* @throws LdapException
*/
protected function bindSystemUser($connection)
protected function bindSystemUser($connection): void
{
$ldapDn = $this->config['dn'];
$ldapPass = $this->config['pass'];
@ -197,7 +190,7 @@ class LdapService
*
* @throws LdapException
*
* @return resource
* @return resource|\LDAP\Connection
*/
protected function getConnection()
{
@ -216,8 +209,8 @@ class LdapService
$this->ldap->setOption(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER);
}
$serverDetails = $this->parseServerString($this->config['server']);
$ldapConnection = $this->ldap->connect($serverDetails['host'], $serverDetails['port']);
$ldapHost = $this->parseServerString($this->config['server']);
$ldapConnection = $this->ldap->connect($ldapHost);
if ($ldapConnection === false) {
throw new LdapException(trans('errors.ldap_cannot_connect'));
@ -242,23 +235,16 @@ class LdapService
}
/**
* Parse a LDAP server string and return the host and port for a connection.
* Parse an LDAP server string and return the host suitable for a connection.
* Is flexible to formats such as 'ldap.example.com:8069' or 'ldaps://ldap.example.com'.
*/
protected function parseServerString(string $serverString): array
protected function parseServerString(string $serverString): string
{
$serverNameParts = explode(':', $serverString);
// If we have a protocol just return the full string since PHP will ignore a separate port.
if ($serverNameParts[0] === 'ldaps' || $serverNameParts[0] === 'ldap') {
return ['host' => $serverString, 'port' => 389];
if (str_starts_with($serverString, 'ldaps://') || str_starts_with($serverString, 'ldap://')) {
return $serverString;
}
// Otherwise, extract the port out
$hostName = $serverNameParts[0];
$ldapPort = (count($serverNameParts) > 1) ? intval($serverNameParts[1]) : 389;
return ['host' => $hostName, 'port' => $ldapPort];
return "ldap://{$serverString}";
}
/**
@ -386,7 +372,7 @@ class LdapService
* @throws LdapException
* @throws JsonDebugException
*/
public function syncGroups(User $user, string $username)
public function syncGroups(User $user, string $username): void
{
$userLdapGroups = $this->getUserGroups($username);
$this->groupSyncService->syncUserWithFoundGroups($user, $userLdapGroups, $this->config['remove_from_groups']);

View File

@ -1,15 +1,15 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Actions\ActivityType;
use BookStack\Auth\Access\Mfa\MfaSession;
use BookStack\Auth\User;
use BookStack\Access\Mfa\MfaSession;
use BookStack\Activity\ActivityType;
use BookStack\Exceptions\LoginAttemptException;
use BookStack\Exceptions\StoppedAuthenticationException;
use BookStack\Facades\Activity;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use BookStack\Users\Models\User;
use Exception;
class LoginService

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Mfa;
namespace BookStack\Access\Mfa;
use Illuminate\Support\Str;

View File

@ -1,8 +1,8 @@
<?php
namespace BookStack\Auth\Access\Mfa;
namespace BookStack\Access\Mfa;
use BookStack\Auth\User;
use BookStack\Users\Models\User;
class MfaSession
{

View File

@ -1,8 +1,8 @@
<?php
namespace BookStack\Auth\Access\Mfa;
namespace BookStack\Access\Mfa;
use BookStack\Auth\User;
use BookStack\Users\Models\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Mfa;
namespace BookStack\Access\Mfa;
use BaconQrCode\Renderer\Color\Rgb;
use BaconQrCode\Renderer\Image\SvgImageBackEnd;
@ -8,7 +8,7 @@ use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\RendererStyle\Fill;
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer;
use BookStack\Auth\User;
use BookStack\Users\Models\User;
use PragmaRX\Google2FA\Google2FA;
use PragmaRX\Google2FA\Support\Constants;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Mfa;
namespace BookStack\Access\Mfa;
use Illuminate\Contracts\Validation\Rule;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
use InvalidArgumentException;
use League\OAuth2\Client\Token\AccessToken;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
use Exception;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
class OidcIdToken
{

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
class OidcInvalidKeyException extends \Exception
{

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
use Exception;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
use Exception;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
use phpseclib3\Crypt\Common\PublicKey;
use phpseclib3\Crypt\PublicKeyLoader;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
use League\OAuth2\Client\Grant\AbstractGrant;
use League\OAuth2\Client\Provider\AbstractProvider;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
use GuzzleHttp\Psr7\Request;
use Illuminate\Contracts\Cache\Repository;

View File

@ -1,16 +1,16 @@
<?php
namespace BookStack\Auth\Access\Oidc;
namespace BookStack\Access\Oidc;
use BookStack\Auth\Access\GroupSyncService;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\RegistrationService;
use BookStack\Auth\User;
use BookStack\Access\GroupSyncService;
use BookStack\Access\LoginService;
use BookStack\Access\RegistrationService;
use BookStack\Exceptions\JsonDebugException;
use BookStack\Exceptions\StoppedAuthenticationException;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use BookStack\Users\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use League\OAuth2\Client\OptionProvider\HttpBasicAuthOptionProvider;

View File

@ -1,15 +1,14 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Actions\ActivityType;
use BookStack\Auth\SocialAccount;
use BookStack\Auth\User;
use BookStack\Auth\UserRepo;
use BookStack\Activity\ActivityType;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Facades\Activity;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use BookStack\Users\Models\User;
use BookStack\Users\UserRepo;
use Exception;
use Illuminate\Support\Str;

View File

@ -1,12 +1,12 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Auth\User;
use BookStack\Exceptions\JsonDebugException;
use BookStack\Exceptions\SamlException;
use BookStack\Exceptions\StoppedAuthenticationException;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Users\Models\User;
use Exception;
use OneLogin\Saml2\Auth;
use OneLogin\Saml2\Constants;

View File

@ -1,9 +1,10 @@
<?php
namespace BookStack\Auth;
namespace BookStack\Access;
use BookStack\Interfaces\Loggable;
use BookStack\Model;
use BookStack\Activity\Models\Loggable;
use BookStack\App\Model;
use BookStack\Users\Models\User;
/**
* Class SocialAccount.

View File

@ -1,12 +1,12 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Auth\SocialAccount;
use BookStack\Auth\User;
use BookStack\Auth\Access\handler;
use BookStack\Exceptions\SocialDriverNotConfigured;
use BookStack\Exceptions\SocialSignInAccountNotUsed;
use BookStack\Exceptions\UserRegistrationException;
use BookStack\Users\Models\User;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Laravel\Socialite\Contracts\Factory as Socialite;

View File

@ -1,9 +1,9 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Auth\User;
use BookStack\Notifications\UserInvite;
use BookStack\Users\Models\User;
class UserInviteService extends UserTokenService
{

View File

@ -1,10 +1,10 @@
<?php
namespace BookStack\Auth\Access;
namespace BookStack\Access;
use BookStack\Auth\User;
use BookStack\Exceptions\UserTokenExpiredException;
use BookStack\Exceptions\UserTokenNotFoundException;
use BookStack\Users\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

View File

@ -1,13 +1,14 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity;
use BookStack\Auth\Permissions\PermissionApplicator;
use BookStack\Auth\User;
use BookStack\Activity\Models\Activity;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page;
use BookStack\Permissions\PermissionApplicator;
use BookStack\Users\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity;
class ActivityType
{

View File

@ -1,32 +1,20 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity;
use BookStack\Activity\Models\Comment;
use BookStack\Entities\Models\Entity;
use BookStack\Facades\Activity as ActivityService;
use League\CommonMark\CommonMarkConverter;
/**
* Class CommentRepo.
*/
class CommentRepo
{
/**
* @var Comment
*/
protected $comment;
public function __construct(Comment $comment)
{
$this->comment = $comment;
}
/**
* Get a comment by ID.
*/
public function getById(int $id): Comment
{
return $this->comment->newQuery()->findOrFail($id);
return Comment::query()->findOrFail($id);
}
/**
@ -35,7 +23,7 @@ class CommentRepo
public function create(Entity $entity, string $text, ?int $parent_id): Comment
{
$userId = user()->id;
$comment = $this->comment->newInstance();
$comment = new Comment();
$comment->text = $text;
$comment->html = $this->commentToHtml($text);
@ -82,7 +70,7 @@ class CommentRepo
'allow_unsafe_links' => false,
]);
return $converter->convertToHtml($commentText);
return $converter->convert($commentText);
}
/**
@ -90,9 +78,8 @@ class CommentRepo
*/
protected function getNextLocalId(Entity $entity): int
{
/** @var Comment $comment */
$comment = $entity->comments(false)->orderBy('local_id', 'desc')->first();
$currentMaxId = $entity->comments()->max('local_id');
return ($comment->local_id ?? 0) + 1;
return $currentMaxId + 1;
}
}

View File

@ -1,12 +1,12 @@
<?php
namespace BookStack\Http\Controllers;
namespace BookStack\Activity\Controllers;
use BookStack\Actions\Activity;
use BookStack\Actions\ActivityType;
use BookStack\Activity\ActivityType;
use BookStack\Activity\Models\Activity;
use BookStack\Http\Controller;
use BookStack\Util\SimpleListOptions;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AuditLogController extends Controller
{

View File

@ -1,19 +1,18 @@
<?php
namespace BookStack\Http\Controllers;
namespace BookStack\Activity\Controllers;
use BookStack\Actions\CommentRepo;
use BookStack\Activity\CommentRepo;
use BookStack\Entities\Models\Page;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
class CommentController extends Controller
{
protected $commentRepo;
public function __construct(CommentRepo $commentRepo)
{
$this->commentRepo = $commentRepo;
public function __construct(
protected CommentRepo $commentRepo
) {
}
/**
@ -42,7 +41,13 @@ class CommentController extends Controller
$this->checkPermission('comment-create-all');
$comment = $this->commentRepo->create($page, $request->get('text'), $request->get('parent_id'));
return view('comments.comment', ['comment' => $comment]);
return view('comments.comment-branch', [
'readOnly' => false,
'branch' => [
'comment' => $comment,
'children' => [],
]
]);
}
/**
@ -62,7 +67,7 @@ class CommentController extends Controller
$comment = $this->commentRepo->update($comment, $request->get('text'));
return view('comments.comment', ['comment' => $comment]);
return view('comments.comment', ['comment' => $comment, 'readOnly' => false]);
}
/**

View File

@ -1,11 +1,12 @@
<?php
namespace BookStack\Http\Controllers;
namespace BookStack\Activity\Controllers;
use BookStack\Activity\Models\Favouritable;
use BookStack\App\Model;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Queries\TopFavourites;
use BookStack\Interfaces\Favouritable;
use BookStack\Model;
use BookStack\Http\Controller;
use Illuminate\Http\Request;
class FavouriteController extends Controller

View File

@ -1,8 +1,9 @@
<?php
namespace BookStack\Http\Controllers;
namespace BookStack\Activity\Controllers;
use BookStack\Actions\TagRepo;
use BookStack\Activity\TagRepo;
use BookStack\Http\Controller;
use BookStack\Util\SimpleListOptions;
use Illuminate\Http\Request;

View File

@ -1,10 +1,11 @@
<?php
namespace BookStack\Http\Controllers;
namespace BookStack\Activity\Controllers;
use BookStack\Actions\ActivityType;
use BookStack\Actions\Queries\WebhooksAllPaginatedAndSorted;
use BookStack\Actions\Webhook;
use BookStack\Activity\ActivityType;
use BookStack\Activity\Models\Webhook;
use BookStack\Activity\Queries\WebhooksAllPaginatedAndSorted;
use BookStack\Http\Controller;
use BookStack\Util\SimpleListOptions;
use Illuminate\Http\Request;

View File

@ -1,11 +1,13 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity;
use BookStack\Auth\User;
use BookStack\Activity\Models\Loggable;
use BookStack\Activity\Models\Webhook;
use BookStack\Activity\Tools\WebhookFormatter;
use BookStack\Facades\Theme;
use BookStack\Interfaces\Loggable;
use BookStack\Theming\ThemeEvents;
use BookStack\Users\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

View File

@ -1,11 +1,11 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Models;
use BookStack\Auth\Permissions\JointPermission;
use BookStack\Auth\User;
use BookStack\App\Model;
use BookStack\Entities\Models\Entity;
use BookStack\Model;
use BookStack\Permissions\Models\JointPermission;
use BookStack\Users\Models\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
@ -19,6 +19,8 @@ use Illuminate\Support\Str;
* @property string $entity_type
* @property int $entity_id
* @property int $user_id
* @property Carbon $created_at
* @property Carbon $updated_at
*/
class Activity extends Model
{

View File

@ -1,9 +1,9 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Models;
use BookStack\Model;
use BookStack\Traits\HasCreatorAndUpdater;
use BookStack\App\Model;
use BookStack\Users\Models\HasCreatorAndUpdater;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\MorphTo;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Interfaces;
namespace BookStack\Activity\Models;
use Illuminate\Database\Eloquent\Relations\MorphMany;

View File

@ -1,9 +1,9 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Models;
use BookStack\Auth\Permissions\JointPermission;
use BookStack\Model;
use BookStack\App\Model;
use BookStack\Permissions\Models\JointPermission;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Interfaces;
namespace BookStack\Activity\Models;
interface Loggable
{

View File

@ -1,9 +1,9 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Models;
use BookStack\Auth\Permissions\JointPermission;
use BookStack\Model;
use BookStack\App\Model;
use BookStack\Permissions\Models\JointPermission;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;

View File

@ -1,10 +1,9 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Models;
use BookStack\Auth\Permissions\JointPermission;
use BookStack\Interfaces\Viewable;
use BookStack\Model;
use BookStack\App\Model;
use BookStack\Permissions\Models\JointPermission;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
@ -55,12 +54,4 @@ class View extends Model
return $view->views;
}
/**
* Clear all views from the system.
*/
public static function clearAll()
{
static::query()->truncate();
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Interfaces;
namespace BookStack\Activity\Models;
use Illuminate\Database\Eloquent\Relations\MorphMany;

View File

@ -1,8 +1,8 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Models;
use BookStack\Interfaces\Loggable;
use BookStack\Activity\ActivityType;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

View File

@ -1,8 +1,8 @@
<?php
namespace BookStack\Actions\Queries;
namespace BookStack\Activity\Queries;
use BookStack\Actions\Webhook;
use BookStack\Activity\Models\Webhook;
use BookStack\Util\SimpleListOptions;
use Illuminate\Pagination\LengthAwarePaginator;

View File

@ -1,9 +1,10 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity;
use BookStack\Auth\Permissions\PermissionApplicator;
use BookStack\Activity\Models\Tag;
use BookStack\Entities\Models\Entity;
use BookStack\Permissions\PermissionApplicator;
use BookStack\Util\SimpleListOptions;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

View File

@ -1,10 +1,13 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Tools;
use BookStack\Activity\DispatchWebhookJob;
use BookStack\Activity\Models\Activity;
use BookStack\Activity\Models\Loggable;
use BookStack\Activity\Models\Webhook;
use BookStack\Entities\Models\Entity;
use BookStack\Facades\Theme;
use BookStack\Interfaces\Loggable;
use BookStack\Theming\ThemeEvents;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;

View File

@ -0,0 +1,102 @@
<?php
namespace BookStack\Activity\Tools;
use BookStack\Activity\Models\Comment;
use BookStack\Entities\Models\Page;
class CommentTree
{
/**
* The built nested tree structure array.
* @var array{comment: Comment, depth: int, children: array}[]
*/
protected array $tree;
protected array $comments;
public function __construct(
protected Page $page
) {
$this->comments = $this->loadComments();
$this->tree = $this->createTree($this->comments);
}
public function enabled(): bool
{
return !setting('app-disable-comments');
}
public function empty(): bool
{
return count($this->tree) === 0;
}
public function count(): int
{
return count($this->comments);
}
public function get(): array
{
return $this->tree;
}
/**
* @param Comment[] $comments
*/
protected function createTree(array $comments): array
{
$byId = [];
foreach ($comments as $comment) {
$byId[$comment->local_id] = $comment;
}
$childMap = [];
foreach ($comments as $comment) {
$parent = $comment->parent_id;
if (is_null($parent) || !isset($byId[$parent])) {
$parent = 0;
}
if (!isset($childMap[$parent])) {
$childMap[$parent] = [];
}
$childMap[$parent][] = $comment->local_id;
}
$tree = [];
foreach ($childMap[0] ?? [] as $childId) {
$tree[] = $this->createTreeForId($childId, 0, $byId, $childMap);
}
return $tree;
}
protected function createTreeForId(int $id, int $depth, array &$byId, array &$childMap): array
{
$childIds = $childMap[$id] ?? [];
$children = [];
foreach ($childIds as $childId) {
$children[] = $this->createTreeForId($childId, $depth + 1, $byId, $childMap);
}
return [
'comment' => $byId[$id],
'depth' => $depth,
'children' => $children,
];
}
protected function loadComments(): array
{
if (!$this->enabled()) {
return [];
}
return $this->page->comments()
->with('createdBy')
->get()
->all();
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Tools;
class IpFormatter
{

View File

@ -1,6 +1,8 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Tools;
use BookStack\Activity\Models\Tag;
class TagClassGenerator
{

View File

@ -1,12 +1,14 @@
<?php
namespace BookStack\Actions;
namespace BookStack\Activity\Tools;
use BookStack\Auth\User;
use BookStack\Activity\ActivityType;
use BookStack\Activity\Models\Loggable;
use BookStack\Activity\Models\Webhook;
use BookStack\App\Model;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page;
use BookStack\Interfaces\Loggable;
use BookStack\Model;
use BookStack\Users\Models\User;
use Illuminate\Support\Carbon;
class WebhookFormatter

View File

@ -1,8 +1,8 @@
<?php
namespace BookStack\Http\Controllers\Api;
namespace BookStack\Api;
use BookStack\Api\ApiDocsGenerator;
use BookStack\Http\ApiController;
class ApiDocsController extends ApiController
{
@ -28,4 +28,12 @@ class ApiDocsController extends ApiController
return response()->json($docs);
}
/**
* Redirect to the API docs page.
*/
public function redirect()
{
return redirect('/api/docs');
}
}

View File

@ -2,7 +2,7 @@
namespace BookStack\Api;
use BookStack\Http\Controllers\Api\ApiController;
use BookStack\Http\ApiController;
use Exception;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Support\Collection;
@ -16,8 +16,8 @@ use ReflectionMethod;
class ApiDocsGenerator
{
protected $reflectionClasses = [];
protected $controllerClasses = [];
protected array $reflectionClasses = [];
protected array $controllerClasses = [];
/**
* Load the docs form the cache if existing
@ -139,9 +139,10 @@ class ApiDocsGenerator
protected function parseDescriptionFromMethodComment(string $comment): string
{
$matches = [];
preg_match_all('/^\s*?\*\s((?![@\s]).*?)$/m', $comment, $matches);
preg_match_all('/^\s*?\*\s?($|((?![\/@\s]).*?))$/m', $comment, $matches);
return implode(' ', $matches[1] ?? []);
$text = implode(' ', $matches[1] ?? []);
return str_replace(' ', "\n", $text);
}
/**

View File

@ -2,8 +2,8 @@
namespace BookStack\Api;
use BookStack\Auth\User;
use BookStack\Interfaces\Loggable;
use BookStack\Activity\Models\Loggable;
use BookStack\Users\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Carbon;

View File

@ -2,7 +2,7 @@
namespace BookStack\Api;
use BookStack\Auth\Access\LoginService;
use BookStack\Access\LoginService;
use BookStack\Exceptions\ApiAuthException;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Authenticatable;

View File

@ -1,10 +1,10 @@
<?php
namespace BookStack\Http\Controllers;
namespace BookStack\Api;
use BookStack\Actions\ActivityType;
use BookStack\Api\ApiToken;
use BookStack\Auth\User;
use BookStack\Activity\ActivityType;
use BookStack\Http\Controller;
use BookStack\Users\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
@ -58,7 +58,6 @@ class UserApiTokenController extends Controller
$token->save();
session()->flash('api-token-secret:' . $token->id, $secret);
$this->showSuccessNotification(trans('settings.user_api_token_create_success'));
$this->logActivity(ActivityType::API_TOKEN_CREATE, $token);
return redirect($user->getEditUrl('/api-tokens/' . $token->id));
@ -96,7 +95,6 @@ class UserApiTokenController extends Controller
'expires_at' => $request->get('expires_at') ?: ApiToken::defaultExpiry(),
])->save();
$this->showSuccessNotification(trans('settings.user_api_token_update_success'));
$this->logActivity(ActivityType::API_TOKEN_UPDATE, $token);
return redirect($user->getEditUrl('/api-tokens/' . $token->id));
@ -123,7 +121,6 @@ class UserApiTokenController extends Controller
[$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId);
$token->delete();
$this->showSuccessNotification(trans('settings.user_api_token_delete_success'));
$this->logActivity(ActivityType::API_TOKEN_DELETE, $token);
return redirect($user->getEditUrl('#api_tokens'));

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack;
namespace BookStack\App;
class Application extends \Illuminate\Foundation\Application
{

View File

@ -1,8 +1,8 @@
<?php
namespace BookStack\Http\Controllers;
namespace BookStack\App;
use BookStack\Actions\ActivityQueries;
use BookStack\Activity\ActivityQueries;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Queries\RecentlyViewed;
@ -10,6 +10,7 @@ use BookStack\Entities\Queries\TopFavourites;
use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Repos\BookshelfRepo;
use BookStack\Entities\Tools\PageContent;
use BookStack\Http\Controller;
use BookStack\Uploads\FaviconHandler;
use BookStack\Util\SimpleListOptions;
use Illuminate\Http\Request;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack;
namespace BookStack\App;
use Illuminate\Database\Eloquent\Model as EloquentModel;

View File

@ -1,9 +1,9 @@
<?php
namespace BookStack\Providers;
namespace BookStack\App\Providers;
use BookStack\Actions\ActivityLogger;
use BookStack\Auth\Access\SocialAuthService;
use BookStack\Access\SocialAuthService;
use BookStack\Activity\Tools\ActivityLogger;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;

View File

@ -1,14 +1,14 @@
<?php
namespace BookStack\Providers;
namespace BookStack\App\Providers;
use BookStack\Access\ExternalBaseUserProvider;
use BookStack\Access\Guards\AsyncExternalBaseSessionGuard;
use BookStack\Access\Guards\LdapSessionGuard;
use BookStack\Access\LdapService;
use BookStack\Access\LoginService;
use BookStack\Access\RegistrationService;
use BookStack\Api\ApiTokenGuard;
use BookStack\Auth\Access\ExternalBaseUserProvider;
use BookStack\Auth\Access\Guards\AsyncExternalBaseSessionGuard;
use BookStack\Auth\Access\Guards\LdapSessionGuard;
use BookStack\Auth\Access\LdapService;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\RegistrationService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\Rules\Password;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Providers;
namespace BookStack\App\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use SocialiteProviders\Manager\SocialiteWasCalled;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Providers;
namespace BookStack\App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Providers;
namespace BookStack\App\Providers;
use BookStack\Theming\ThemeEvents;
use BookStack\Theming\ThemeService;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Providers;
namespace BookStack\App\Providers;
use BookStack\Translation\FileLoader;
use BookStack\Translation\MessageSelector;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Providers;
namespace BookStack\App\Providers;
use BookStack\Uploads\ImageService;
use Illuminate\Support\Facades\Validator;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Providers;
namespace BookStack\App\Providers;
use BookStack\Entities\BreadcrumbsViewComposer;
use Illuminate\Pagination\Paginator;

View File

@ -1,6 +1,6 @@
<?php
namespace BookStack\Interfaces;
namespace BookStack\App;
/**
* Assigned to models that can have slugs.

View File

@ -1,9 +1,9 @@
<?php
use BookStack\Auth\Permissions\PermissionApplicator;
use BookStack\Auth\User;
use BookStack\Model;
use BookStack\App\Model;
use BookStack\Permissions\PermissionApplicator;
use BookStack\Settings\SettingService;
use BookStack\Users\Models\User;
/**
* Get the path to a versioned file.

View File

@ -1,136 +0,0 @@
<?php
namespace BookStack\Auth\Access;
/**
* Class Ldap
* An object-orientated thin abstraction wrapper for common PHP LDAP functions.
* Allows the standard LDAP functions to be mocked for testing.
*/
class Ldap
{
/**
* Connect to an LDAP server.
*
* @return resource
*/
public function connect(string $hostName, int $port)
{
return ldap_connect($hostName, $port);
}
/**
* Set the value of a LDAP option for the given connection.
*
* @param resource $ldapConnection
* @param mixed $value
*/
public function setOption($ldapConnection, int $option, $value): bool
{
return ldap_set_option($ldapConnection, $option, $value);
}
/**
* Start TLS on the given LDAP connection.
*/
public function startTls($ldapConnection): bool
{
return ldap_start_tls($ldapConnection);
}
/**
* Set the version number for the given ldap connection.
*
* @param resource $ldapConnection
*/
public function setVersion($ldapConnection, int $version): bool
{
return $this->setOption($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, $version);
}
/**
* Search LDAP tree using the provided filter.
*
* @param resource $ldapConnection
* @param string $baseDn
* @param string $filter
* @param array|null $attributes
*
* @return resource
*/
public function search($ldapConnection, $baseDn, $filter, array $attributes = null)
{
return ldap_search($ldapConnection, $baseDn, $filter, $attributes);
}
/**
* Get entries from an ldap search result.
*
* @param resource $ldapConnection
* @param resource $ldapSearchResult
*
* @return array
*/
public function getEntries($ldapConnection, $ldapSearchResult)
{
return ldap_get_entries($ldapConnection, $ldapSearchResult);
}
/**
* Search and get entries immediately.
*
* @param resource $ldapConnection
* @param string $baseDn
* @param string $filter
* @param array|null $attributes
*
* @return resource
*/
public function searchAndGetEntries($ldapConnection, $baseDn, $filter, array $attributes = null)
{
$search = $this->search($ldapConnection, $baseDn, $filter, $attributes);
return $this->getEntries($ldapConnection, $search);
}
/**
* Bind to LDAP directory.
*
* @param resource $ldapConnection
* @param string $bindRdn
* @param string $bindPassword
*
* @return bool
*/
public function bind($ldapConnection, $bindRdn = null, $bindPassword = null)
{
return ldap_bind($ldapConnection, $bindRdn, $bindPassword);
}
/**
* Explode a LDAP dn string into an array of components.
*
* @param string $dn
* @param int $withAttrib
*
* @return array
*/
public function explodeDn(string $dn, int $withAttrib)
{
return ldap_explode_dn($dn, $withAttrib);
}
/**
* Escape a string for use in an LDAP filter.
*
* @param string $value
* @param string $ignore
* @param int $flags
*
* @return string
*/
public function escape(string $value, string $ignore = '', int $flags = 0)
{
return ldap_escape($value, $ignore, $flags);
}
}

View File

@ -139,14 +139,14 @@ return [
SocialiteProviders\Manager\ServiceProvider::class,
// BookStack custom service providers
BookStack\Providers\ThemeServiceProvider::class,
BookStack\Providers\AppServiceProvider::class,
BookStack\Providers\AuthServiceProvider::class,
BookStack\Providers\EventServiceProvider::class,
BookStack\Providers\RouteServiceProvider::class,
BookStack\Providers\TranslationServiceProvider::class,
BookStack\Providers\ValidationRuleServiceProvider::class,
BookStack\Providers\ViewTweaksServiceProvider::class,
\BookStack\App\Providers\ThemeServiceProvider::class,
\BookStack\App\Providers\AppServiceProvider::class,
\BookStack\App\Providers\AuthServiceProvider::class,
\BookStack\App\Providers\EventServiceProvider::class,
\BookStack\App\Providers\RouteServiceProvider::class,
\BookStack\App\Providers\TranslationServiceProvider::class,
\BookStack\App\Providers\ValidationRuleServiceProvider::class,
\BookStack\App\Providers\ViewTweaksServiceProvider::class,
],
// Class Aliases

View File

@ -59,12 +59,12 @@ return [
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => \BookStack\Auth\User::class,
'model' => \BookStack\Users\Models\User::class,
],
'external' => [
'driver' => 'external-users',
'model' => \BookStack\Auth\User::class,
'model' => \BookStack\Users\Models\User::class,
],
// 'users' => [

View File

@ -8,6 +8,10 @@
* Do not edit this file unless you're happy to maintain any changes yourself.
*/
// Configured mail encryption method.
// STARTTLS should still be attempted, but tls/ssl forces TLS usage.
$mailEncryption = env('MAIL_ENCRYPTION', null);
return [
// Mail driver to use.
@ -27,9 +31,9 @@ return [
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'scheme' => ($mailEncryption === 'tls' || $mailEncryption === 'ssl') ? 'smtps' : null,
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_PORT', 587),
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'verify_peer' => env('MAIL_VERIFY_SSL', true),

View File

@ -6,7 +6,7 @@ use BookStack\Uploads\ImageService;
use Illuminate\Console\Command;
use Symfony\Component\Console\Output\OutputInterface;
class CleanupImages extends Command
class CleanupImagesCommand extends Command
{
/**
* The name and signature of the console command.
@ -25,60 +25,49 @@ class CleanupImages extends Command
*/
protected $description = 'Cleanup images and drawings';
protected $imageService;
/**
* Create a new command instance.
*
* @param \BookStack\Uploads\ImageService $imageService
*/
public function __construct(ImageService $imageService)
{
$this->imageService = $imageService;
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
public function handle(ImageService $imageService): int
{
$checkRevisions = $this->option('all') ? false : true;
$dryRun = $this->option('force') ? false : true;
$checkRevisions = !$this->option('all');
$dryRun = !$this->option('force');
if (!$dryRun) {
$proceed = $this->confirm("This operation is destructive and is not guaranteed to be fully accurate.\nEnsure you have a backup of your images.\nAre you sure you want to proceed?");
$this->warn("This operation is destructive and is not guaranteed to be fully accurate.\nEnsure you have a backup of your images.\n");
$proceed = $this->confirm("Are you sure you want to proceed?");
if (!$proceed) {
return;
return 0;
}
}
$deleted = $this->imageService->deleteUnusedImages($checkRevisions, $dryRun);
$deleted = $imageService->deleteUnusedImages($checkRevisions, $dryRun);
$deleteCount = count($deleted);
if ($dryRun) {
$this->comment('Dry run, No images have been deleted');
$this->comment('Dry run, no images have been deleted');
$this->comment($deleteCount . ' images found that would have been deleted');
$this->showDeletedImages($deleted);
$this->comment('Run with -f or --force to perform deletions');
return;
return 0;
}
$this->showDeletedImages($deleted);
$this->comment($deleteCount . ' images deleted');
return 0;
}
protected function showDeletedImages($paths)
protected function showDeletedImages($paths): void
{
if ($this->getOutput()->getVerbosity() <= OutputInterface::VERBOSITY_NORMAL) {
return;
}
if (count($paths) > 0) {
$this->line('Images to delete:');
}
foreach ($paths as $path) {
$this->line($path);
}

View File

@ -2,10 +2,10 @@
namespace BookStack\Console\Commands;
use BookStack\Actions\Activity;
use BookStack\Activity\Models\Activity;
use Illuminate\Console\Command;
class ClearActivity extends Command
class ClearActivityCommand extends Command
{
/**
* The name and signature of the console command.
@ -21,27 +21,13 @@ class ClearActivity extends Command
*/
protected $description = 'Clear user activity from the system';
protected $activity;
/**
* Create a new command instance.
*
* @param Activity $activity
*/
public function __construct(Activity $activity)
{
$this->activity = $activity;
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
public function handle(): int
{
$this->activity->newQuery()->truncate();
Activity::query()->truncate();
$this->comment('System activity cleared');
return 0;
}
}

View File

@ -5,7 +5,7 @@ namespace BookStack\Console\Commands;
use BookStack\Entities\Models\PageRevision;
use Illuminate\Console\Command;
class ClearRevisions extends Command
class ClearRevisionsCommand extends Command
{
/**
* The name and signature of the console command.
@ -23,28 +23,14 @@ class ClearRevisions extends Command
*/
protected $description = 'Clear page revisions';
protected $pageRevision;
/**
* Create a new command instance.
*
* @param PageRevision $pageRevision
*/
public function __construct(PageRevision $pageRevision)
{
$this->pageRevision = $pageRevision;
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
public function handle(): int
{
$deleteTypes = $this->option('all') ? ['version', 'update_draft'] : ['version'];
$this->pageRevision->newQuery()->whereIn('type', $deleteTypes)->delete();
PageRevision::query()->whereIn('type', $deleteTypes)->delete();
$this->comment('Revisions deleted');
return 0;
}
}

View File

@ -2,10 +2,10 @@
namespace BookStack\Console\Commands;
use BookStack\Actions\View;
use BookStack\Activity\Models\View;
use Illuminate\Console\Command;
class ClearViews extends Command
class ClearViewsCommand extends Command
{
/**
* The name and signature of the console command.
@ -21,22 +21,13 @@ class ClearViews extends Command
*/
protected $description = 'Clear all view-counts for all entities';
/**
* Create a new command instance.
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
public function handle(): int
{
View::clearAll();
View::query()->truncate();
$this->comment('Views cleared');
return 0;
}
}

View File

@ -6,7 +6,7 @@ use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Tools\PermissionsUpdater;
use Illuminate\Console\Command;
class CopyShelfPermissions extends Command
class CopyShelfPermissionsCommand extends Command
{
/**
* The name and signature of the console command.
@ -25,25 +25,10 @@ class CopyShelfPermissions extends Command
*/
protected $description = 'Copy shelf permissions to all child books';
protected PermissionsUpdater $permissionsUpdater;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(PermissionsUpdater $permissionsUpdater)
{
$this->permissionsUpdater = $permissionsUpdater;
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
public function handle(PermissionsUpdater $permissionsUpdater): int
{
$shelfSlug = $this->option('slug');
$cascadeAll = $this->option('all');
@ -52,7 +37,7 @@ class CopyShelfPermissions extends Command
if (!$cascadeAll && !$shelfSlug) {
$this->error('Either a --slug or --all option must be provided.');
return;
return 1;
}
if ($cascadeAll) {
@ -63,7 +48,7 @@ class CopyShelfPermissions extends Command
);
if (!$continue && !$this->hasOption('no-interaction')) {
return;
return 0;
}
$shelves = Bookshelf::query()->get(['id']);
@ -77,10 +62,11 @@ class CopyShelfPermissions extends Command
}
foreach ($shelves as $shelf) {
$this->permissionsUpdater->updateBookPermissionsFromShelf($shelf, false);
$permissionsUpdater->updateBookPermissionsFromShelf($shelf, false);
$this->info('Copied permissions for shelf [' . $shelf->id . ']');
}
$this->info('Permissions copied for ' . $shelves->count() . ' shelves.');
return 0;
}
}

Some files were not shown because too many files have changed in this diff Show More