Compare commits

...

77 Commits

Author SHA1 Message Date
Dan Brown
bbea76668b Updated version and assets for release v23.06 2023-06-30 11:06:19 +01:00
Dan Brown
becc630acf Merge branch 'development' into release 2023-06-30 11:05:57 +01:00
Dan Brown
80635144b1 Meta: Updated dev version and translation attribution 2023-06-30 10:55:54 +01:00
Dan Brown
d23cfc3d32 Updated test to match German translation 2023-06-28 23:46:59 +01:00
Dan Brown
5ea2d0c57b WYSIWYG: Fixed growing rows on Firefox
Occured when the cell contained any block content with a differnt line
height to the table cell itself.
In firefox, cells with a height would end up with an actual greater
real cell height, which messed up TinyMCE resize calculations, causing
tables to grow.
Adding default vertical-align: top, changes this behaviour to get proper
cell heights.
Related to Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=569645
Have tested that editor cell text align options can still be used with
this.

For #4337
2023-06-28 23:28:31 +01:00
Dan Brown
b425d0f65c Updated tinymce to v6.5.1 2023-06-28 22:45:21 +01:00
Dan Brown
63f03046b3 Updated translations with latest Crowdin changes (#4256) 2023-06-28 17:54:32 +01:00
Dan Brown
7f98906b0f Comments: Tweaked design to be more consistent and compact 2023-06-28 13:41:14 +01:00
Dan Brown
b24246085f CSS: Tweaked css heading font to fall back to body font 2023-06-28 09:35:30 +01:00
Dan Brown
bae0e80cee Merge pull request #4320 from devdot/improve-api-auth-exception
Improve ApiAuthException control flow
2023-06-25 23:35:19 +01:00
Dan Brown
847a57a49a Shelf permissions: Removed unused 'create' permission from view
Was causing confusion.
Added test to cover.
Also added migration to remove existing create entries to pre-emptively
avoid issues in future if 'create' is used again.
2023-06-25 23:22:49 +01:00
Dan Brown
c74a2608c4 Updated php dependencies 2023-06-24 11:32:54 +01:00
Dan Brown
dbb6c87580 Mail Config: Updated how TLS is configured
After full review of current MAIL_ENCRYPTION usage in laravel and
smyfony mailer, this updates the options in BookStack to be simplified
and specific in usage:

- Removed mail.mailers.smtp.encryption option since it did not actually
  affect anything in the current state of dependancies.
- Updated MAIL_ENCRYPTION so values of tls OR ssl will force-enable tls
  via 'scheme' option with laravel passes to the SMTP transfport, which
  Smyfony uses as an indicator to force TLS.

When MAIL_ENCRYPTION is not used, STARTTLS will still be attempted by
symfony mailer.
Updated .env files to refer to BookStack docs (which was updated for
this) and to reflect correct default port.
Related to #4342
2023-06-24 11:32:07 +01:00
Dan Brown
9ae17efce9 Shelf view: Updated books to be database sorted
Fixes issue where sorting would not match other database-sorted parts of
app due to case sensitivity differences.
Added test to cover.

For #4341
2023-06-23 16:42:40 +01:00
Dan Brown
0a485baf8b Merge pull request #4332 from BookStackApp/api_docs_tweaks
API Docs: Allowed multi-paragraph descriptions
2023-06-20 23:47:58 +01:00
Dan Brown
38883e8d46 API Docs: Allowed multi-paragraph descriptions
Added support for mulit-line endpoint descriptions via blank
intermediate lines in php controller method docblocks.

Also tweaks endpoint header design for better flexing and alignment.
2023-06-20 23:44:39 +01:00
Dan Brown
4bb2cf5c5f Pages API: Added extra helper text to read endpoint 2023-06-20 17:15:32 +01:00
Dan Brown
8b935e71d1 Pages API: Made raw_html available on page responses
To provide a way to see the original un-pre-processed database HTML
content.

For #4310
2023-06-20 17:07:46 +01:00
Dan Brown
41c3ed154b Content Permissions API: Fixed param combination bug
Fixes issue where providing owner_id alongside certain
fallback_permissions would cause the owner change not to take affect,
due to bad variable shadowing.

For #4323
2023-06-20 14:13:26 +01:00
Dan Brown
f5396ecaf0 Merge pull request #4317 from devdot/http-fetch-improve-exception-logging
Modify HttpFetchException flow to log the exception
2023-06-20 13:49:23 +01:00
Thomas Kuschan
97d46f43a7 Revert some changes to HttpFetchException 2023-06-19 08:47:47 +02:00
Dan Brown
22fc720c22 Merge pull request #4318 from devdot/improve-json-debug-exception
Change JsonDebugException to Responsable interface
2023-06-18 17:52:57 +01:00
Dan Brown
eb44748084 Merge branch 'development' of github.com:BookStackApp/BookStack into development 2023-06-17 18:22:01 +01:00
Dan Brown
00b5dd7852 Users API: Fixed incorrect created_at date on index endpoint
For #4325
2023-06-17 18:18:17 +01:00
Dan Brown
9f4450fea9 Merge pull request #4322 from BookStackApp/comments_in_editor
Added read-only comments listing into page editor
2023-06-16 13:23:40 +01:00
Dan Brown
88aae5b004 Comments: Fixed failing tests due to unset template variable 2023-06-16 13:17:11 +01:00
Dan Brown
9a2ef7ef44 Comments: Added read-only listing into page editor 2023-06-16 13:08:04 +01:00
Thomas Kuschan
74097bd47c Simplify ApiAuthException control flow
Remove unnecessary UnauthorizedException
and make ApiAuthException compatible with HttpExceptionInterface.

Move the creation of a rsponse for the exception
from ApiAuthenticate middleware into the application exception handler.
2023-06-16 10:00:02 +02:00
Thomas Kuschan
7249d947ec Change JsonDebugException to Responsable interface
In all other exceptions, when a Response is supposed to be returned,
the Responsable interface is used instead of render.
2023-06-16 09:53:12 +02:00
Thomas Kuschan
c35080d6ce Modify HttpFetchException handle to log exception
Within the flow of HttpFetchException, the actual exception from curl is preserved and logged. Make HttpFetchException a pretty exception for when it is shown to users.
2023-06-16 09:21:25 +02:00
Dan Brown
ec775aec02 Merge branch 'fix-api-404' into development 2023-06-15 17:08:51 +01:00
Dan Brown
e72cf61f7e Exceptions: Added some types, simplified some classes
During review of #4291
2023-06-15 17:07:40 +01:00
Dan Brown
70be2e8c9e CSS: Reduced styles used in export formats
Extracted many main page content styles to own scss partial.
Styles could do with a more general clean-up.

Closes #4303
2023-06-14 13:19:29 +01:00
Dan Brown
610ad0d613 Updated fonts to be defined via CSS variables
Exports system remains separate due to lacking css variable support.
2023-06-14 12:53:48 +01:00
Thomas Kuschan
34d8268b2b Refactor notify exception to clean up api exception handling 2023-06-14 11:08:20 +02:00
Thomas Kuschan
321a459421 Refactor exception handling by using interface 2023-06-13 18:52:02 +02:00
Dan Brown
56a40f1b23 Merge pull request #4301 from BookStackApp/css_color_variables
CSS: Updated status colors to be CSS variables, Added dark variants
2023-06-13 15:54:27 +01:00
Dan Brown
f7ad387a10 CSS: Updated status colors to be CSS variables, Added dark variants
Needed some level of harcoding though due to callouts using colors,
which can't be css colors as DOMPDF won't understand these.
Use css variables elsewhere and added new dark variants to fit a bit
better.
2023-06-13 15:52:33 +01:00
Dan Brown
b01bbf9c89 Page Drafts: Added new "Delete Draft" action to draft menu
Provides a way for users to actually delte their user drafts where
required.
For #3927

Added test to cover new endpoint.

Makes update to MD editor #setText so that new selection is within new
range, otherwise it errors and fails operation.
2023-06-13 15:13:07 +01:00
Dan Brown
f39938c4e3 Added activity text for each activity type
Ensures some sensible text is always in webhook text data.
Also aligned some notification reporting to use centralised activity
system instead of custom success events.

For #4216
2023-06-12 16:47:36 +01:00
Dan Brown
af0b4fa851 Search: Updated popular items query, load parent book for chapters/pages
Primarily intended to show parent book for chapters when moving/copying
pages, since the default parent selector interfaces, which used the
entity-selector search endpoint, would run this popular query when no
term was present as a default backup.

For #4264
2023-06-10 15:08:07 +01:00
Dan Brown
777027bc48 Permissions: Updated guest user handling so additional roles apply
Previously additional roles would only partially apply (system or "all"
permissions). This aligns the query-handling of permissions so that
additional roles will be used for permission queries.

Adds migration to detach existing roles as a safety precaution since
this is likely to widen permissions in scenarios that the public user
has other roles assigned already.

For #1229
2023-06-10 11:37:01 +01:00
Dan Brown
1e220c473f API: Fixed misaligned image datetime format
For #4294
2023-06-10 10:54:56 +01:00
Dan Brown
59c7077fd9 Fixed error on pages without comments 2023-06-09 19:21:49 +01:00
Dan Brown
07de6ecdc5 Merge pull request #4286 from BookStackApp/comment_threads
Comment threads
2023-06-09 17:39:02 +01:00
Dan Brown
19e39ddd1f Comments: Updated reply-to and general styling
Updated reply inidicator to fit with new nesting system, only showing on
view when nest within nesting structure.

Updated the general design to be a bit cleaner and better adapt on
mobile.

Tested on FF+Chrome, inc. dark mode.
2023-06-09 17:36:30 +01:00
Dan Brown
3bede42121 Comments: Added visual nesting limit, added nesting test 2023-06-09 11:12:39 +01:00
Dan Brown
3b46b92bb9 Comments: Updated to show form in expected location
Includes a change of create response to use a branch as a template.
2023-06-08 15:09:54 +01:00
Thomas Kuschan
9ba7d1e6c5 Fix "HTTP 500 on not found" bug #4290 2023-06-08 10:50:12 +02:00
Thomas Kuschan
ecf99fa0ed Add test showing the "HTTP 500 on not found" bug 2023-06-08 09:53:53 +02:00
Dan Brown
154924cc0c Comments: updated component and split out code
Split out comment component code so single-comment actions (delete, edit) are handled within their own compontent.
Modernised existing component code.
2023-06-07 17:47:37 +01:00
Dan Brown
4b9f6beb37 Comments: Updated to show as nested threads
Initial functional implementation, a lot of tweaking and adapting to be
done.
2023-06-07 13:24:49 +01:00
Dan Brown
88785aa71b Page display pointer: Considerably improved accessibility
- Updated pointer to move within content DOM so that you can back-focus
  into the pointer if desired.
- Added new "Section select mode" which toggles focusabiltiy for main
  content sections, with ability to show pointer via enter press on
  these.
- Updated pointer with proper input/button labelling.

Tested via orca screen reader on Firefox/Fedora/Gnome.
For #3975
2023-05-31 16:44:20 +01:00
Dan Brown
0323ebccd3 Chapters API: Allowed move via book_id property
Aligns it with pages and with the book_id property already being part of
the API.
For #4272.
2023-05-30 20:55:24 +01:00
Dan Brown
3f5dc10cd4 Altered ldap_connect usage, cleaned up LDAP classes
Primarily updated ldap_connect to avoid usage of deprecated syntax.
Updated tests and service to handle as expected.
Cleaned up syntax and types in classes while there.

Closes #4274
2023-05-30 13:12:00 +01:00
Dan Brown
242d23788d Merge pull request #4265 from BookStackApp/image_manager_responsive
Enhanced Responsive Image Manager
2023-05-29 16:52:55 +01:00
Dan Brown
08c73f02c9 Removed forced initial image manager display 2023-05-29 16:23:37 +01:00
Dan Brown
a139c2a8a2 Image manager: Improved screen reader usage
Added extra labels, or removed duplicate info, to improve screen reader
ux after testing via gnome/fedora/firefox screen reader usage testing.
2023-05-29 16:21:44 +01:00
Dan Brown
f5ef52ca59 Image manager: cleaned up style changes, dark mode support
- Updated tab handling to be smarter on initial tab selection, to first
  target non-hidden tab panels where they may be handled server-side.
- Extracted contained search box handling styles to _forms.scss, after
  merging with image-manager-specific styles since this is only usage of
  contained variant.
- Aligned focus handling on image manager UI elements.
2023-05-29 15:50:36 +01:00
Dan Brown
948e95e1ad Updated test to align with image manager HTML changes 2023-05-29 15:16:16 +01:00
Dan Brown
cd4b612019 Image update API: added update image file ability 2023-05-29 15:06:17 +01:00
Dan Brown
f78c0635ee Fixed bad /api docs redirection on sub path
Direct route redirect does not seem to go via standard URL generator so
misses off generation via base URL.
2023-05-29 14:41:59 +01:00
Dan Brown
e3c4a9d167 Added the ability to replace existing image files
- Updated UI with image form dropdown containing delete and replace
  image actions.
- Adds new endpoint and service/repo handling for replacing existing
  image.
- Includes tests to cover.
2023-05-28 17:32:22 +01:00
Dan Brown
9ff7c97911 Image manager: Added extra detail below image edit form 2023-05-28 12:07:19 +01:00
Dan Brown
89d6d862fa Image manager: extracted lang text, updated anims and search cancel
- Updated search cancel to only show when a search is active.
- Updated gallery image load animation to be much faster.
2023-05-28 11:37:49 +01:00
Dan Brown
946c9ae804 Image manager: supported a tabbed interface on mobile
Makes interface relatively usable now on mobile sizes.
Required updating of tab handling to support tabs being active at only
mobile screen sizes, include change on resize, upon support for
potentially nested tab usage.
Tab component will now search within sensible depths for finding its own
tabs and panels to control.
2023-05-27 16:58:10 +01:00
Dan Brown
dc6133c4c4 Image manager: added ability to trigger load more via scroll 2023-05-26 18:05:29 +01:00
Dan Brown
6c91e09c73 Image manager: Redesigned header bar(s) 2023-05-26 14:30:59 +01:00
Dan Brown
e467324658 Updated image manager to use grid-based css 2023-05-24 17:07:32 +01:00
Dan Brown
4c726201f9 Merge pull request #4262 from BookStackApp/command_cleanup
Command cleanup & alignment
2023-05-24 13:22:25 +01:00
Dan Brown
431aeefdda Updated command classes to include "Command" in name 2023-05-24 13:21:46 +01:00
Dan Brown
c0620da9f8 Aligned command class code
- Aligned usage of injecting through handler.
- Aligned handler return type.
- Aligned argument and arg desc format.
- Aligned lack of constructor.
2023-05-24 12:59:50 +01:00
Dan Brown
0704f1bd0d Covered untested commands with testing 2023-05-24 10:34:43 +01:00
Dan Brown
3b31ac75ec Merge pull request #4247 from BookStackApp/controller_cleanup
Revised `app/` folder layout/structure
2023-05-24 09:12:49 +01:00
Dan Brown
df6326e5ab Fixed failing references after controller/file reshuffle 2023-05-24 09:06:15 +01:00
Dan Brown
141eecb858 Cleaned up namespacing in routes
Also moved home controller and moved controllers up a level in http.
2023-05-18 20:57:05 +01:00
Dan Brown
295cd01605 Played around with a new app structure 2023-05-17 17:56:55 +01:00
691 changed files with 6975 additions and 3692 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