Showing
199 changed files
with
2061 additions
and
1033 deletions
| 1 | ### For Feature Requests | 1 | ### For Feature Requests |
| 2 | + | ||
| 2 | Desired Feature: | 3 | Desired Feature: |
| 3 | 4 | ||
| 4 | ### For Bug Reports | 5 | ### For Bug Reports |
| 5 | -PHP Version: | ||
| 6 | 6 | ||
| 7 | -MySQL Version: | 7 | +* BookStack Version: |
| 8 | +* PHP Version: | ||
| 9 | +* MySQL Version: | ||
| 8 | 10 | ||
| 9 | -Expected Behavior: | 11 | +##### Expected Behavior |
| 10 | 12 | ||
| 11 | -Actual Behavior: | 13 | +##### Actual Behavior | ... | ... |
| ... | @@ -17,9 +17,7 @@ addons: | ... | @@ -17,9 +17,7 @@ addons: |
| 17 | 17 | ||
| 18 | before_script: | 18 | before_script: |
| 19 | - mysql -u root -e 'create database `bookstack-test`;' | 19 | - mysql -u root -e 'create database `bookstack-test`;' |
| 20 | - - composer config -g github-oauth.github.com $GITHUB_ACCESS_TOKEN | ||
| 21 | - phpenv config-rm xdebug.ini | 20 | - phpenv config-rm xdebug.ini |
| 22 | - - composer self-update | ||
| 23 | - composer dump-autoload --no-interaction | 21 | - composer dump-autoload --no-interaction |
| 24 | - composer install --prefer-dist --no-interaction | 22 | - composer install --prefer-dist --no-interaction |
| 25 | - php artisan clear-compiled -n | 23 | - php artisan clear-compiled -n | ... | ... |
| ... | @@ -5,6 +5,8 @@ class Chapter extends Entity | ... | @@ -5,6 +5,8 @@ class Chapter extends Entity |
| 5 | { | 5 | { |
| 6 | protected $fillable = ['name', 'description', 'priority', 'book_id']; | 6 | protected $fillable = ['name', 'description', 'priority', 'book_id']; |
| 7 | 7 | ||
| 8 | + protected $with = ['book']; | ||
| 9 | + | ||
| 8 | /** | 10 | /** |
| 9 | * Get the book this chapter is within. | 11 | * Get the book this chapter is within. |
| 10 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo | 12 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo |
| ... | @@ -16,11 +18,12 @@ class Chapter extends Entity | ... | @@ -16,11 +18,12 @@ class Chapter extends Entity |
| 16 | 18 | ||
| 17 | /** | 19 | /** |
| 18 | * Get the pages that this chapter contains. | 20 | * Get the pages that this chapter contains. |
| 21 | + * @param string $dir | ||
| 19 | * @return mixed | 22 | * @return mixed |
| 20 | */ | 23 | */ |
| 21 | - public function pages() | 24 | + public function pages($dir = 'ASC') |
| 22 | { | 25 | { |
| 23 | - return $this->hasMany(Page::class)->orderBy('priority', 'ASC'); | 26 | + return $this->hasMany(Page::class)->orderBy('priority', $dir); |
| 24 | } | 27 | } |
| 25 | 28 | ||
| 26 | /** | 29 | /** | ... | ... |
| ... | @@ -4,6 +4,8 @@ | ... | @@ -4,6 +4,8 @@ |
| 4 | class Entity extends Ownable | 4 | class Entity extends Ownable |
| 5 | { | 5 | { |
| 6 | 6 | ||
| 7 | + protected $fieldsToSearch = ['name', 'description']; | ||
| 8 | + | ||
| 7 | /** | 9 | /** |
| 8 | * Compares this entity to another given entity. | 10 | * Compares this entity to another given entity. |
| 9 | * Matches by comparing class and id. | 11 | * Matches by comparing class and id. |
| ... | @@ -157,7 +159,7 @@ class Entity extends Ownable | ... | @@ -157,7 +159,7 @@ class Entity extends Ownable |
| 157 | * @param string[] array $wheres | 159 | * @param string[] array $wheres |
| 158 | * @return mixed | 160 | * @return mixed |
| 159 | */ | 161 | */ |
| 160 | - public function fullTextSearchQuery($fieldsToSearch, $terms, $wheres = []) | 162 | + public function fullTextSearchQuery($terms, $wheres = []) |
| 161 | { | 163 | { |
| 162 | $exactTerms = []; | 164 | $exactTerms = []; |
| 163 | $fuzzyTerms = []; | 165 | $fuzzyTerms = []; |
| ... | @@ -181,16 +183,16 @@ class Entity extends Ownable | ... | @@ -181,16 +183,16 @@ class Entity extends Ownable |
| 181 | // Perform fulltext search if relevant terms exist. | 183 | // Perform fulltext search if relevant terms exist. |
| 182 | if ($isFuzzy) { | 184 | if ($isFuzzy) { |
| 183 | $termString = implode(' ', $fuzzyTerms); | 185 | $termString = implode(' ', $fuzzyTerms); |
| 184 | - $fields = implode(',', $fieldsToSearch); | 186 | + $fields = implode(',', $this->fieldsToSearch); |
| 185 | $search = $search->selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]); | 187 | $search = $search->selectRaw('*, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS title_relevance', [$termString]); |
| 186 | $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]); | 188 | $search = $search->whereRaw('MATCH(' . $fields . ') AGAINST(? IN BOOLEAN MODE)', [$termString]); |
| 187 | } | 189 | } |
| 188 | 190 | ||
| 189 | // Ensure at least one exact term matches if in search | 191 | // Ensure at least one exact term matches if in search |
| 190 | if (count($exactTerms) > 0) { | 192 | if (count($exactTerms) > 0) { |
| 191 | - $search = $search->where(function ($query) use ($exactTerms, $fieldsToSearch) { | 193 | + $search = $search->where(function ($query) use ($exactTerms) { |
| 192 | foreach ($exactTerms as $exactTerm) { | 194 | foreach ($exactTerms as $exactTerm) { |
| 193 | - foreach ($fieldsToSearch as $field) { | 195 | + foreach ($this->fieldsToSearch as $field) { |
| 194 | $query->orWhere($field, 'like', $exactTerm); | 196 | $query->orWhere($field, 'like', $exactTerm); |
| 195 | } | 197 | } |
| 196 | } | 198 | } | ... | ... |
| ... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | ||
| 3 | use BookStack\Exceptions\FileUploadException; | 3 | use BookStack\Exceptions\FileUploadException; |
| 4 | use BookStack\Attachment; | 4 | use BookStack\Attachment; |
| 5 | -use BookStack\Repos\PageRepo; | 5 | +use BookStack\Repos\EntityRepo; |
| 6 | use BookStack\Services\AttachmentService; | 6 | use BookStack\Services\AttachmentService; |
| 7 | use Illuminate\Http\Request; | 7 | use Illuminate\Http\Request; |
| 8 | 8 | ||
| ... | @@ -10,19 +10,19 @@ class AttachmentController extends Controller | ... | @@ -10,19 +10,19 @@ class AttachmentController extends Controller |
| 10 | { | 10 | { |
| 11 | protected $attachmentService; | 11 | protected $attachmentService; |
| 12 | protected $attachment; | 12 | protected $attachment; |
| 13 | - protected $pageRepo; | 13 | + protected $entityRepo; |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | * AttachmentController constructor. | 16 | * AttachmentController constructor. |
| 17 | * @param AttachmentService $attachmentService | 17 | * @param AttachmentService $attachmentService |
| 18 | * @param Attachment $attachment | 18 | * @param Attachment $attachment |
| 19 | - * @param PageRepo $pageRepo | 19 | + * @param EntityRepo $entityRepo |
| 20 | */ | 20 | */ |
| 21 | - public function __construct(AttachmentService $attachmentService, Attachment $attachment, PageRepo $pageRepo) | 21 | + public function __construct(AttachmentService $attachmentService, Attachment $attachment, EntityRepo $entityRepo) |
| 22 | { | 22 | { |
| 23 | $this->attachmentService = $attachmentService; | 23 | $this->attachmentService = $attachmentService; |
| 24 | $this->attachment = $attachment; | 24 | $this->attachment = $attachment; |
| 25 | - $this->pageRepo = $pageRepo; | 25 | + $this->entityRepo = $entityRepo; |
| 26 | parent::__construct(); | 26 | parent::__construct(); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| ... | @@ -40,7 +40,7 @@ class AttachmentController extends Controller | ... | @@ -40,7 +40,7 @@ class AttachmentController extends Controller |
| 40 | ]); | 40 | ]); |
| 41 | 41 | ||
| 42 | $pageId = $request->get('uploaded_to'); | 42 | $pageId = $request->get('uploaded_to'); |
| 43 | - $page = $this->pageRepo->getById($pageId, true); | 43 | + $page = $this->entityRepo->getById('page', $pageId, true); |
| 44 | 44 | ||
| 45 | $this->checkPermission('attachment-create-all'); | 45 | $this->checkPermission('attachment-create-all'); |
| 46 | $this->checkOwnablePermission('page-update', $page); | 46 | $this->checkOwnablePermission('page-update', $page); |
| ... | @@ -70,14 +70,14 @@ class AttachmentController extends Controller | ... | @@ -70,14 +70,14 @@ class AttachmentController extends Controller |
| 70 | ]); | 70 | ]); |
| 71 | 71 | ||
| 72 | $pageId = $request->get('uploaded_to'); | 72 | $pageId = $request->get('uploaded_to'); |
| 73 | - $page = $this->pageRepo->getById($pageId, true); | 73 | + $page = $this->entityRepo->getById('page', $pageId, true); |
| 74 | $attachment = $this->attachment->findOrFail($attachmentId); | 74 | $attachment = $this->attachment->findOrFail($attachmentId); |
| 75 | 75 | ||
| 76 | $this->checkOwnablePermission('page-update', $page); | 76 | $this->checkOwnablePermission('page-update', $page); |
| 77 | $this->checkOwnablePermission('attachment-create', $attachment); | 77 | $this->checkOwnablePermission('attachment-create', $attachment); |
| 78 | 78 | ||
| 79 | if (intval($pageId) !== intval($attachment->uploaded_to)) { | 79 | if (intval($pageId) !== intval($attachment->uploaded_to)) { |
| 80 | - return $this->jsonError('Page mismatch during attached file update'); | 80 | + return $this->jsonError(trans('errors.attachment_page_mismatch')); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | $uploadedFile = $request->file('file'); | 83 | $uploadedFile = $request->file('file'); |
| ... | @@ -106,18 +106,18 @@ class AttachmentController extends Controller | ... | @@ -106,18 +106,18 @@ class AttachmentController extends Controller |
| 106 | ]); | 106 | ]); |
| 107 | 107 | ||
| 108 | $pageId = $request->get('uploaded_to'); | 108 | $pageId = $request->get('uploaded_to'); |
| 109 | - $page = $this->pageRepo->getById($pageId, true); | 109 | + $page = $this->entityRepo->getById('page', $pageId, true); |
| 110 | $attachment = $this->attachment->findOrFail($attachmentId); | 110 | $attachment = $this->attachment->findOrFail($attachmentId); |
| 111 | 111 | ||
| 112 | $this->checkOwnablePermission('page-update', $page); | 112 | $this->checkOwnablePermission('page-update', $page); |
| 113 | $this->checkOwnablePermission('attachment-create', $attachment); | 113 | $this->checkOwnablePermission('attachment-create', $attachment); |
| 114 | 114 | ||
| 115 | if (intval($pageId) !== intval($attachment->uploaded_to)) { | 115 | if (intval($pageId) !== intval($attachment->uploaded_to)) { |
| 116 | - return $this->jsonError('Page mismatch during attachment update'); | 116 | + return $this->jsonError(trans('errors.attachment_page_mismatch')); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | $attachment = $this->attachmentService->updateFile($attachment, $request->all()); | 119 | $attachment = $this->attachmentService->updateFile($attachment, $request->all()); |
| 120 | - return $attachment; | 120 | + return response()->json($attachment); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | /** | 123 | /** |
| ... | @@ -134,7 +134,7 @@ class AttachmentController extends Controller | ... | @@ -134,7 +134,7 @@ class AttachmentController extends Controller |
| 134 | ]); | 134 | ]); |
| 135 | 135 | ||
| 136 | $pageId = $request->get('uploaded_to'); | 136 | $pageId = $request->get('uploaded_to'); |
| 137 | - $page = $this->pageRepo->getById($pageId, true); | 137 | + $page = $this->entityRepo->getById('page', $pageId, true); |
| 138 | 138 | ||
| 139 | $this->checkPermission('attachment-create-all'); | 139 | $this->checkPermission('attachment-create-all'); |
| 140 | $this->checkOwnablePermission('page-update', $page); | 140 | $this->checkOwnablePermission('page-update', $page); |
| ... | @@ -153,7 +153,7 @@ class AttachmentController extends Controller | ... | @@ -153,7 +153,7 @@ class AttachmentController extends Controller |
| 153 | */ | 153 | */ |
| 154 | public function listForPage($pageId) | 154 | public function listForPage($pageId) |
| 155 | { | 155 | { |
| 156 | - $page = $this->pageRepo->getById($pageId, true); | 156 | + $page = $this->entityRepo->getById('page', $pageId, true); |
| 157 | $this->checkOwnablePermission('page-view', $page); | 157 | $this->checkOwnablePermission('page-view', $page); |
| 158 | return response()->json($page->attachments); | 158 | return response()->json($page->attachments); |
| 159 | } | 159 | } |
| ... | @@ -170,12 +170,12 @@ class AttachmentController extends Controller | ... | @@ -170,12 +170,12 @@ class AttachmentController extends Controller |
| 170 | 'files' => 'required|array', | 170 | 'files' => 'required|array', |
| 171 | 'files.*.id' => 'required|integer', | 171 | 'files.*.id' => 'required|integer', |
| 172 | ]); | 172 | ]); |
| 173 | - $page = $this->pageRepo->getById($pageId); | 173 | + $page = $this->entityRepo->getById('page', $pageId); |
| 174 | $this->checkOwnablePermission('page-update', $page); | 174 | $this->checkOwnablePermission('page-update', $page); |
| 175 | 175 | ||
| 176 | $attachments = $request->get('files'); | 176 | $attachments = $request->get('files'); |
| 177 | $this->attachmentService->updateFileOrderWithinPage($attachments, $pageId); | 177 | $this->attachmentService->updateFileOrderWithinPage($attachments, $pageId); |
| 178 | - return response()->json(['message' => 'Attachment order updated']); | 178 | + return response()->json(['message' => trans('entities.attachments_order_updated')]); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | /** | 181 | /** |
| ... | @@ -186,7 +186,7 @@ class AttachmentController extends Controller | ... | @@ -186,7 +186,7 @@ class AttachmentController extends Controller |
| 186 | public function get($attachmentId) | 186 | public function get($attachmentId) |
| 187 | { | 187 | { |
| 188 | $attachment = $this->attachment->findOrFail($attachmentId); | 188 | $attachment = $this->attachment->findOrFail($attachmentId); |
| 189 | - $page = $this->pageRepo->getById($attachment->uploaded_to); | 189 | + $page = $this->entityRepo->getById('page', $attachment->uploaded_to); |
| 190 | $this->checkOwnablePermission('page-view', $page); | 190 | $this->checkOwnablePermission('page-view', $page); |
| 191 | 191 | ||
| 192 | if ($attachment->external) { | 192 | if ($attachment->external) { |
| ... | @@ -210,6 +210,6 @@ class AttachmentController extends Controller | ... | @@ -210,6 +210,6 @@ class AttachmentController extends Controller |
| 210 | $attachment = $this->attachment->findOrFail($attachmentId); | 210 | $attachment = $this->attachment->findOrFail($attachmentId); |
| 211 | $this->checkOwnablePermission('attachment-delete', $attachment); | 211 | $this->checkOwnablePermission('attachment-delete', $attachment); |
| 212 | $this->attachmentService->deleteFile($attachment); | 212 | $this->attachmentService->deleteFile($attachment); |
| 213 | - return response()->json(['message' => 'Attachment deleted']); | 213 | + return response()->json(['message' => trans('entities.attachments_deleted')]); |
| 214 | } | 214 | } |
| 215 | } | 215 | } | ... | ... |
| ... | @@ -52,7 +52,7 @@ class ForgotPasswordController extends Controller | ... | @@ -52,7 +52,7 @@ class ForgotPasswordController extends Controller |
| 52 | ); | 52 | ); |
| 53 | 53 | ||
| 54 | if ($response === Password::RESET_LINK_SENT) { | 54 | if ($response === Password::RESET_LINK_SENT) { |
| 55 | - $message = 'A password reset link has been sent to ' . $request->get('email') . '.'; | 55 | + $message = trans('auth.reset_password_sent_success', ['email' => $request->get('email')]); |
| 56 | session()->flash('success', $message); | 56 | session()->flash('success', $message); |
| 57 | return back()->with('status', trans($response)); | 57 | return back()->with('status', trans($response)); |
| 58 | } | 58 | } | ... | ... |
| ... | @@ -87,7 +87,7 @@ class LoginController extends Controller | ... | @@ -87,7 +87,7 @@ class LoginController extends Controller |
| 87 | // Check for users with same email already | 87 | // Check for users with same email already |
| 88 | $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; | 88 | $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; |
| 89 | if ($alreadyUser) { | 89 | if ($alreadyUser) { |
| 90 | - throw new AuthException('A user with the email ' . $user->email . ' already exists but with different credentials.'); | 90 | + throw new AuthException(trans('errors.error_user_exists_different_creds', ['email' => $user->email])); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | $user->save(); | 93 | $user->save(); | ... | ... |
| ... | @@ -3,6 +3,7 @@ | ... | @@ -3,6 +3,7 @@ |
| 3 | namespace BookStack\Http\Controllers\Auth; | 3 | namespace BookStack\Http\Controllers\Auth; |
| 4 | 4 | ||
| 5 | use BookStack\Exceptions\ConfirmationEmailException; | 5 | use BookStack\Exceptions\ConfirmationEmailException; |
| 6 | +use BookStack\Exceptions\SocialSignInException; | ||
| 6 | use BookStack\Exceptions\UserRegistrationException; | 7 | use BookStack\Exceptions\UserRegistrationException; |
| 7 | use BookStack\Repos\UserRepo; | 8 | use BookStack\Repos\UserRepo; |
| 8 | use BookStack\Services\EmailConfirmationService; | 9 | use BookStack\Services\EmailConfirmationService; |
| ... | @@ -82,7 +83,7 @@ class RegisterController extends Controller | ... | @@ -82,7 +83,7 @@ class RegisterController extends Controller |
| 82 | protected function checkRegistrationAllowed() | 83 | protected function checkRegistrationAllowed() |
| 83 | { | 84 | { |
| 84 | if (!setting('registration-enabled')) { | 85 | if (!setting('registration-enabled')) { |
| 85 | - throw new UserRegistrationException('Registrations are currently disabled.', '/login'); | 86 | + throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); |
| 86 | } | 87 | } |
| 87 | } | 88 | } |
| 88 | 89 | ||
| ... | @@ -147,7 +148,7 @@ class RegisterController extends Controller | ... | @@ -147,7 +148,7 @@ class RegisterController extends Controller |
| 147 | $restrictedEmailDomains = explode(',', str_replace(' ', '', setting('registration-restrict'))); | 148 | $restrictedEmailDomains = explode(',', str_replace(' ', '', setting('registration-restrict'))); |
| 148 | $userEmailDomain = $domain = substr(strrchr($userData['email'], "@"), 1); | 149 | $userEmailDomain = $domain = substr(strrchr($userData['email'], "@"), 1); |
| 149 | if (!in_array($userEmailDomain, $restrictedEmailDomains)) { | 150 | if (!in_array($userEmailDomain, $restrictedEmailDomains)) { |
| 150 | - throw new UserRegistrationException('That email domain does not have access to this application', '/register'); | 151 | + throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register'); |
| 151 | } | 152 | } |
| 152 | } | 153 | } |
| 153 | 154 | ||
| ... | @@ -169,7 +170,7 @@ class RegisterController extends Controller | ... | @@ -169,7 +170,7 @@ class RegisterController extends Controller |
| 169 | } | 170 | } |
| 170 | 171 | ||
| 171 | auth()->login($newUser); | 172 | auth()->login($newUser); |
| 172 | - session()->flash('success', 'Thanks for signing up! You are now registered and signed in.'); | 173 | + session()->flash('success', trans('auth.register_success')); |
| 173 | return redirect($this->redirectPath()); | 174 | return redirect($this->redirectPath()); |
| 174 | } | 175 | } |
| 175 | 176 | ||
| ... | @@ -262,7 +263,7 @@ class RegisterController extends Controller | ... | @@ -262,7 +263,7 @@ class RegisterController extends Controller |
| 262 | return $this->socialRegisterCallback($socialDriver); | 263 | return $this->socialRegisterCallback($socialDriver); |
| 263 | } | 264 | } |
| 264 | } else { | 265 | } else { |
| 265 | - throw new SocialSignInException('No action defined', '/login'); | 266 | + throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login'); |
| 266 | } | 267 | } |
| 267 | return redirect()->back(); | 268 | return redirect()->back(); |
| 268 | } | 269 | } | ... | ... |
| ... | @@ -41,7 +41,7 @@ class ResetPasswordController extends Controller | ... | @@ -41,7 +41,7 @@ class ResetPasswordController extends Controller |
| 41 | */ | 41 | */ |
| 42 | protected function sendResetResponse($response) | 42 | protected function sendResetResponse($response) |
| 43 | { | 43 | { |
| 44 | - $message = 'Your password has been successfully reset.'; | 44 | + $message = trans('auth.reset_password_success'); |
| 45 | session()->flash('success', $message); | 45 | session()->flash('success', $message); |
| 46 | return redirect($this->redirectPath()) | 46 | return redirect($this->redirectPath()) |
| 47 | ->with('status', trans($response)); | 47 | ->with('status', trans($response)); | ... | ... |
| 1 | <?php namespace BookStack\Http\Controllers; | 1 | <?php namespace BookStack\Http\Controllers; |
| 2 | 2 | ||
| 3 | use Activity; | 3 | use Activity; |
| 4 | +use BookStack\Repos\EntityRepo; | ||
| 4 | use BookStack\Repos\UserRepo; | 5 | use BookStack\Repos\UserRepo; |
| 5 | use Illuminate\Http\Request; | 6 | use Illuminate\Http\Request; |
| 6 | -use BookStack\Http\Requests; | 7 | +use Illuminate\Http\Response; |
| 7 | -use BookStack\Repos\BookRepo; | ||
| 8 | -use BookStack\Repos\ChapterRepo; | ||
| 9 | -use BookStack\Repos\PageRepo; | ||
| 10 | use Views; | 8 | use Views; |
| 11 | 9 | ||
| 12 | class BookController extends Controller | 10 | class BookController extends Controller |
| 13 | { | 11 | { |
| 14 | 12 | ||
| 15 | - protected $bookRepo; | 13 | + protected $entityRepo; |
| 16 | - protected $pageRepo; | ||
| 17 | - protected $chapterRepo; | ||
| 18 | protected $userRepo; | 14 | protected $userRepo; |
| 19 | 15 | ||
| 20 | /** | 16 | /** |
| 21 | * BookController constructor. | 17 | * BookController constructor. |
| 22 | - * @param BookRepo $bookRepo | 18 | + * @param EntityRepo $entityRepo |
| 23 | - * @param PageRepo $pageRepo | ||
| 24 | - * @param ChapterRepo $chapterRepo | ||
| 25 | * @param UserRepo $userRepo | 19 | * @param UserRepo $userRepo |
| 26 | */ | 20 | */ |
| 27 | - public function __construct(BookRepo $bookRepo, PageRepo $pageRepo, ChapterRepo $chapterRepo, UserRepo $userRepo) | 21 | + public function __construct(EntityRepo $entityRepo, UserRepo $userRepo) |
| 28 | { | 22 | { |
| 29 | - $this->bookRepo = $bookRepo; | 23 | + $this->entityRepo = $entityRepo; |
| 30 | - $this->pageRepo = $pageRepo; | ||
| 31 | - $this->chapterRepo = $chapterRepo; | ||
| 32 | $this->userRepo = $userRepo; | 24 | $this->userRepo = $userRepo; |
| 33 | parent::__construct(); | 25 | parent::__construct(); |
| 34 | } | 26 | } |
| ... | @@ -39,9 +31,9 @@ class BookController extends Controller | ... | @@ -39,9 +31,9 @@ class BookController extends Controller |
| 39 | */ | 31 | */ |
| 40 | public function index() | 32 | public function index() |
| 41 | { | 33 | { |
| 42 | - $books = $this->bookRepo->getAllPaginated(10); | 34 | + $books = $this->entityRepo->getAllPaginated('book', 10); |
| 43 | - $recents = $this->signedIn ? $this->bookRepo->getRecentlyViewed(4, 0) : false; | 35 | + $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false; |
| 44 | - $popular = $this->bookRepo->getPopular(4, 0); | 36 | + $popular = $this->entityRepo->getPopular('book', 4, 0); |
| 45 | $this->setPageTitle('Books'); | 37 | $this->setPageTitle('Books'); |
| 46 | return view('books/index', ['books' => $books, 'recents' => $recents, 'popular' => $popular]); | 38 | return view('books/index', ['books' => $books, 'recents' => $recents, 'popular' => $popular]); |
| 47 | } | 39 | } |
| ... | @@ -53,7 +45,7 @@ class BookController extends Controller | ... | @@ -53,7 +45,7 @@ class BookController extends Controller |
| 53 | public function create() | 45 | public function create() |
| 54 | { | 46 | { |
| 55 | $this->checkPermission('book-create-all'); | 47 | $this->checkPermission('book-create-all'); |
| 56 | - $this->setPageTitle('Create New Book'); | 48 | + $this->setPageTitle(trans('entities.books_create')); |
| 57 | return view('books/create'); | 49 | return view('books/create'); |
| 58 | } | 50 | } |
| 59 | 51 | ||
| ... | @@ -70,7 +62,7 @@ class BookController extends Controller | ... | @@ -70,7 +62,7 @@ class BookController extends Controller |
| 70 | 'name' => 'required|string|max:255', | 62 | 'name' => 'required|string|max:255', |
| 71 | 'description' => 'string|max:1000' | 63 | 'description' => 'string|max:1000' |
| 72 | ]); | 64 | ]); |
| 73 | - $book = $this->bookRepo->createFromInput($request->all()); | 65 | + $book = $this->entityRepo->createFromInput('book', $request->all()); |
| 74 | Activity::add($book, 'book_create', $book->id); | 66 | Activity::add($book, 'book_create', $book->id); |
| 75 | return redirect($book->getUrl()); | 67 | return redirect($book->getUrl()); |
| 76 | } | 68 | } |
| ... | @@ -82,9 +74,9 @@ class BookController extends Controller | ... | @@ -82,9 +74,9 @@ class BookController extends Controller |
| 82 | */ | 74 | */ |
| 83 | public function show($slug) | 75 | public function show($slug) |
| 84 | { | 76 | { |
| 85 | - $book = $this->bookRepo->getBySlug($slug); | 77 | + $book = $this->entityRepo->getBySlug('book', $slug); |
| 86 | $this->checkOwnablePermission('book-view', $book); | 78 | $this->checkOwnablePermission('book-view', $book); |
| 87 | - $bookChildren = $this->bookRepo->getChildren($book); | 79 | + $bookChildren = $this->entityRepo->getBookChildren($book); |
| 88 | Views::add($book); | 80 | Views::add($book); |
| 89 | $this->setPageTitle($book->getShortName()); | 81 | $this->setPageTitle($book->getShortName()); |
| 90 | return view('books/show', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]); | 82 | return view('books/show', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]); |
| ... | @@ -97,9 +89,9 @@ class BookController extends Controller | ... | @@ -97,9 +89,9 @@ class BookController extends Controller |
| 97 | */ | 89 | */ |
| 98 | public function edit($slug) | 90 | public function edit($slug) |
| 99 | { | 91 | { |
| 100 | - $book = $this->bookRepo->getBySlug($slug); | 92 | + $book = $this->entityRepo->getBySlug('book', $slug); |
| 101 | $this->checkOwnablePermission('book-update', $book); | 93 | $this->checkOwnablePermission('book-update', $book); |
| 102 | - $this->setPageTitle('Edit Book ' . $book->getShortName()); | 94 | + $this->setPageTitle(trans('entities.books_edit_named',['bookName'=>$book->getShortName()])); |
| 103 | return view('books/edit', ['book' => $book, 'current' => $book]); | 95 | return view('books/edit', ['book' => $book, 'current' => $book]); |
| 104 | } | 96 | } |
| 105 | 97 | ||
| ... | @@ -111,13 +103,13 @@ class BookController extends Controller | ... | @@ -111,13 +103,13 @@ class BookController extends Controller |
| 111 | */ | 103 | */ |
| 112 | public function update(Request $request, $slug) | 104 | public function update(Request $request, $slug) |
| 113 | { | 105 | { |
| 114 | - $book = $this->bookRepo->getBySlug($slug); | 106 | + $book = $this->entityRepo->getBySlug('book', $slug); |
| 115 | $this->checkOwnablePermission('book-update', $book); | 107 | $this->checkOwnablePermission('book-update', $book); |
| 116 | $this->validate($request, [ | 108 | $this->validate($request, [ |
| 117 | 'name' => 'required|string|max:255', | 109 | 'name' => 'required|string|max:255', |
| 118 | 'description' => 'string|max:1000' | 110 | 'description' => 'string|max:1000' |
| 119 | ]); | 111 | ]); |
| 120 | - $book = $this->bookRepo->updateFromInput($book, $request->all()); | 112 | + $book = $this->entityRepo->updateFromInput('book', $book, $request->all()); |
| 121 | Activity::add($book, 'book_update', $book->id); | 113 | Activity::add($book, 'book_update', $book->id); |
| 122 | return redirect($book->getUrl()); | 114 | return redirect($book->getUrl()); |
| 123 | } | 115 | } |
| ... | @@ -129,9 +121,9 @@ class BookController extends Controller | ... | @@ -129,9 +121,9 @@ class BookController extends Controller |
| 129 | */ | 121 | */ |
| 130 | public function showDelete($bookSlug) | 122 | public function showDelete($bookSlug) |
| 131 | { | 123 | { |
| 132 | - $book = $this->bookRepo->getBySlug($bookSlug); | 124 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 133 | $this->checkOwnablePermission('book-delete', $book); | 125 | $this->checkOwnablePermission('book-delete', $book); |
| 134 | - $this->setPageTitle('Delete Book ' . $book->getShortName()); | 126 | + $this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()])); |
| 135 | return view('books/delete', ['book' => $book, 'current' => $book]); | 127 | return view('books/delete', ['book' => $book, 'current' => $book]); |
| 136 | } | 128 | } |
| 137 | 129 | ||
| ... | @@ -142,11 +134,11 @@ class BookController extends Controller | ... | @@ -142,11 +134,11 @@ class BookController extends Controller |
| 142 | */ | 134 | */ |
| 143 | public function sort($bookSlug) | 135 | public function sort($bookSlug) |
| 144 | { | 136 | { |
| 145 | - $book = $this->bookRepo->getBySlug($bookSlug); | 137 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 146 | $this->checkOwnablePermission('book-update', $book); | 138 | $this->checkOwnablePermission('book-update', $book); |
| 147 | - $bookChildren = $this->bookRepo->getChildren($book, true); | 139 | + $bookChildren = $this->entityRepo->getBookChildren($book, true); |
| 148 | - $books = $this->bookRepo->getAll(false); | 140 | + $books = $this->entityRepo->getAll('book', false); |
| 149 | - $this->setPageTitle('Sort Book ' . $book->getShortName()); | 141 | + $this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()])); |
| 150 | return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]); | 142 | return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]); |
| 151 | } | 143 | } |
| 152 | 144 | ||
| ... | @@ -158,8 +150,8 @@ class BookController extends Controller | ... | @@ -158,8 +150,8 @@ class BookController extends Controller |
| 158 | */ | 150 | */ |
| 159 | public function getSortItem($bookSlug) | 151 | public function getSortItem($bookSlug) |
| 160 | { | 152 | { |
| 161 | - $book = $this->bookRepo->getBySlug($bookSlug); | 153 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 162 | - $bookChildren = $this->bookRepo->getChildren($book); | 154 | + $bookChildren = $this->entityRepo->getBookChildren($book); |
| 163 | return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]); | 155 | return view('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]); |
| 164 | } | 156 | } |
| 165 | 157 | ||
| ... | @@ -171,7 +163,7 @@ class BookController extends Controller | ... | @@ -171,7 +163,7 @@ class BookController extends Controller |
| 171 | */ | 163 | */ |
| 172 | public function saveSort($bookSlug, Request $request) | 164 | public function saveSort($bookSlug, Request $request) |
| 173 | { | 165 | { |
| 174 | - $book = $this->bookRepo->getBySlug($bookSlug); | 166 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 175 | $this->checkOwnablePermission('book-update', $book); | 167 | $this->checkOwnablePermission('book-update', $book); |
| 176 | 168 | ||
| 177 | // Return if no map sent | 169 | // Return if no map sent |
| ... | @@ -190,13 +182,13 @@ class BookController extends Controller | ... | @@ -190,13 +182,13 @@ class BookController extends Controller |
| 190 | $priority = $bookChild->sort; | 182 | $priority = $bookChild->sort; |
| 191 | $id = intval($bookChild->id); | 183 | $id = intval($bookChild->id); |
| 192 | $isPage = $bookChild->type == 'page'; | 184 | $isPage = $bookChild->type == 'page'; |
| 193 | - $bookId = $this->bookRepo->exists($bookChild->book) ? intval($bookChild->book) : $defaultBookId; | 185 | + $bookId = $this->entityRepo->exists('book', $bookChild->book) ? intval($bookChild->book) : $defaultBookId; |
| 194 | $chapterId = ($isPage && $bookChild->parentChapter === false) ? 0 : intval($bookChild->parentChapter); | 186 | $chapterId = ($isPage && $bookChild->parentChapter === false) ? 0 : intval($bookChild->parentChapter); |
| 195 | - $model = $isPage ? $this->pageRepo->getById($id) : $this->chapterRepo->getById($id); | 187 | + $model = $this->entityRepo->getById($isPage?'page':'chapter', $id); |
| 196 | 188 | ||
| 197 | // Update models only if there's a change in parent chain or ordering. | 189 | // Update models only if there's a change in parent chain or ordering. |
| 198 | if ($model->priority !== $priority || $model->book_id !== $bookId || ($isPage && $model->chapter_id !== $chapterId)) { | 190 | if ($model->priority !== $priority || $model->book_id !== $bookId || ($isPage && $model->chapter_id !== $chapterId)) { |
| 199 | - $isPage ? $this->pageRepo->changeBook($bookId, $model) : $this->chapterRepo->changeBook($bookId, $model); | 191 | + $this->entityRepo->changeBook($isPage?'page':'chapter', $bookId, $model); |
| 200 | $model->priority = $priority; | 192 | $model->priority = $priority; |
| 201 | if ($isPage) $model->chapter_id = $chapterId; | 193 | if ($isPage) $model->chapter_id = $chapterId; |
| 202 | $model->save(); | 194 | $model->save(); |
| ... | @@ -211,12 +203,12 @@ class BookController extends Controller | ... | @@ -211,12 +203,12 @@ class BookController extends Controller |
| 211 | 203 | ||
| 212 | // Add activity for books | 204 | // Add activity for books |
| 213 | foreach ($sortedBooks as $bookId) { | 205 | foreach ($sortedBooks as $bookId) { |
| 214 | - $updatedBook = $this->bookRepo->getById($bookId); | 206 | + $updatedBook = $this->entityRepo->getById('book', $bookId); |
| 215 | Activity::add($updatedBook, 'book_sort', $updatedBook->id); | 207 | Activity::add($updatedBook, 'book_sort', $updatedBook->id); |
| 216 | } | 208 | } |
| 217 | 209 | ||
| 218 | // Update permissions on changed models | 210 | // Update permissions on changed models |
| 219 | - $this->bookRepo->buildJointPermissions($updatedModels); | 211 | + $this->entityRepo->buildJointPermissions($updatedModels); |
| 220 | 212 | ||
| 221 | return redirect($book->getUrl()); | 213 | return redirect($book->getUrl()); |
| 222 | } | 214 | } |
| ... | @@ -228,11 +220,10 @@ class BookController extends Controller | ... | @@ -228,11 +220,10 @@ class BookController extends Controller |
| 228 | */ | 220 | */ |
| 229 | public function destroy($bookSlug) | 221 | public function destroy($bookSlug) |
| 230 | { | 222 | { |
| 231 | - $book = $this->bookRepo->getBySlug($bookSlug); | 223 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 232 | $this->checkOwnablePermission('book-delete', $book); | 224 | $this->checkOwnablePermission('book-delete', $book); |
| 233 | Activity::addMessage('book_delete', 0, $book->name); | 225 | Activity::addMessage('book_delete', 0, $book->name); |
| 234 | - Activity::removeEntity($book); | 226 | + $this->entityRepo->destroyBook($book); |
| 235 | - $this->bookRepo->destroy($book); | ||
| 236 | return redirect('/books'); | 227 | return redirect('/books'); |
| 237 | } | 228 | } |
| 238 | 229 | ||
| ... | @@ -243,7 +234,7 @@ class BookController extends Controller | ... | @@ -243,7 +234,7 @@ class BookController extends Controller |
| 243 | */ | 234 | */ |
| 244 | public function showRestrict($bookSlug) | 235 | public function showRestrict($bookSlug) |
| 245 | { | 236 | { |
| 246 | - $book = $this->bookRepo->getBySlug($bookSlug); | 237 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 247 | $this->checkOwnablePermission('restrictions-manage', $book); | 238 | $this->checkOwnablePermission('restrictions-manage', $book); |
| 248 | $roles = $this->userRepo->getRestrictableRoles(); | 239 | $roles = $this->userRepo->getRestrictableRoles(); |
| 249 | return view('books/restrictions', [ | 240 | return view('books/restrictions', [ |
| ... | @@ -261,10 +252,10 @@ class BookController extends Controller | ... | @@ -261,10 +252,10 @@ class BookController extends Controller |
| 261 | */ | 252 | */ |
| 262 | public function restrict($bookSlug, Request $request) | 253 | public function restrict($bookSlug, Request $request) |
| 263 | { | 254 | { |
| 264 | - $book = $this->bookRepo->getBySlug($bookSlug); | 255 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 265 | $this->checkOwnablePermission('restrictions-manage', $book); | 256 | $this->checkOwnablePermission('restrictions-manage', $book); |
| 266 | - $this->bookRepo->updateEntityPermissionsFromRequest($request, $book); | 257 | + $this->entityRepo->updateEntityPermissionsFromRequest($request, $book); |
| 267 | - session()->flash('success', 'Book Restrictions Updated'); | 258 | + session()->flash('success', trans('entities.books_permissions_updated')); |
| 268 | return redirect($book->getUrl()); | 259 | return redirect($book->getUrl()); |
| 269 | } | 260 | } |
| 270 | } | 261 | } | ... | ... |
| 1 | <?php namespace BookStack\Http\Controllers; | 1 | <?php namespace BookStack\Http\Controllers; |
| 2 | 2 | ||
| 3 | use Activity; | 3 | use Activity; |
| 4 | +use BookStack\Repos\EntityRepo; | ||
| 4 | use BookStack\Repos\UserRepo; | 5 | use BookStack\Repos\UserRepo; |
| 5 | use Illuminate\Http\Request; | 6 | use Illuminate\Http\Request; |
| 6 | -use BookStack\Http\Requests; | 7 | +use Illuminate\Http\Response; |
| 7 | -use BookStack\Repos\BookRepo; | ||
| 8 | -use BookStack\Repos\ChapterRepo; | ||
| 9 | use Views; | 8 | use Views; |
| 10 | 9 | ||
| 11 | class ChapterController extends Controller | 10 | class ChapterController extends Controller |
| 12 | { | 11 | { |
| 13 | 12 | ||
| 14 | - protected $bookRepo; | ||
| 15 | - protected $chapterRepo; | ||
| 16 | protected $userRepo; | 13 | protected $userRepo; |
| 14 | + protected $entityRepo; | ||
| 17 | 15 | ||
| 18 | /** | 16 | /** |
| 19 | * ChapterController constructor. | 17 | * ChapterController constructor. |
| 20 | - * @param BookRepo $bookRepo | 18 | + * @param EntityRepo $entityRepo |
| 21 | - * @param ChapterRepo $chapterRepo | ||
| 22 | * @param UserRepo $userRepo | 19 | * @param UserRepo $userRepo |
| 23 | */ | 20 | */ |
| 24 | - public function __construct(BookRepo $bookRepo, ChapterRepo $chapterRepo, UserRepo $userRepo) | 21 | + public function __construct(EntityRepo $entityRepo, UserRepo $userRepo) |
| 25 | { | 22 | { |
| 26 | - $this->bookRepo = $bookRepo; | 23 | + $this->entityRepo = $entityRepo; |
| 27 | - $this->chapterRepo = $chapterRepo; | ||
| 28 | $this->userRepo = $userRepo; | 24 | $this->userRepo = $userRepo; |
| 29 | parent::__construct(); | 25 | parent::__construct(); |
| 30 | } | 26 | } |
| ... | @@ -36,9 +32,9 @@ class ChapterController extends Controller | ... | @@ -36,9 +32,9 @@ class ChapterController extends Controller |
| 36 | */ | 32 | */ |
| 37 | public function create($bookSlug) | 33 | public function create($bookSlug) |
| 38 | { | 34 | { |
| 39 | - $book = $this->bookRepo->getBySlug($bookSlug); | 35 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 40 | $this->checkOwnablePermission('chapter-create', $book); | 36 | $this->checkOwnablePermission('chapter-create', $book); |
| 41 | - $this->setPageTitle('Create New Chapter'); | 37 | + $this->setPageTitle(trans('entities.chapters_create')); |
| 42 | return view('chapters/create', ['book' => $book, 'current' => $book]); | 38 | return view('chapters/create', ['book' => $book, 'current' => $book]); |
| 43 | } | 39 | } |
| 44 | 40 | ||
| ... | @@ -54,12 +50,12 @@ class ChapterController extends Controller | ... | @@ -54,12 +50,12 @@ class ChapterController extends Controller |
| 54 | 'name' => 'required|string|max:255' | 50 | 'name' => 'required|string|max:255' |
| 55 | ]); | 51 | ]); |
| 56 | 52 | ||
| 57 | - $book = $this->bookRepo->getBySlug($bookSlug); | 53 | + $book = $this->entityRepo->getBySlug('book', $bookSlug); |
| 58 | $this->checkOwnablePermission('chapter-create', $book); | 54 | $this->checkOwnablePermission('chapter-create', $book); |
| 59 | 55 | ||
| 60 | $input = $request->all(); | 56 | $input = $request->all(); |
| 61 | - $input['priority'] = $this->bookRepo->getNewPriority($book); | 57 | + $input['priority'] = $this->entityRepo->getNewBookPriority($book); |
| 62 | - $chapter = $this->chapterRepo->createFromInput($input, $book); | 58 | + $chapter = $this->entityRepo->createFromInput('chapter', $input, $book); |
| 63 | Activity::add($chapter, 'chapter_create', $book->id); | 59 | Activity::add($chapter, 'chapter_create', $book->id); |
| 64 | return redirect($chapter->getUrl()); | 60 | return redirect($chapter->getUrl()); |
| 65 | } | 61 | } |
| ... | @@ -72,15 +68,14 @@ class ChapterController extends Controller | ... | @@ -72,15 +68,14 @@ class ChapterController extends Controller |
| 72 | */ | 68 | */ |
| 73 | public function show($bookSlug, $chapterSlug) | 69 | public function show($bookSlug, $chapterSlug) |
| 74 | { | 70 | { |
| 75 | - $book = $this->bookRepo->getBySlug($bookSlug); | 71 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 76 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | ||
| 77 | $this->checkOwnablePermission('chapter-view', $chapter); | 72 | $this->checkOwnablePermission('chapter-view', $chapter); |
| 78 | - $sidebarTree = $this->bookRepo->getChildren($book); | 73 | + $sidebarTree = $this->entityRepo->getBookChildren($chapter->book); |
| 79 | Views::add($chapter); | 74 | Views::add($chapter); |
| 80 | $this->setPageTitle($chapter->getShortName()); | 75 | $this->setPageTitle($chapter->getShortName()); |
| 81 | - $pages = $this->chapterRepo->getChildren($chapter); | 76 | + $pages = $this->entityRepo->getChapterChildren($chapter); |
| 82 | return view('chapters/show', [ | 77 | return view('chapters/show', [ |
| 83 | - 'book' => $book, | 78 | + 'book' => $chapter->book, |
| 84 | 'chapter' => $chapter, | 79 | 'chapter' => $chapter, |
| 85 | 'current' => $chapter, | 80 | 'current' => $chapter, |
| 86 | 'sidebarTree' => $sidebarTree, | 81 | 'sidebarTree' => $sidebarTree, |
| ... | @@ -96,11 +91,10 @@ class ChapterController extends Controller | ... | @@ -96,11 +91,10 @@ class ChapterController extends Controller |
| 96 | */ | 91 | */ |
| 97 | public function edit($bookSlug, $chapterSlug) | 92 | public function edit($bookSlug, $chapterSlug) |
| 98 | { | 93 | { |
| 99 | - $book = $this->bookRepo->getBySlug($bookSlug); | 94 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 100 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | ||
| 101 | $this->checkOwnablePermission('chapter-update', $chapter); | 95 | $this->checkOwnablePermission('chapter-update', $chapter); |
| 102 | - $this->setPageTitle('Edit Chapter' . $chapter->getShortName()); | 96 | + $this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()])); |
| 103 | - return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]); | 97 | + return view('chapters/edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]); |
| 104 | } | 98 | } |
| 105 | 99 | ||
| 106 | /** | 100 | /** |
| ... | @@ -112,16 +106,15 @@ class ChapterController extends Controller | ... | @@ -112,16 +106,15 @@ class ChapterController extends Controller |
| 112 | */ | 106 | */ |
| 113 | public function update(Request $request, $bookSlug, $chapterSlug) | 107 | public function update(Request $request, $bookSlug, $chapterSlug) |
| 114 | { | 108 | { |
| 115 | - $book = $this->bookRepo->getBySlug($bookSlug); | 109 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 116 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | ||
| 117 | $this->checkOwnablePermission('chapter-update', $chapter); | 110 | $this->checkOwnablePermission('chapter-update', $chapter); |
| 118 | if ($chapter->name !== $request->get('name')) { | 111 | if ($chapter->name !== $request->get('name')) { |
| 119 | - $chapter->slug = $this->chapterRepo->findSuitableSlug($request->get('name'), $book->id, $chapter->id); | 112 | + $chapter->slug = $this->entityRepo->findSuitableSlug('chapter', $request->get('name'), $chapter->id, $chapter->book->id); |
| 120 | } | 113 | } |
| 121 | $chapter->fill($request->all()); | 114 | $chapter->fill($request->all()); |
| 122 | $chapter->updated_by = user()->id; | 115 | $chapter->updated_by = user()->id; |
| 123 | $chapter->save(); | 116 | $chapter->save(); |
| 124 | - Activity::add($chapter, 'chapter_update', $book->id); | 117 | + Activity::add($chapter, 'chapter_update', $chapter->book->id); |
| 125 | return redirect($chapter->getUrl()); | 118 | return redirect($chapter->getUrl()); |
| 126 | } | 119 | } |
| 127 | 120 | ||
| ... | @@ -133,11 +126,10 @@ class ChapterController extends Controller | ... | @@ -133,11 +126,10 @@ class ChapterController extends Controller |
| 133 | */ | 126 | */ |
| 134 | public function showDelete($bookSlug, $chapterSlug) | 127 | public function showDelete($bookSlug, $chapterSlug) |
| 135 | { | 128 | { |
| 136 | - $book = $this->bookRepo->getBySlug($bookSlug); | 129 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 137 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | ||
| 138 | $this->checkOwnablePermission('chapter-delete', $chapter); | 130 | $this->checkOwnablePermission('chapter-delete', $chapter); |
| 139 | - $this->setPageTitle('Delete Chapter' . $chapter->getShortName()); | 131 | + $this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()])); |
| 140 | - return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]); | 132 | + return view('chapters/delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]); |
| 141 | } | 133 | } |
| 142 | 134 | ||
| 143 | /** | 135 | /** |
| ... | @@ -148,11 +140,11 @@ class ChapterController extends Controller | ... | @@ -148,11 +140,11 @@ class ChapterController extends Controller |
| 148 | */ | 140 | */ |
| 149 | public function destroy($bookSlug, $chapterSlug) | 141 | public function destroy($bookSlug, $chapterSlug) |
| 150 | { | 142 | { |
| 151 | - $book = $this->bookRepo->getBySlug($bookSlug); | 143 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 152 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | 144 | + $book = $chapter->book; |
| 153 | $this->checkOwnablePermission('chapter-delete', $chapter); | 145 | $this->checkOwnablePermission('chapter-delete', $chapter); |
| 154 | Activity::addMessage('chapter_delete', $book->id, $chapter->name); | 146 | Activity::addMessage('chapter_delete', $book->id, $chapter->name); |
| 155 | - $this->chapterRepo->destroy($chapter); | 147 | + $this->entityRepo->destroyChapter($chapter); |
| 156 | return redirect($book->getUrl()); | 148 | return redirect($book->getUrl()); |
| 157 | } | 149 | } |
| 158 | 150 | ||
| ... | @@ -164,12 +156,12 @@ class ChapterController extends Controller | ... | @@ -164,12 +156,12 @@ class ChapterController extends Controller |
| 164 | * @throws \BookStack\Exceptions\NotFoundException | 156 | * @throws \BookStack\Exceptions\NotFoundException |
| 165 | */ | 157 | */ |
| 166 | public function showMove($bookSlug, $chapterSlug) { | 158 | public function showMove($bookSlug, $chapterSlug) { |
| 167 | - $book = $this->bookRepo->getBySlug($bookSlug); | 159 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 168 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | 160 | + $this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()])); |
| 169 | $this->checkOwnablePermission('chapter-update', $chapter); | 161 | $this->checkOwnablePermission('chapter-update', $chapter); |
| 170 | return view('chapters/move', [ | 162 | return view('chapters/move', [ |
| 171 | 'chapter' => $chapter, | 163 | 'chapter' => $chapter, |
| 172 | - 'book' => $book | 164 | + 'book' => $chapter->book |
| 173 | ]); | 165 | ]); |
| 174 | } | 166 | } |
| 175 | 167 | ||
| ... | @@ -182,8 +174,7 @@ class ChapterController extends Controller | ... | @@ -182,8 +174,7 @@ class ChapterController extends Controller |
| 182 | * @throws \BookStack\Exceptions\NotFoundException | 174 | * @throws \BookStack\Exceptions\NotFoundException |
| 183 | */ | 175 | */ |
| 184 | public function move($bookSlug, $chapterSlug, Request $request) { | 176 | public function move($bookSlug, $chapterSlug, Request $request) { |
| 185 | - $book = $this->bookRepo->getBySlug($bookSlug); | 177 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 186 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | ||
| 187 | $this->checkOwnablePermission('chapter-update', $chapter); | 178 | $this->checkOwnablePermission('chapter-update', $chapter); |
| 188 | 179 | ||
| 189 | $entitySelection = $request->get('entity_selection', null); | 180 | $entitySelection = $request->get('entity_selection', null); |
| ... | @@ -198,17 +189,17 @@ class ChapterController extends Controller | ... | @@ -198,17 +189,17 @@ class ChapterController extends Controller |
| 198 | $parent = false; | 189 | $parent = false; |
| 199 | 190 | ||
| 200 | if ($entityType == 'book') { | 191 | if ($entityType == 'book') { |
| 201 | - $parent = $this->bookRepo->getById($entityId); | 192 | + $parent = $this->entityRepo->getById('book', $entityId); |
| 202 | } | 193 | } |
| 203 | 194 | ||
| 204 | if ($parent === false || $parent === null) { | 195 | if ($parent === false || $parent === null) { |
| 205 | - session()->flash('The selected Book was not found'); | 196 | + session()->flash('error', trans('errors.selected_book_not_found')); |
| 206 | return redirect()->back(); | 197 | return redirect()->back(); |
| 207 | } | 198 | } |
| 208 | 199 | ||
| 209 | - $this->chapterRepo->changeBook($parent->id, $chapter, true); | 200 | + $this->entityRepo->changeBook('chapter', $parent->id, $chapter, true); |
| 210 | Activity::add($chapter, 'chapter_move', $chapter->book->id); | 201 | Activity::add($chapter, 'chapter_move', $chapter->book->id); |
| 211 | - session()->flash('success', sprintf('Chapter moved to "%s"', $parent->name)); | 202 | + session()->flash('success', trans('entities.chapter_move_success', ['bookName' => $parent->name])); |
| 212 | 203 | ||
| 213 | return redirect($chapter->getUrl()); | 204 | return redirect($chapter->getUrl()); |
| 214 | } | 205 | } |
| ... | @@ -221,8 +212,7 @@ class ChapterController extends Controller | ... | @@ -221,8 +212,7 @@ class ChapterController extends Controller |
| 221 | */ | 212 | */ |
| 222 | public function showRestrict($bookSlug, $chapterSlug) | 213 | public function showRestrict($bookSlug, $chapterSlug) |
| 223 | { | 214 | { |
| 224 | - $book = $this->bookRepo->getBySlug($bookSlug); | 215 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 225 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | ||
| 226 | $this->checkOwnablePermission('restrictions-manage', $chapter); | 216 | $this->checkOwnablePermission('restrictions-manage', $chapter); |
| 227 | $roles = $this->userRepo->getRestrictableRoles(); | 217 | $roles = $this->userRepo->getRestrictableRoles(); |
| 228 | return view('chapters/restrictions', [ | 218 | return view('chapters/restrictions', [ |
| ... | @@ -240,11 +230,10 @@ class ChapterController extends Controller | ... | @@ -240,11 +230,10 @@ class ChapterController extends Controller |
| 240 | */ | 230 | */ |
| 241 | public function restrict($bookSlug, $chapterSlug, Request $request) | 231 | public function restrict($bookSlug, $chapterSlug, Request $request) |
| 242 | { | 232 | { |
| 243 | - $book = $this->bookRepo->getBySlug($bookSlug); | 233 | + $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); |
| 244 | - $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); | ||
| 245 | $this->checkOwnablePermission('restrictions-manage', $chapter); | 234 | $this->checkOwnablePermission('restrictions-manage', $chapter); |
| 246 | - $this->chapterRepo->updateEntityPermissionsFromRequest($request, $chapter); | 235 | + $this->entityRepo->updateEntityPermissionsFromRequest($request, $chapter); |
| 247 | - session()->flash('success', 'Chapter Restrictions Updated'); | 236 | + session()->flash('success', trans('entities.chapters_permissions_success')); |
| 248 | return redirect($chapter->getUrl()); | 237 | return redirect($chapter->getUrl()); |
| 249 | } | 238 | } |
| 250 | } | 239 | } | ... | ... |
| ... | @@ -5,6 +5,7 @@ namespace BookStack\Http\Controllers; | ... | @@ -5,6 +5,7 @@ namespace BookStack\Http\Controllers; |
| 5 | use Activity; | 5 | use Activity; |
| 6 | use BookStack\Repos\EntityRepo; | 6 | use BookStack\Repos\EntityRepo; |
| 7 | use BookStack\Http\Requests; | 7 | use BookStack\Http\Requests; |
| 8 | +use Illuminate\Http\Response; | ||
| 8 | use Views; | 9 | use Views; |
| 9 | 10 | ||
| 10 | class HomeController extends Controller | 11 | class HomeController extends Controller |
| ... | @@ -31,9 +32,9 @@ class HomeController extends Controller | ... | @@ -31,9 +32,9 @@ class HomeController extends Controller |
| 31 | $activity = Activity::latest(10); | 32 | $activity = Activity::latest(10); |
| 32 | $draftPages = $this->signedIn ? $this->entityRepo->getUserDraftPages(6) : []; | 33 | $draftPages = $this->signedIn ? $this->entityRepo->getUserDraftPages(6) : []; |
| 33 | $recentFactor = count($draftPages) > 0 ? 0.5 : 1; | 34 | $recentFactor = count($draftPages) > 0 ? 0.5 : 1; |
| 34 | - $recents = $this->signedIn ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreatedBooks(10*$recentFactor); | 35 | + $recents = $this->signedIn ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreated('book', 10*$recentFactor); |
| 35 | - $recentlyCreatedPages = $this->entityRepo->getRecentlyCreatedPages(5); | 36 | + $recentlyCreatedPages = $this->entityRepo->getRecentlyCreated('page', 5); |
| 36 | - $recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdatedPages(5); | 37 | + $recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdated('page', 5); |
| 37 | return view('home', [ | 38 | return view('home', [ |
| 38 | 'activity' => $activity, | 39 | 'activity' => $activity, |
| 39 | 'recents' => $recents, | 40 | 'recents' => $recents, |
| ... | @@ -43,4 +44,39 @@ class HomeController extends Controller | ... | @@ -43,4 +44,39 @@ class HomeController extends Controller |
| 43 | ]); | 44 | ]); |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 47 | + /** | ||
| 48 | + * Get a js representation of the current translations | ||
| 49 | + * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response | ||
| 50 | + */ | ||
| 51 | + public function getTranslations() { | ||
| 52 | + $locale = trans()->getLocale(); | ||
| 53 | + $cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale; | ||
| 54 | + if (cache()->has($cacheKey) && config('app.env') !== 'development') { | ||
| 55 | + $resp = cache($cacheKey); | ||
| 56 | + } else { | ||
| 57 | + $translations = [ | ||
| 58 | + // Get only translations which might be used in JS | ||
| 59 | + 'common' => trans('common'), | ||
| 60 | + 'components' => trans('components'), | ||
| 61 | + 'entities' => trans('entities'), | ||
| 62 | + 'errors' => trans('errors') | ||
| 63 | + ]; | ||
| 64 | + if ($locale !== 'en') { | ||
| 65 | + $enTrans = [ | ||
| 66 | + 'common' => trans('common', [], null, 'en'), | ||
| 67 | + 'components' => trans('components', [], null, 'en'), | ||
| 68 | + 'entities' => trans('entities', [], null, 'en'), | ||
| 69 | + 'errors' => trans('errors', [], null, 'en') | ||
| 70 | + ]; | ||
| 71 | + $translations = array_replace_recursive($enTrans, $translations); | ||
| 72 | + } | ||
| 73 | + $resp = 'window.translations = ' . json_encode($translations); | ||
| 74 | + cache()->put($cacheKey, $resp, 120); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + return response($resp, 200, [ | ||
| 78 | + 'Content-Type' => 'application/javascript' | ||
| 79 | + ]); | ||
| 80 | + } | ||
| 81 | + | ||
| 46 | } | 82 | } | ... | ... |
| 1 | <?php namespace BookStack\Http\Controllers; | 1 | <?php namespace BookStack\Http\Controllers; |
| 2 | 2 | ||
| 3 | use BookStack\Exceptions\ImageUploadException; | 3 | use BookStack\Exceptions\ImageUploadException; |
| 4 | +use BookStack\Repos\EntityRepo; | ||
| 4 | use BookStack\Repos\ImageRepo; | 5 | use BookStack\Repos\ImageRepo; |
| 5 | use Illuminate\Filesystem\Filesystem as File; | 6 | use Illuminate\Filesystem\Filesystem as File; |
| 6 | use Illuminate\Http\Request; | 7 | use Illuminate\Http\Request; |
| ... | @@ -73,6 +74,7 @@ class ImageController extends Controller | ... | @@ -73,6 +74,7 @@ class ImageController extends Controller |
| 73 | * @param $filter | 74 | * @param $filter |
| 74 | * @param int $page | 75 | * @param int $page |
| 75 | * @param Request $request | 76 | * @param Request $request |
| 77 | + * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response | ||
| 76 | */ | 78 | */ |
| 77 | public function getGalleryFiltered($filter, $page = 0, Request $request) | 79 | public function getGalleryFiltered($filter, $page = 0, Request $request) |
| 78 | { | 80 | { |
| ... | @@ -149,12 +151,12 @@ class ImageController extends Controller | ... | @@ -149,12 +151,12 @@ class ImageController extends Controller |
| 149 | 151 | ||
| 150 | /** | 152 | /** |
| 151 | * Deletes an image and all thumbnail/image files | 153 | * Deletes an image and all thumbnail/image files |
| 152 | - * @param PageRepo $pageRepo | 154 | + * @param EntityRepo $entityRepo |
| 153 | * @param Request $request | 155 | * @param Request $request |
| 154 | * @param int $id | 156 | * @param int $id |
| 155 | * @return \Illuminate\Http\JsonResponse | 157 | * @return \Illuminate\Http\JsonResponse |
| 156 | */ | 158 | */ |
| 157 | - public function destroy(PageRepo $pageRepo, Request $request, $id) | 159 | + public function destroy(EntityRepo $entityRepo, Request $request, $id) |
| 158 | { | 160 | { |
| 159 | $image = $this->imageRepo->getById($id); | 161 | $image = $this->imageRepo->getById($id); |
| 160 | $this->checkOwnablePermission('image-delete', $image); | 162 | $this->checkOwnablePermission('image-delete', $image); |
| ... | @@ -162,14 +164,14 @@ class ImageController extends Controller | ... | @@ -162,14 +164,14 @@ class ImageController extends Controller |
| 162 | // Check if this image is used on any pages | 164 | // Check if this image is used on any pages |
| 163 | $isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true); | 165 | $isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true); |
| 164 | if (!$isForced) { | 166 | if (!$isForced) { |
| 165 | - $pageSearch = $pageRepo->searchForImage($image->url); | 167 | + $pageSearch = $entityRepo->searchForImage($image->url); |
| 166 | if ($pageSearch !== false) { | 168 | if ($pageSearch !== false) { |
| 167 | return response()->json($pageSearch, 400); | 169 | return response()->json($pageSearch, 400); |
| 168 | } | 170 | } |
| 169 | } | 171 | } |
| 170 | 172 | ||
| 171 | $this->imageRepo->destroyImage($image); | 173 | $this->imageRepo->destroyImage($image); |
| 172 | - return response()->json('Image Deleted'); | 174 | + return response()->json(trans('components.images_deleted')); |
| 173 | } | 175 | } |
| 174 | 176 | ||
| 175 | 177 | ... | ... |
This diff is collapsed.
Click to expand it.
| ... | @@ -2,9 +2,7 @@ | ... | @@ -2,9 +2,7 @@ |
| 2 | 2 | ||
| 3 | use BookStack\Exceptions\PermissionsException; | 3 | use BookStack\Exceptions\PermissionsException; |
| 4 | use BookStack\Repos\PermissionsRepo; | 4 | use BookStack\Repos\PermissionsRepo; |
| 5 | -use BookStack\Services\PermissionService; | ||
| 6 | use Illuminate\Http\Request; | 5 | use Illuminate\Http\Request; |
| 7 | -use BookStack\Http\Requests; | ||
| 8 | 6 | ||
| 9 | class PermissionController extends Controller | 7 | class PermissionController extends Controller |
| 10 | { | 8 | { |
| ... | @@ -55,7 +53,7 @@ class PermissionController extends Controller | ... | @@ -55,7 +53,7 @@ class PermissionController extends Controller |
| 55 | ]); | 53 | ]); |
| 56 | 54 | ||
| 57 | $this->permissionsRepo->saveNewRole($request->all()); | 55 | $this->permissionsRepo->saveNewRole($request->all()); |
| 58 | - session()->flash('success', 'Role successfully created'); | 56 | + session()->flash('success', trans('settings.role_create_success')); |
| 59 | return redirect('/settings/roles'); | 57 | return redirect('/settings/roles'); |
| 60 | } | 58 | } |
| 61 | 59 | ||
| ... | @@ -69,7 +67,7 @@ class PermissionController extends Controller | ... | @@ -69,7 +67,7 @@ class PermissionController extends Controller |
| 69 | { | 67 | { |
| 70 | $this->checkPermission('user-roles-manage'); | 68 | $this->checkPermission('user-roles-manage'); |
| 71 | $role = $this->permissionsRepo->getRoleById($id); | 69 | $role = $this->permissionsRepo->getRoleById($id); |
| 72 | - if ($role->hidden) throw new PermissionsException('This role cannot be edited'); | 70 | + if ($role->hidden) throw new PermissionsException(trans('errors.role_cannot_be_edited')); |
| 73 | return view('settings/roles/edit', ['role' => $role]); | 71 | return view('settings/roles/edit', ['role' => $role]); |
| 74 | } | 72 | } |
| 75 | 73 | ||
| ... | @@ -88,7 +86,7 @@ class PermissionController extends Controller | ... | @@ -88,7 +86,7 @@ class PermissionController extends Controller |
| 88 | ]); | 86 | ]); |
| 89 | 87 | ||
| 90 | $this->permissionsRepo->updateRole($id, $request->all()); | 88 | $this->permissionsRepo->updateRole($id, $request->all()); |
| 91 | - session()->flash('success', 'Role successfully updated'); | 89 | + session()->flash('success', trans('settings.role_update_success')); |
| 92 | return redirect('/settings/roles'); | 90 | return redirect('/settings/roles'); |
| 93 | } | 91 | } |
| 94 | 92 | ||
| ... | @@ -103,7 +101,7 @@ class PermissionController extends Controller | ... | @@ -103,7 +101,7 @@ class PermissionController extends Controller |
| 103 | $this->checkPermission('user-roles-manage'); | 101 | $this->checkPermission('user-roles-manage'); |
| 104 | $role = $this->permissionsRepo->getRoleById($id); | 102 | $role = $this->permissionsRepo->getRoleById($id); |
| 105 | $roles = $this->permissionsRepo->getAllRolesExcept($role); | 103 | $roles = $this->permissionsRepo->getAllRolesExcept($role); |
| 106 | - $blankRole = $role->newInstance(['display_name' => 'Don\'t migrate users']); | 104 | + $blankRole = $role->newInstance(['display_name' => trans('settings.role_delete_no_migration')]); |
| 107 | $roles->prepend($blankRole); | 105 | $roles->prepend($blankRole); |
| 108 | return view('settings/roles/delete', ['role' => $role, 'roles' => $roles]); | 106 | return view('settings/roles/delete', ['role' => $role, 'roles' => $roles]); |
| 109 | } | 107 | } |
| ... | @@ -126,7 +124,7 @@ class PermissionController extends Controller | ... | @@ -126,7 +124,7 @@ class PermissionController extends Controller |
| 126 | return redirect()->back(); | 124 | return redirect()->back(); |
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | - session()->flash('success', 'Role successfully deleted'); | 127 | + session()->flash('success', trans('settings.role_delete_success')); |
| 130 | return redirect('/settings/roles'); | 128 | return redirect('/settings/roles'); |
| 131 | } | 129 | } |
| 132 | } | 130 | } | ... | ... |
| 1 | -<?php | 1 | +<?php namespace BookStack\Http\Controllers; |
| 2 | - | ||
| 3 | -namespace BookStack\Http\Controllers; | ||
| 4 | 2 | ||
| 3 | +use BookStack\Repos\EntityRepo; | ||
| 5 | use BookStack\Services\ViewService; | 4 | use BookStack\Services\ViewService; |
| 6 | use Illuminate\Http\Request; | 5 | use Illuminate\Http\Request; |
| 7 | 6 | ||
| 8 | -use BookStack\Http\Requests; | ||
| 9 | -use BookStack\Repos\BookRepo; | ||
| 10 | -use BookStack\Repos\ChapterRepo; | ||
| 11 | -use BookStack\Repos\PageRepo; | ||
| 12 | - | ||
| 13 | class SearchController extends Controller | 7 | class SearchController extends Controller |
| 14 | { | 8 | { |
| 15 | - protected $pageRepo; | 9 | + protected $entityRepo; |
| 16 | - protected $bookRepo; | ||
| 17 | - protected $chapterRepo; | ||
| 18 | protected $viewService; | 10 | protected $viewService; |
| 19 | 11 | ||
| 20 | /** | 12 | /** |
| 21 | * SearchController constructor. | 13 | * SearchController constructor. |
| 22 | - * @param PageRepo $pageRepo | 14 | + * @param EntityRepo $entityRepo |
| 23 | - * @param BookRepo $bookRepo | ||
| 24 | - * @param ChapterRepo $chapterRepo | ||
| 25 | * @param ViewService $viewService | 15 | * @param ViewService $viewService |
| 26 | */ | 16 | */ |
| 27 | - public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo, ViewService $viewService) | 17 | + public function __construct(EntityRepo $entityRepo, ViewService $viewService) |
| 28 | { | 18 | { |
| 29 | - $this->pageRepo = $pageRepo; | 19 | + $this->entityRepo = $entityRepo; |
| 30 | - $this->bookRepo = $bookRepo; | ||
| 31 | - $this->chapterRepo = $chapterRepo; | ||
| 32 | $this->viewService = $viewService; | 20 | $this->viewService = $viewService; |
| 33 | parent::__construct(); | 21 | parent::__construct(); |
| 34 | } | 22 | } |
| ... | @@ -46,10 +34,10 @@ class SearchController extends Controller | ... | @@ -46,10 +34,10 @@ class SearchController extends Controller |
| 46 | } | 34 | } |
| 47 | $searchTerm = $request->get('term'); | 35 | $searchTerm = $request->get('term'); |
| 48 | $paginationAppends = $request->only('term'); | 36 | $paginationAppends = $request->only('term'); |
| 49 | - $pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends); | 37 | + $pages = $this->entityRepo->getBySearch('page', $searchTerm, [], 20, $paginationAppends); |
| 50 | - $books = $this->bookRepo->getBySearch($searchTerm, 10, $paginationAppends); | 38 | + $books = $this->entityRepo->getBySearch('book', $searchTerm, [], 10, $paginationAppends); |
| 51 | - $chapters = $this->chapterRepo->getBySearch($searchTerm, [], 10, $paginationAppends); | 39 | + $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, [], 10, $paginationAppends); |
| 52 | - $this->setPageTitle('Search For ' . $searchTerm); | 40 | + $this->setPageTitle(trans('entities.search_for_term', ['term' => $searchTerm])); |
| 53 | return view('search/all', [ | 41 | return view('search/all', [ |
| 54 | 'pages' => $pages, | 42 | 'pages' => $pages, |
| 55 | 'books' => $books, | 43 | 'books' => $books, |
| ... | @@ -69,11 +57,11 @@ class SearchController extends Controller | ... | @@ -69,11 +57,11 @@ class SearchController extends Controller |
| 69 | 57 | ||
| 70 | $searchTerm = $request->get('term'); | 58 | $searchTerm = $request->get('term'); |
| 71 | $paginationAppends = $request->only('term'); | 59 | $paginationAppends = $request->only('term'); |
| 72 | - $pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends); | 60 | + $pages = $this->entityRepo->getBySearch('page', $searchTerm, [], 20, $paginationAppends); |
| 73 | - $this->setPageTitle('Page Search For ' . $searchTerm); | 61 | + $this->setPageTitle(trans('entities.search_page_for_term', ['term' => $searchTerm])); |
| 74 | return view('search/entity-search-list', [ | 62 | return view('search/entity-search-list', [ |
| 75 | 'entities' => $pages, | 63 | 'entities' => $pages, |
| 76 | - 'title' => 'Page Search Results', | 64 | + 'title' => trans('entities.search_results_page'), |
| 77 | 'searchTerm' => $searchTerm | 65 | 'searchTerm' => $searchTerm |
| 78 | ]); | 66 | ]); |
| 79 | } | 67 | } |
| ... | @@ -89,11 +77,11 @@ class SearchController extends Controller | ... | @@ -89,11 +77,11 @@ class SearchController extends Controller |
| 89 | 77 | ||
| 90 | $searchTerm = $request->get('term'); | 78 | $searchTerm = $request->get('term'); |
| 91 | $paginationAppends = $request->only('term'); | 79 | $paginationAppends = $request->only('term'); |
| 92 | - $chapters = $this->chapterRepo->getBySearch($searchTerm, [], 20, $paginationAppends); | 80 | + $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, [], 20, $paginationAppends); |
| 93 | - $this->setPageTitle('Chapter Search For ' . $searchTerm); | 81 | + $this->setPageTitle(trans('entities.search_chapter_for_term', ['term' => $searchTerm])); |
| 94 | return view('search/entity-search-list', [ | 82 | return view('search/entity-search-list', [ |
| 95 | 'entities' => $chapters, | 83 | 'entities' => $chapters, |
| 96 | - 'title' => 'Chapter Search Results', | 84 | + 'title' => trans('entities.search_results_chapter'), |
| 97 | 'searchTerm' => $searchTerm | 85 | 'searchTerm' => $searchTerm |
| 98 | ]); | 86 | ]); |
| 99 | } | 87 | } |
| ... | @@ -109,11 +97,11 @@ class SearchController extends Controller | ... | @@ -109,11 +97,11 @@ class SearchController extends Controller |
| 109 | 97 | ||
| 110 | $searchTerm = $request->get('term'); | 98 | $searchTerm = $request->get('term'); |
| 111 | $paginationAppends = $request->only('term'); | 99 | $paginationAppends = $request->only('term'); |
| 112 | - $books = $this->bookRepo->getBySearch($searchTerm, 20, $paginationAppends); | 100 | + $books = $this->entityRepo->getBySearch('book', $searchTerm, [], 20, $paginationAppends); |
| 113 | - $this->setPageTitle('Book Search For ' . $searchTerm); | 101 | + $this->setPageTitle(trans('entities.search_book_for_term', ['term' => $searchTerm])); |
| 114 | return view('search/entity-search-list', [ | 102 | return view('search/entity-search-list', [ |
| 115 | 'entities' => $books, | 103 | 'entities' => $books, |
| 116 | - 'title' => 'Book Search Results', | 104 | + 'title' => trans('entities.search_results_book'), |
| 117 | 'searchTerm' => $searchTerm | 105 | 'searchTerm' => $searchTerm |
| 118 | ]); | 106 | ]); |
| 119 | } | 107 | } |
| ... | @@ -132,8 +120,8 @@ class SearchController extends Controller | ... | @@ -132,8 +120,8 @@ class SearchController extends Controller |
| 132 | } | 120 | } |
| 133 | $searchTerm = $request->get('term'); | 121 | $searchTerm = $request->get('term'); |
| 134 | $searchWhereTerms = [['book_id', '=', $bookId]]; | 122 | $searchWhereTerms = [['book_id', '=', $bookId]]; |
| 135 | - $pages = $this->pageRepo->getBySearch($searchTerm, $searchWhereTerms); | 123 | + $pages = $this->entityRepo->getBySearch('page', $searchTerm, $searchWhereTerms); |
| 136 | - $chapters = $this->chapterRepo->getBySearch($searchTerm, $searchWhereTerms); | 124 | + $chapters = $this->entityRepo->getBySearch('chapter', $searchTerm, $searchWhereTerms); |
| 137 | return view('search/book', ['pages' => $pages, 'chapters' => $chapters, 'searchTerm' => $searchTerm]); | 125 | return view('search/book', ['pages' => $pages, 'chapters' => $chapters, 'searchTerm' => $searchTerm]); |
| 138 | } | 126 | } |
| 139 | 127 | ||
| ... | @@ -152,9 +140,11 @@ class SearchController extends Controller | ... | @@ -152,9 +140,11 @@ class SearchController extends Controller |
| 152 | 140 | ||
| 153 | // Search for entities otherwise show most popular | 141 | // Search for entities otherwise show most popular |
| 154 | if ($searchTerm !== false) { | 142 | if ($searchTerm !== false) { |
| 155 | - if ($entityTypes->contains('page')) $entities = $entities->merge($this->pageRepo->getBySearch($searchTerm)->items()); | 143 | + foreach (['page', 'chapter', 'book'] as $entityType) { |
| 156 | - if ($entityTypes->contains('chapter')) $entities = $entities->merge($this->chapterRepo->getBySearch($searchTerm)->items()); | 144 | + if ($entityTypes->contains($entityType)) { |
| 157 | - if ($entityTypes->contains('book')) $entities = $entities->merge($this->bookRepo->getBySearch($searchTerm)->items()); | 145 | + $entities = $entities->merge($this->entityRepo->getBySearch($entityType, $searchTerm)->items()); |
| 146 | + } | ||
| 147 | + } | ||
| 158 | $entities = $entities->sortByDesc('title_relevance'); | 148 | $entities = $entities->sortByDesc('title_relevance'); |
| 159 | } else { | 149 | } else { |
| 160 | $entityNames = $entityTypes->map(function ($type) { | 150 | $entityNames = $entityTypes->map(function ($type) { | ... | ... |
| 1 | <?php namespace BookStack\Http\Controllers; | 1 | <?php namespace BookStack\Http\Controllers; |
| 2 | 2 | ||
| 3 | use Illuminate\Http\Request; | 3 | use Illuminate\Http\Request; |
| 4 | - | 4 | +use Illuminate\Http\Response; |
| 5 | -use BookStack\Http\Requests; | ||
| 6 | use Setting; | 5 | use Setting; |
| 7 | 6 | ||
| 8 | class SettingController extends Controller | 7 | class SettingController extends Controller |
| ... | @@ -39,7 +38,7 @@ class SettingController extends Controller | ... | @@ -39,7 +38,7 @@ class SettingController extends Controller |
| 39 | Setting::put($key, $value); | 38 | Setting::put($key, $value); |
| 40 | } | 39 | } |
| 41 | 40 | ||
| 42 | - session()->flash('success', 'Settings Saved'); | 41 | + session()->flash('success', trans('settings.settings_save_success')); |
| 43 | return redirect('/settings'); | 42 | return redirect('/settings'); |
| 44 | } | 43 | } |
| 45 | 44 | ... | ... |
| ... | @@ -2,7 +2,6 @@ | ... | @@ -2,7 +2,6 @@ |
| 2 | 2 | ||
| 3 | use BookStack\Repos\TagRepo; | 3 | use BookStack\Repos\TagRepo; |
| 4 | use Illuminate\Http\Request; | 4 | use Illuminate\Http\Request; |
| 5 | -use BookStack\Http\Requests; | ||
| 6 | 5 | ||
| 7 | class TagController extends Controller | 6 | class TagController extends Controller |
| 8 | { | 7 | { |
| ... | @@ -16,12 +15,14 @@ class TagController extends Controller | ... | @@ -16,12 +15,14 @@ class TagController extends Controller |
| 16 | public function __construct(TagRepo $tagRepo) | 15 | public function __construct(TagRepo $tagRepo) |
| 17 | { | 16 | { |
| 18 | $this->tagRepo = $tagRepo; | 17 | $this->tagRepo = $tagRepo; |
| 18 | + parent::__construct(); | ||
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | * Get all the Tags for a particular entity | 22 | * Get all the Tags for a particular entity |
| 23 | * @param $entityType | 23 | * @param $entityType |
| 24 | * @param $entityId | 24 | * @param $entityId |
| 25 | + * @return \Illuminate\Http\JsonResponse | ||
| 25 | */ | 26 | */ |
| 26 | public function getForEntity($entityType, $entityId) | 27 | public function getForEntity($entityType, $entityId) |
| 27 | { | 28 | { |
| ... | @@ -30,28 +31,9 @@ class TagController extends Controller | ... | @@ -30,28 +31,9 @@ class TagController extends Controller |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | /** | 33 | /** |
| 33 | - * Update the tags for a particular entity. | ||
| 34 | - * @param $entityType | ||
| 35 | - * @param $entityId | ||
| 36 | - * @param Request $request | ||
| 37 | - * @return mixed | ||
| 38 | - */ | ||
| 39 | - public function updateForEntity($entityType, $entityId, Request $request) | ||
| 40 | - { | ||
| 41 | - $entity = $this->tagRepo->getEntity($entityType, $entityId, 'update'); | ||
| 42 | - if ($entity === null) return $this->jsonError("Entity not found", 404); | ||
| 43 | - | ||
| 44 | - $inputTags = $request->input('tags'); | ||
| 45 | - $tags = $this->tagRepo->saveTagsToEntity($entity, $inputTags); | ||
| 46 | - return response()->json([ | ||
| 47 | - 'tags' => $tags, | ||
| 48 | - 'message' => 'Tags successfully updated' | ||
| 49 | - ]); | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - /** | ||
| 53 | * Get tag name suggestions from a given search term. | 34 | * Get tag name suggestions from a given search term. |
| 54 | * @param Request $request | 35 | * @param Request $request |
| 36 | + * @return \Illuminate\Http\JsonResponse | ||
| 55 | */ | 37 | */ |
| 56 | public function getNameSuggestions(Request $request) | 38 | public function getNameSuggestions(Request $request) |
| 57 | { | 39 | { |
| ... | @@ -63,6 +45,7 @@ class TagController extends Controller | ... | @@ -63,6 +45,7 @@ class TagController extends Controller |
| 63 | /** | 45 | /** |
| 64 | * Get tag value suggestions from a given search term. | 46 | * Get tag value suggestions from a given search term. |
| 65 | * @param Request $request | 47 | * @param Request $request |
| 48 | + * @return \Illuminate\Http\JsonResponse | ||
| 66 | */ | 49 | */ |
| 67 | public function getValueSuggestions(Request $request) | 50 | public function getValueSuggestions(Request $request) |
| 68 | { | 51 | { | ... | ... |
| 1 | -<?php | 1 | +<?php namespace BookStack\Http\Controllers; |
| 2 | 2 | ||
| 3 | -namespace BookStack\Http\Controllers; | ||
| 4 | - | ||
| 5 | -use BookStack\Activity; | ||
| 6 | use Exception; | 3 | use Exception; |
| 7 | use Illuminate\Http\Request; | 4 | use Illuminate\Http\Request; |
| 8 | - | ||
| 9 | use Illuminate\Http\Response; | 5 | use Illuminate\Http\Response; |
| 10 | -use BookStack\Http\Requests; | ||
| 11 | use BookStack\Repos\UserRepo; | 6 | use BookStack\Repos\UserRepo; |
| 12 | use BookStack\Services\SocialAuthService; | 7 | use BookStack\Services\SocialAuthService; |
| 13 | use BookStack\User; | 8 | use BookStack\User; |
| ... | @@ -44,7 +39,7 @@ class UserController extends Controller | ... | @@ -44,7 +39,7 @@ class UserController extends Controller |
| 44 | 'sort' => $request->has('sort') ? $request->get('sort') : 'name', | 39 | 'sort' => $request->has('sort') ? $request->get('sort') : 'name', |
| 45 | ]; | 40 | ]; |
| 46 | $users = $this->userRepo->getAllUsersPaginatedAndSorted(20, $listDetails); | 41 | $users = $this->userRepo->getAllUsersPaginatedAndSorted(20, $listDetails); |
| 47 | - $this->setPageTitle('Users'); | 42 | + $this->setPageTitle(trans('settings.users')); |
| 48 | $users->appends($listDetails); | 43 | $users->appends($listDetails); |
| 49 | return view('users/index', ['users' => $users, 'listDetails' => $listDetails]); | 44 | return view('users/index', ['users' => $users, 'listDetails' => $listDetails]); |
| 50 | } | 45 | } |
| ... | @@ -83,7 +78,6 @@ class UserController extends Controller | ... | @@ -83,7 +78,6 @@ class UserController extends Controller |
| 83 | } | 78 | } |
| 84 | $this->validate($request, $validationRules); | 79 | $this->validate($request, $validationRules); |
| 85 | 80 | ||
| 86 | - | ||
| 87 | $user = $this->user->fill($request->all()); | 81 | $user = $this->user->fill($request->all()); |
| 88 | 82 | ||
| 89 | if ($authMethod === 'standard') { | 83 | if ($authMethod === 'standard') { |
| ... | @@ -131,7 +125,7 @@ class UserController extends Controller | ... | @@ -131,7 +125,7 @@ class UserController extends Controller |
| 131 | $authMethod = ($user->system_name) ? 'system' : config('auth.method'); | 125 | $authMethod = ($user->system_name) ? 'system' : config('auth.method'); |
| 132 | 126 | ||
| 133 | $activeSocialDrivers = $socialAuthService->getActiveDrivers(); | 127 | $activeSocialDrivers = $socialAuthService->getActiveDrivers(); |
| 134 | - $this->setPageTitle('User Profile'); | 128 | + $this->setPageTitle(trans('settings.user_profile')); |
| 135 | $roles = $this->userRepo->getAllRoles(); | 129 | $roles = $this->userRepo->getAllRoles(); |
| 136 | return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]); | 130 | return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]); |
| 137 | } | 131 | } |
| ... | @@ -153,9 +147,8 @@ class UserController extends Controller | ... | @@ -153,9 +147,8 @@ class UserController extends Controller |
| 153 | 'name' => 'min:2', | 147 | 'name' => 'min:2', |
| 154 | 'email' => 'min:2|email|unique:users,email,' . $id, | 148 | 'email' => 'min:2|email|unique:users,email,' . $id, |
| 155 | 'password' => 'min:5|required_with:password_confirm', | 149 | 'password' => 'min:5|required_with:password_confirm', |
| 156 | - 'password-confirm' => 'same:password|required_with:password' | 150 | + 'password-confirm' => 'same:password|required_with:password', |
| 157 | - ], [ | 151 | + 'setting' => 'array' |
| 158 | - 'password-confirm.required_with' => 'Password confirmation required' | ||
| 159 | ]); | 152 | ]); |
| 160 | 153 | ||
| 161 | $user = $this->user->findOrFail($id); | 154 | $user = $this->user->findOrFail($id); |
| ... | @@ -178,8 +171,15 @@ class UserController extends Controller | ... | @@ -178,8 +171,15 @@ class UserController extends Controller |
| 178 | $user->external_auth_id = $request->get('external_auth_id'); | 171 | $user->external_auth_id = $request->get('external_auth_id'); |
| 179 | } | 172 | } |
| 180 | 173 | ||
| 174 | + // Save an user-specific settings | ||
| 175 | + if ($request->has('setting')) { | ||
| 176 | + foreach ($request->get('setting') as $key => $value) { | ||
| 177 | + setting()->putUser($user, $key, $value); | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | $user->save(); | 181 | $user->save(); |
| 182 | - session()->flash('success', 'User successfully updated'); | 182 | + session()->flash('success', trans('settings.users_edit_success')); |
| 183 | 183 | ||
| 184 | $redirectUrl = userCan('users-manage') ? '/settings/users' : '/settings/users/' . $user->id; | 184 | $redirectUrl = userCan('users-manage') ? '/settings/users' : '/settings/users/' . $user->id; |
| 185 | return redirect($redirectUrl); | 185 | return redirect($redirectUrl); |
| ... | @@ -197,7 +197,7 @@ class UserController extends Controller | ... | @@ -197,7 +197,7 @@ class UserController extends Controller |
| 197 | }); | 197 | }); |
| 198 | 198 | ||
| 199 | $user = $this->user->findOrFail($id); | 199 | $user = $this->user->findOrFail($id); |
| 200 | - $this->setPageTitle('Delete User ' . $user->name); | 200 | + $this->setPageTitle(trans('settings.users_delete_named', ['userName' => $user->name])); |
| 201 | return view('users/delete', ['user' => $user]); | 201 | return view('users/delete', ['user' => $user]); |
| 202 | } | 202 | } |
| 203 | 203 | ||
| ... | @@ -216,17 +216,17 @@ class UserController extends Controller | ... | @@ -216,17 +216,17 @@ class UserController extends Controller |
| 216 | $user = $this->userRepo->getById($id); | 216 | $user = $this->userRepo->getById($id); |
| 217 | 217 | ||
| 218 | if ($this->userRepo->isOnlyAdmin($user)) { | 218 | if ($this->userRepo->isOnlyAdmin($user)) { |
| 219 | - session()->flash('error', 'You cannot delete the only admin'); | 219 | + session()->flash('error', trans('errors.users_cannot_delete_only_admin')); |
| 220 | return redirect($user->getEditUrl()); | 220 | return redirect($user->getEditUrl()); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | if ($user->system_name === 'public') { | 223 | if ($user->system_name === 'public') { |
| 224 | - session()->flash('error', 'You cannot delete the guest user'); | 224 | + session()->flash('error', trans('errors.users_cannot_delete_guest')); |
| 225 | return redirect($user->getEditUrl()); | 225 | return redirect($user->getEditUrl()); |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | $this->userRepo->destroy($user); | 228 | $this->userRepo->destroy($user); |
| 229 | - session()->flash('success', 'User successfully removed'); | 229 | + session()->flash('success', trans('settings.users_delete_success')); |
| 230 | 230 | ||
| 231 | return redirect('/settings/users'); | 231 | return redirect('/settings/users'); |
| 232 | } | 232 | } | ... | ... |
| 1 | -<?php | 1 | +<?php namespace BookStack\Http; |
| 2 | - | ||
| 3 | -namespace BookStack\Http; | ||
| 4 | 2 | ||
| 5 | use Illuminate\Foundation\Http\Kernel as HttpKernel; | 3 | use Illuminate\Foundation\Http\Kernel as HttpKernel; |
| 6 | 4 | ||
| ... | @@ -30,6 +28,7 @@ class Kernel extends HttpKernel | ... | @@ -30,6 +28,7 @@ class Kernel extends HttpKernel |
| 30 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, | 28 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, |
| 31 | \BookStack\Http\Middleware\VerifyCsrfToken::class, | 29 | \BookStack\Http\Middleware\VerifyCsrfToken::class, |
| 32 | \Illuminate\Routing\Middleware\SubstituteBindings::class, | 30 | \Illuminate\Routing\Middleware\SubstituteBindings::class, |
| 31 | + \BookStack\Http\Middleware\Localization::class | ||
| 33 | ], | 32 | ], |
| 34 | 'api' => [ | 33 | 'api' => [ |
| 35 | 'throttle:60,1', | 34 | 'throttle:60,1', | ... | ... |
| ... | @@ -4,8 +4,6 @@ namespace BookStack\Http\Middleware; | ... | @@ -4,8 +4,6 @@ namespace BookStack\Http\Middleware; |
| 4 | 4 | ||
| 5 | use Closure; | 5 | use Closure; |
| 6 | use Illuminate\Contracts\Auth\Guard; | 6 | use Illuminate\Contracts\Auth\Guard; |
| 7 | -use BookStack\Exceptions\UserRegistrationException; | ||
| 8 | -use Setting; | ||
| 9 | 7 | ||
| 10 | class Authenticate | 8 | class Authenticate |
| 11 | { | 9 | { | ... | ... |
app/Http/Middleware/Localization.php
0 → 100644
| 1 | +<?php namespace BookStack\Http\Middleware; | ||
| 2 | + | ||
| 3 | +use Carbon\Carbon; | ||
| 4 | +use Closure; | ||
| 5 | + | ||
| 6 | +class Localization | ||
| 7 | +{ | ||
| 8 | + /** | ||
| 9 | + * Handle an incoming request. | ||
| 10 | + * | ||
| 11 | + * @param \Illuminate\Http\Request $request | ||
| 12 | + * @param \Closure $next | ||
| 13 | + * @return mixed | ||
| 14 | + */ | ||
| 15 | + public function handle($request, Closure $next) | ||
| 16 | + { | ||
| 17 | + $defaultLang = config('app.locale'); | ||
| 18 | + $locale = setting()->getUser(user(), 'language', $defaultLang); | ||
| 19 | + app()->setLocale($locale); | ||
| 20 | + Carbon::setLocale($locale); | ||
| 21 | + return $next($request); | ||
| 22 | + } | ||
| 23 | +} |
| ... | @@ -43,8 +43,9 @@ class ResetPassword extends Notification | ... | @@ -43,8 +43,9 @@ class ResetPassword extends Notification |
| 43 | public function toMail() | 43 | public function toMail() |
| 44 | { | 44 | { |
| 45 | return (new MailMessage) | 45 | return (new MailMessage) |
| 46 | - ->line('You are receiving this email because we received a password reset request for your account.') | 46 | + ->subject(trans('auth.email_reset_subject', ['appName' => setting('app-name')])) |
| 47 | - ->action('Reset Password', baseUrl('password/reset/' . $this->token)) | 47 | + ->line(trans('auth.email_reset_text')) |
| 48 | - ->line('If you did not request a password reset, no further action is required.'); | 48 | + ->action(trans('auth.reset_password'), baseUrl('password/reset/' . $this->token)) |
| 49 | + ->line(trans('auth.email_reset_not_requested')); | ||
| 49 | } | 50 | } |
| 50 | } | 51 | } | ... | ... |
| ... | @@ -7,6 +7,10 @@ class Page extends Entity | ... | @@ -7,6 +7,10 @@ class Page extends Entity |
| 7 | 7 | ||
| 8 | protected $simpleAttributes = ['name', 'id', 'slug']; | 8 | protected $simpleAttributes = ['name', 'id', 'slug']; |
| 9 | 9 | ||
| 10 | + protected $with = ['book']; | ||
| 11 | + | ||
| 12 | + protected $fieldsToSearch = ['name', 'text']; | ||
| 13 | + | ||
| 10 | /** | 14 | /** |
| 11 | * Converts this page into a simplified array. | 15 | * Converts this page into a simplified array. |
| 12 | * @return mixed | 16 | * @return mixed | ... | ... |
| 1 | <?php namespace BookStack\Providers; | 1 | <?php namespace BookStack\Providers; |
| 2 | 2 | ||
| 3 | use Illuminate\Support\ServiceProvider; | 3 | use Illuminate\Support\ServiceProvider; |
| 4 | +use Validator; | ||
| 4 | 5 | ||
| 5 | class AppServiceProvider extends ServiceProvider | 6 | class AppServiceProvider extends ServiceProvider |
| 6 | { | 7 | { |
| ... | @@ -12,11 +13,10 @@ class AppServiceProvider extends ServiceProvider | ... | @@ -12,11 +13,10 @@ class AppServiceProvider extends ServiceProvider |
| 12 | public function boot() | 13 | public function boot() |
| 13 | { | 14 | { |
| 14 | // Custom validation methods | 15 | // Custom validation methods |
| 15 | - \Validator::extend('is_image', function($attribute, $value, $parameters, $validator) { | 16 | + Validator::extend('is_image', function($attribute, $value, $parameters, $validator) { |
| 16 | $imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/tiff', 'image/webp']; | 17 | $imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/tiff', 'image/webp']; |
| 17 | return in_array($value->getMimeType(), $imageMimes); | 18 | return in_array($value->getMimeType(), $imageMimes); |
| 18 | }); | 19 | }); |
| 19 | - | ||
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | /** | 22 | /** | ... | ... |
app/Repos/BookRepo.php
deleted
100644 → 0
| 1 | -<?php namespace BookStack\Repos; | ||
| 2 | - | ||
| 3 | -use Alpha\B; | ||
| 4 | -use BookStack\Exceptions\NotFoundException; | ||
| 5 | -use Illuminate\Database\Eloquent\Collection; | ||
| 6 | -use Illuminate\Support\Str; | ||
| 7 | -use BookStack\Book; | ||
| 8 | -use Views; | ||
| 9 | - | ||
| 10 | -class BookRepo extends EntityRepo | ||
| 11 | -{ | ||
| 12 | - protected $pageRepo; | ||
| 13 | - protected $chapterRepo; | ||
| 14 | - | ||
| 15 | - /** | ||
| 16 | - * BookRepo constructor. | ||
| 17 | - * @param PageRepo $pageRepo | ||
| 18 | - * @param ChapterRepo $chapterRepo | ||
| 19 | - */ | ||
| 20 | - public function __construct(PageRepo $pageRepo, ChapterRepo $chapterRepo) | ||
| 21 | - { | ||
| 22 | - $this->pageRepo = $pageRepo; | ||
| 23 | - $this->chapterRepo = $chapterRepo; | ||
| 24 | - parent::__construct(); | ||
| 25 | - } | ||
| 26 | - | ||
| 27 | - /** | ||
| 28 | - * Base query for getting books. | ||
| 29 | - * Takes into account any restrictions. | ||
| 30 | - * @return mixed | ||
| 31 | - */ | ||
| 32 | - private function bookQuery() | ||
| 33 | - { | ||
| 34 | - return $this->permissionService->enforceBookRestrictions($this->book, 'view'); | ||
| 35 | - } | ||
| 36 | - | ||
| 37 | - /** | ||
| 38 | - * Get the book that has the given id. | ||
| 39 | - * @param $id | ||
| 40 | - * @return mixed | ||
| 41 | - */ | ||
| 42 | - public function getById($id) | ||
| 43 | - { | ||
| 44 | - return $this->bookQuery()->findOrFail($id); | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | - /** | ||
| 48 | - * Get all books, Limited by count. | ||
| 49 | - * @param int $count | ||
| 50 | - * @return mixed | ||
| 51 | - */ | ||
| 52 | - public function getAll($count = 10) | ||
| 53 | - { | ||
| 54 | - $bookQuery = $this->bookQuery()->orderBy('name', 'asc'); | ||
| 55 | - if (!$count) return $bookQuery->get(); | ||
| 56 | - return $bookQuery->take($count)->get(); | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - /** | ||
| 60 | - * Get all books paginated. | ||
| 61 | - * @param int $count | ||
| 62 | - * @return mixed | ||
| 63 | - */ | ||
| 64 | - public function getAllPaginated($count = 10) | ||
| 65 | - { | ||
| 66 | - return $this->bookQuery() | ||
| 67 | - ->orderBy('name', 'asc')->paginate($count); | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - | ||
| 71 | - /** | ||
| 72 | - * Get the latest books. | ||
| 73 | - * @param int $count | ||
| 74 | - * @return mixed | ||
| 75 | - */ | ||
| 76 | - public function getLatest($count = 10) | ||
| 77 | - { | ||
| 78 | - return $this->bookQuery()->orderBy('created_at', 'desc')->take($count)->get(); | ||
| 79 | - } | ||
| 80 | - | ||
| 81 | - /** | ||
| 82 | - * Gets the most recently viewed for a user. | ||
| 83 | - * @param int $count | ||
| 84 | - * @param int $page | ||
| 85 | - * @return mixed | ||
| 86 | - */ | ||
| 87 | - public function getRecentlyViewed($count = 10, $page = 0) | ||
| 88 | - { | ||
| 89 | - return Views::getUserRecentlyViewed($count, $page, $this->book); | ||
| 90 | - } | ||
| 91 | - | ||
| 92 | - /** | ||
| 93 | - * Gets the most viewed books. | ||
| 94 | - * @param int $count | ||
| 95 | - * @param int $page | ||
| 96 | - * @return mixed | ||
| 97 | - */ | ||
| 98 | - public function getPopular($count = 10, $page = 0) | ||
| 99 | - { | ||
| 100 | - return Views::getPopular($count, $page, $this->book); | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - /** | ||
| 104 | - * Get a book by slug | ||
| 105 | - * @param $slug | ||
| 106 | - * @return mixed | ||
| 107 | - * @throws NotFoundException | ||
| 108 | - */ | ||
| 109 | - public function getBySlug($slug) | ||
| 110 | - { | ||
| 111 | - $book = $this->bookQuery()->where('slug', '=', $slug)->first(); | ||
| 112 | - if ($book === null) throw new NotFoundException('Book not found'); | ||
| 113 | - return $book; | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - /** | ||
| 117 | - * Checks if a book exists. | ||
| 118 | - * @param $id | ||
| 119 | - * @return bool | ||
| 120 | - */ | ||
| 121 | - public function exists($id) | ||
| 122 | - { | ||
| 123 | - return $this->bookQuery()->where('id', '=', $id)->exists(); | ||
| 124 | - } | ||
| 125 | - | ||
| 126 | - /** | ||
| 127 | - * Get a new book instance from request input. | ||
| 128 | - * @param array $input | ||
| 129 | - * @return Book | ||
| 130 | - */ | ||
| 131 | - public function createFromInput($input) | ||
| 132 | - { | ||
| 133 | - $book = $this->book->newInstance($input); | ||
| 134 | - $book->slug = $this->findSuitableSlug($book->name); | ||
| 135 | - $book->created_by = user()->id; | ||
| 136 | - $book->updated_by = user()->id; | ||
| 137 | - $book->save(); | ||
| 138 | - $this->permissionService->buildJointPermissionsForEntity($book); | ||
| 139 | - return $book; | ||
| 140 | - } | ||
| 141 | - | ||
| 142 | - /** | ||
| 143 | - * Update the given book from user input. | ||
| 144 | - * @param Book $book | ||
| 145 | - * @param $input | ||
| 146 | - * @return Book | ||
| 147 | - */ | ||
| 148 | - public function updateFromInput(Book $book, $input) | ||
| 149 | - { | ||
| 150 | - if ($book->name !== $input['name']) { | ||
| 151 | - $book->slug = $this->findSuitableSlug($input['name'], $book->id); | ||
| 152 | - } | ||
| 153 | - $book->fill($input); | ||
| 154 | - $book->updated_by = user()->id; | ||
| 155 | - $book->save(); | ||
| 156 | - $this->permissionService->buildJointPermissionsForEntity($book); | ||
| 157 | - return $book; | ||
| 158 | - } | ||
| 159 | - | ||
| 160 | - /** | ||
| 161 | - * Destroy the given book. | ||
| 162 | - * @param Book $book | ||
| 163 | - * @throws \Exception | ||
| 164 | - */ | ||
| 165 | - public function destroy(Book $book) | ||
| 166 | - { | ||
| 167 | - foreach ($book->pages as $page) { | ||
| 168 | - $this->pageRepo->destroy($page); | ||
| 169 | - } | ||
| 170 | - foreach ($book->chapters as $chapter) { | ||
| 171 | - $this->chapterRepo->destroy($chapter); | ||
| 172 | - } | ||
| 173 | - $book->views()->delete(); | ||
| 174 | - $book->permissions()->delete(); | ||
| 175 | - $this->permissionService->deleteJointPermissionsForEntity($book); | ||
| 176 | - $book->delete(); | ||
| 177 | - } | ||
| 178 | - | ||
| 179 | - /** | ||
| 180 | - * Get the next child element priority. | ||
| 181 | - * @param Book $book | ||
| 182 | - * @return int | ||
| 183 | - */ | ||
| 184 | - public function getNewPriority($book) | ||
| 185 | - { | ||
| 186 | - $lastElem = $this->getChildren($book)->pop(); | ||
| 187 | - return $lastElem ? $lastElem->priority + 1 : 0; | ||
| 188 | - } | ||
| 189 | - | ||
| 190 | - /** | ||
| 191 | - * @param string $slug | ||
| 192 | - * @param bool|false $currentId | ||
| 193 | - * @return bool | ||
| 194 | - */ | ||
| 195 | - public function doesSlugExist($slug, $currentId = false) | ||
| 196 | - { | ||
| 197 | - $query = $this->book->where('slug', '=', $slug); | ||
| 198 | - if ($currentId) { | ||
| 199 | - $query = $query->where('id', '!=', $currentId); | ||
| 200 | - } | ||
| 201 | - return $query->count() > 0; | ||
| 202 | - } | ||
| 203 | - | ||
| 204 | - /** | ||
| 205 | - * Provides a suitable slug for the given book name. | ||
| 206 | - * Ensures the returned slug is unique in the system. | ||
| 207 | - * @param string $name | ||
| 208 | - * @param bool|false $currentId | ||
| 209 | - * @return string | ||
| 210 | - */ | ||
| 211 | - public function findSuitableSlug($name, $currentId = false) | ||
| 212 | - { | ||
| 213 | - $slug = $this->nameToSlug($name); | ||
| 214 | - while ($this->doesSlugExist($slug, $currentId)) { | ||
| 215 | - $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); | ||
| 216 | - } | ||
| 217 | - return $slug; | ||
| 218 | - } | ||
| 219 | - | ||
| 220 | - /** | ||
| 221 | - * Get all child objects of a book. | ||
| 222 | - * Returns a sorted collection of Pages and Chapters. | ||
| 223 | - * Loads the book slug onto child elements to prevent access database access for getting the slug. | ||
| 224 | - * @param Book $book | ||
| 225 | - * @param bool $filterDrafts | ||
| 226 | - * @return mixed | ||
| 227 | - */ | ||
| 228 | - public function getChildren(Book $book, $filterDrafts = false) | ||
| 229 | - { | ||
| 230 | - $pageQuery = $book->pages()->where('chapter_id', '=', 0); | ||
| 231 | - $pageQuery = $this->permissionService->enforcePageRestrictions($pageQuery, 'view'); | ||
| 232 | - | ||
| 233 | - if ($filterDrafts) { | ||
| 234 | - $pageQuery = $pageQuery->where('draft', '=', false); | ||
| 235 | - } | ||
| 236 | - | ||
| 237 | - $pages = $pageQuery->get(); | ||
| 238 | - | ||
| 239 | - $chapterQuery = $book->chapters()->with(['pages' => function ($query) use ($filterDrafts) { | ||
| 240 | - $this->permissionService->enforcePageRestrictions($query, 'view'); | ||
| 241 | - if ($filterDrafts) $query->where('draft', '=', false); | ||
| 242 | - }]); | ||
| 243 | - $chapterQuery = $this->permissionService->enforceChapterRestrictions($chapterQuery, 'view'); | ||
| 244 | - $chapters = $chapterQuery->get(); | ||
| 245 | - $children = $pages->values(); | ||
| 246 | - foreach ($chapters as $chapter) { | ||
| 247 | - $children->push($chapter); | ||
| 248 | - } | ||
| 249 | - $bookSlug = $book->slug; | ||
| 250 | - | ||
| 251 | - $children->each(function ($child) use ($bookSlug) { | ||
| 252 | - $child->setAttribute('bookSlug', $bookSlug); | ||
| 253 | - if ($child->isA('chapter')) { | ||
| 254 | - $child->pages->each(function ($page) use ($bookSlug) { | ||
| 255 | - $page->setAttribute('bookSlug', $bookSlug); | ||
| 256 | - }); | ||
| 257 | - $child->pages = $child->pages->sortBy(function ($child, $key) { | ||
| 258 | - $score = $child->priority; | ||
| 259 | - if ($child->draft) $score -= 100; | ||
| 260 | - return $score; | ||
| 261 | - }); | ||
| 262 | - } | ||
| 263 | - }); | ||
| 264 | - | ||
| 265 | - // Sort items with drafts first then by priority. | ||
| 266 | - return $children->sortBy(function ($child, $key) { | ||
| 267 | - $score = $child->priority; | ||
| 268 | - if ($child->isA('page') && $child->draft) $score -= 100; | ||
| 269 | - return $score; | ||
| 270 | - }); | ||
| 271 | - } | ||
| 272 | - | ||
| 273 | - /** | ||
| 274 | - * Get books by search term. | ||
| 275 | - * @param $term | ||
| 276 | - * @param int $count | ||
| 277 | - * @param array $paginationAppends | ||
| 278 | - * @return mixed | ||
| 279 | - */ | ||
| 280 | - public function getBySearch($term, $count = 20, $paginationAppends = []) | ||
| 281 | - { | ||
| 282 | - $terms = $this->prepareSearchTerms($term); | ||
| 283 | - $bookQuery = $this->permissionService->enforceBookRestrictions($this->book->fullTextSearchQuery(['name', 'description'], $terms)); | ||
| 284 | - $bookQuery = $this->addAdvancedSearchQueries($bookQuery, $term); | ||
| 285 | - $books = $bookQuery->paginate($count)->appends($paginationAppends); | ||
| 286 | - $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | ||
| 287 | - foreach ($books as $book) { | ||
| 288 | - //highlight | ||
| 289 | - $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $book->getExcerpt(100)); | ||
| 290 | - $book->searchSnippet = $result; | ||
| 291 | - } | ||
| 292 | - return $books; | ||
| 293 | - } | ||
| 294 | - | ||
| 295 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
app/Repos/ChapterRepo.php
deleted
100644 → 0
| 1 | -<?php namespace BookStack\Repos; | ||
| 2 | - | ||
| 3 | - | ||
| 4 | -use Activity; | ||
| 5 | -use BookStack\Book; | ||
| 6 | -use BookStack\Exceptions\NotFoundException; | ||
| 7 | -use Illuminate\Support\Str; | ||
| 8 | -use BookStack\Chapter; | ||
| 9 | - | ||
| 10 | -class ChapterRepo extends EntityRepo | ||
| 11 | -{ | ||
| 12 | - protected $pageRepo; | ||
| 13 | - | ||
| 14 | - /** | ||
| 15 | - * ChapterRepo constructor. | ||
| 16 | - * @param $pageRepo | ||
| 17 | - */ | ||
| 18 | - public function __construct(PageRepo $pageRepo) | ||
| 19 | - { | ||
| 20 | - $this->pageRepo = $pageRepo; | ||
| 21 | - parent::__construct(); | ||
| 22 | - } | ||
| 23 | - | ||
| 24 | - /** | ||
| 25 | - * Base query for getting chapters, Takes permissions into account. | ||
| 26 | - * @return mixed | ||
| 27 | - */ | ||
| 28 | - private function chapterQuery() | ||
| 29 | - { | ||
| 30 | - return $this->permissionService->enforceChapterRestrictions($this->chapter, 'view'); | ||
| 31 | - } | ||
| 32 | - | ||
| 33 | - /** | ||
| 34 | - * Check if an id exists. | ||
| 35 | - * @param $id | ||
| 36 | - * @return bool | ||
| 37 | - */ | ||
| 38 | - public function idExists($id) | ||
| 39 | - { | ||
| 40 | - return $this->chapterQuery()->where('id', '=', $id)->count() > 0; | ||
| 41 | - } | ||
| 42 | - | ||
| 43 | - /** | ||
| 44 | - * Get a chapter by a specific id. | ||
| 45 | - * @param $id | ||
| 46 | - * @return mixed | ||
| 47 | - */ | ||
| 48 | - public function getById($id) | ||
| 49 | - { | ||
| 50 | - return $this->chapterQuery()->findOrFail($id); | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - /** | ||
| 54 | - * Get all chapters. | ||
| 55 | - * @return \Illuminate\Database\Eloquent\Collection|static[] | ||
| 56 | - */ | ||
| 57 | - public function getAll() | ||
| 58 | - { | ||
| 59 | - return $this->chapterQuery()->all(); | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - /** | ||
| 63 | - * Get a chapter that has the given slug within the given book. | ||
| 64 | - * @param $slug | ||
| 65 | - * @param $bookId | ||
| 66 | - * @return mixed | ||
| 67 | - * @throws NotFoundException | ||
| 68 | - */ | ||
| 69 | - public function getBySlug($slug, $bookId) | ||
| 70 | - { | ||
| 71 | - $chapter = $this->chapterQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first(); | ||
| 72 | - if ($chapter === null) throw new NotFoundException('Chapter not found'); | ||
| 73 | - return $chapter; | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - /** | ||
| 77 | - * Get the child items for a chapter | ||
| 78 | - * @param Chapter $chapter | ||
| 79 | - */ | ||
| 80 | - public function getChildren(Chapter $chapter) | ||
| 81 | - { | ||
| 82 | - $pages = $this->permissionService->enforcePageRestrictions($chapter->pages())->get(); | ||
| 83 | - // Sort items with drafts first then by priority. | ||
| 84 | - return $pages->sortBy(function ($child, $key) { | ||
| 85 | - $score = $child->priority; | ||
| 86 | - if ($child->draft) $score -= 100; | ||
| 87 | - return $score; | ||
| 88 | - }); | ||
| 89 | - } | ||
| 90 | - | ||
| 91 | - /** | ||
| 92 | - * Create a new chapter from request input. | ||
| 93 | - * @param $input | ||
| 94 | - * @param Book $book | ||
| 95 | - * @return Chapter | ||
| 96 | - */ | ||
| 97 | - public function createFromInput($input, Book $book) | ||
| 98 | - { | ||
| 99 | - $chapter = $this->chapter->newInstance($input); | ||
| 100 | - $chapter->slug = $this->findSuitableSlug($chapter->name, $book->id); | ||
| 101 | - $chapter->created_by = user()->id; | ||
| 102 | - $chapter->updated_by = user()->id; | ||
| 103 | - $chapter = $book->chapters()->save($chapter); | ||
| 104 | - $this->permissionService->buildJointPermissionsForEntity($chapter); | ||
| 105 | - return $chapter; | ||
| 106 | - } | ||
| 107 | - | ||
| 108 | - /** | ||
| 109 | - * Destroy a chapter and its relations by providing its slug. | ||
| 110 | - * @param Chapter $chapter | ||
| 111 | - */ | ||
| 112 | - public function destroy(Chapter $chapter) | ||
| 113 | - { | ||
| 114 | - if (count($chapter->pages) > 0) { | ||
| 115 | - foreach ($chapter->pages as $page) { | ||
| 116 | - $page->chapter_id = 0; | ||
| 117 | - $page->save(); | ||
| 118 | - } | ||
| 119 | - } | ||
| 120 | - Activity::removeEntity($chapter); | ||
| 121 | - $chapter->views()->delete(); | ||
| 122 | - $chapter->permissions()->delete(); | ||
| 123 | - $this->permissionService->deleteJointPermissionsForEntity($chapter); | ||
| 124 | - $chapter->delete(); | ||
| 125 | - } | ||
| 126 | - | ||
| 127 | - /** | ||
| 128 | - * Check if a chapter's slug exists. | ||
| 129 | - * @param $slug | ||
| 130 | - * @param $bookId | ||
| 131 | - * @param bool|false $currentId | ||
| 132 | - * @return bool | ||
| 133 | - */ | ||
| 134 | - public function doesSlugExist($slug, $bookId, $currentId = false) | ||
| 135 | - { | ||
| 136 | - $query = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId); | ||
| 137 | - if ($currentId) { | ||
| 138 | - $query = $query->where('id', '!=', $currentId); | ||
| 139 | - } | ||
| 140 | - return $query->count() > 0; | ||
| 141 | - } | ||
| 142 | - | ||
| 143 | - /** | ||
| 144 | - * Finds a suitable slug for the provided name. | ||
| 145 | - * Checks database to prevent duplicate slugs. | ||
| 146 | - * @param $name | ||
| 147 | - * @param $bookId | ||
| 148 | - * @param bool|false $currentId | ||
| 149 | - * @return string | ||
| 150 | - */ | ||
| 151 | - public function findSuitableSlug($name, $bookId, $currentId = false) | ||
| 152 | - { | ||
| 153 | - $slug = $this->nameToSlug($name); | ||
| 154 | - while ($this->doesSlugExist($slug, $bookId, $currentId)) { | ||
| 155 | - $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); | ||
| 156 | - } | ||
| 157 | - return $slug; | ||
| 158 | - } | ||
| 159 | - | ||
| 160 | - /** | ||
| 161 | - * Get a new priority value for a new page to be added | ||
| 162 | - * to the given chapter. | ||
| 163 | - * @param Chapter $chapter | ||
| 164 | - * @return int | ||
| 165 | - */ | ||
| 166 | - public function getNewPriority(Chapter $chapter) | ||
| 167 | - { | ||
| 168 | - $lastPage = $chapter->pages->last(); | ||
| 169 | - return $lastPage !== null ? $lastPage->priority + 1 : 0; | ||
| 170 | - } | ||
| 171 | - | ||
| 172 | - /** | ||
| 173 | - * Get chapters by the given search term. | ||
| 174 | - * @param string $term | ||
| 175 | - * @param array $whereTerms | ||
| 176 | - * @param int $count | ||
| 177 | - * @param array $paginationAppends | ||
| 178 | - * @return mixed | ||
| 179 | - */ | ||
| 180 | - public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = []) | ||
| 181 | - { | ||
| 182 | - $terms = $this->prepareSearchTerms($term); | ||
| 183 | - $chapterQuery = $this->permissionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms)); | ||
| 184 | - $chapterQuery = $this->addAdvancedSearchQueries($chapterQuery, $term); | ||
| 185 | - $chapters = $chapterQuery->paginate($count)->appends($paginationAppends); | ||
| 186 | - $words = join('|', explode(' ', preg_quote(trim($term), '/'))); | ||
| 187 | - foreach ($chapters as $chapter) { | ||
| 188 | - //highlight | ||
| 189 | - $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $chapter->getExcerpt(100)); | ||
| 190 | - $chapter->searchSnippet = $result; | ||
| 191 | - } | ||
| 192 | - return $chapters; | ||
| 193 | - } | ||
| 194 | - | ||
| 195 | - /** | ||
| 196 | - * Changes the book relation of this chapter. | ||
| 197 | - * @param $bookId | ||
| 198 | - * @param Chapter $chapter | ||
| 199 | - * @param bool $rebuildPermissions | ||
| 200 | - * @return Chapter | ||
| 201 | - */ | ||
| 202 | - public function changeBook($bookId, Chapter $chapter, $rebuildPermissions = false) | ||
| 203 | - { | ||
| 204 | - $chapter->book_id = $bookId; | ||
| 205 | - // Update related activity | ||
| 206 | - foreach ($chapter->activity as $activity) { | ||
| 207 | - $activity->book_id = $bookId; | ||
| 208 | - $activity->save(); | ||
| 209 | - } | ||
| 210 | - $chapter->slug = $this->findSuitableSlug($chapter->name, $bookId, $chapter->id); | ||
| 211 | - $chapter->save(); | ||
| 212 | - // Update all child pages | ||
| 213 | - foreach ($chapter->pages as $page) { | ||
| 214 | - $this->pageRepo->changeBook($bookId, $page); | ||
| 215 | - } | ||
| 216 | - | ||
| 217 | - // Update permissions if applicable | ||
| 218 | - if ($rebuildPermissions) { | ||
| 219 | - $chapter->load('book'); | ||
| 220 | - $this->permissionService->buildJointPermissionsForEntity($chapter->book); | ||
| 221 | - } | ||
| 222 | - | ||
| 223 | - return $chapter; | ||
| 224 | - } | ||
| 225 | - | ||
| 226 | -} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
This diff is collapsed.
Click to expand it.
app/Repos/PageRepo.php
deleted
100644 → 0
This diff is collapsed.
Click to expand it.
| ... | @@ -93,7 +93,7 @@ class PermissionsRepo | ... | @@ -93,7 +93,7 @@ class PermissionsRepo |
| 93 | $permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : []; | 93 | $permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : []; |
| 94 | $this->assignRolePermissions($role, $permissions); | 94 | $this->assignRolePermissions($role, $permissions); |
| 95 | 95 | ||
| 96 | - if ($role->name === 'admin') { | 96 | + if ($role->system_name === 'admin') { |
| 97 | $permissions = $this->permission->all()->pluck('id')->toArray(); | 97 | $permissions = $this->permission->all()->pluck('id')->toArray(); |
| 98 | $role->permissions()->sync($permissions); | 98 | $role->permissions()->sync($permissions); |
| 99 | } | 99 | } |
| ... | @@ -133,9 +133,9 @@ class PermissionsRepo | ... | @@ -133,9 +133,9 @@ class PermissionsRepo |
| 133 | 133 | ||
| 134 | // Prevent deleting admin role or default registration role. | 134 | // Prevent deleting admin role or default registration role. |
| 135 | if ($role->system_name && in_array($role->system_name, $this->systemRoles)) { | 135 | if ($role->system_name && in_array($role->system_name, $this->systemRoles)) { |
| 136 | - throw new PermissionsException('This role is a system role and cannot be deleted'); | 136 | + throw new PermissionsException(trans('errors.role_system_cannot_be_deleted')); |
| 137 | } else if ($role->id == setting('registration-role')) { | 137 | } else if ($role->id == setting('registration-role')) { |
| 138 | - throw new PermissionsException('This role cannot be deleted while set as the default registration role.'); | 138 | + throw new PermissionsException(trans('errors.role_registration_default_cannot_delete')); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | if ($migrateRoleId) { | 141 | if ($migrateRoleId) { | ... | ... |
| ... | @@ -38,7 +38,7 @@ class TagRepo | ... | @@ -38,7 +38,7 @@ class TagRepo |
| 38 | { | 38 | { |
| 39 | $entityInstance = $this->entity->getEntityInstance($entityType); | 39 | $entityInstance = $this->entity->getEntityInstance($entityType); |
| 40 | $searchQuery = $entityInstance->where('id', '=', $entityId)->with('tags'); | 40 | $searchQuery = $entityInstance->where('id', '=', $entityId)->with('tags'); |
| 41 | - $searchQuery = $this->permissionService->enforceEntityRestrictions($searchQuery, $action); | 41 | + $searchQuery = $this->permissionService->enforceEntityRestrictions($entityType, $searchQuery, $action); |
| 42 | return $searchQuery->first(); | 42 | return $searchQuery->first(); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| ... | @@ -121,7 +121,7 @@ class TagRepo | ... | @@ -121,7 +121,7 @@ class TagRepo |
| 121 | /** | 121 | /** |
| 122 | * Create a new Tag instance from user input. | 122 | * Create a new Tag instance from user input. |
| 123 | * @param $input | 123 | * @param $input |
| 124 | - * @return static | 124 | + * @return Tag |
| 125 | */ | 125 | */ |
| 126 | protected function newInstanceFromInput($input) | 126 | protected function newInstanceFromInput($input) |
| 127 | { | 127 | { | ... | ... |
| ... | @@ -3,7 +3,6 @@ | ... | @@ -3,7 +3,6 @@ |
| 3 | use BookStack\Role; | 3 | use BookStack\Role; |
| 4 | use BookStack\User; | 4 | use BookStack\User; |
| 5 | use Exception; | 5 | use Exception; |
| 6 | -use Setting; | ||
| 7 | 6 | ||
| 8 | class UserRepo | 7 | class UserRepo |
| 9 | { | 8 | { |
| ... | @@ -169,13 +168,13 @@ class UserRepo | ... | @@ -169,13 +168,13 @@ class UserRepo |
| 169 | public function getRecentlyCreated(User $user, $count = 20) | 168 | public function getRecentlyCreated(User $user, $count = 20) |
| 170 | { | 169 | { |
| 171 | return [ | 170 | return [ |
| 172 | - 'pages' => $this->entityRepo->getRecentlyCreatedPages($count, 0, function ($query) use ($user) { | 171 | + 'pages' => $this->entityRepo->getRecentlyCreated('page', $count, 0, function ($query) use ($user) { |
| 173 | $query->where('created_by', '=', $user->id); | 172 | $query->where('created_by', '=', $user->id); |
| 174 | }), | 173 | }), |
| 175 | - 'chapters' => $this->entityRepo->getRecentlyCreatedChapters($count, 0, function ($query) use ($user) { | 174 | + 'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, function ($query) use ($user) { |
| 176 | $query->where('created_by', '=', $user->id); | 175 | $query->where('created_by', '=', $user->id); |
| 177 | }), | 176 | }), |
| 178 | - 'books' => $this->entityRepo->getRecentlyCreatedBooks($count, 0, function ($query) use ($user) { | 177 | + 'books' => $this->entityRepo->getRecentlyCreated('book', $count, 0, function ($query) use ($user) { |
| 179 | $query->where('created_by', '=', $user->id); | 178 | $query->where('created_by', '=', $user->id); |
| 180 | }) | 179 | }) |
| 181 | ]; | 180 | ]; | ... | ... |
| ... | @@ -114,7 +114,7 @@ class ActivityService | ... | @@ -114,7 +114,7 @@ class ActivityService |
| 114 | 114 | ||
| 115 | $activity = $this->permissionService | 115 | $activity = $this->permissionService |
| 116 | ->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type') | 116 | ->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type') |
| 117 | - ->orderBy('created_at', 'desc')->skip($count * $page)->take($count)->get(); | 117 | + ->orderBy('created_at', 'desc')->with(['entity', 'user.avatar'])->skip($count * $page)->take($count)->get(); |
| 118 | 118 | ||
| 119 | return $this->filterSimilar($activity); | 119 | return $this->filterSimilar($activity); |
| 120 | } | 120 | } | ... | ... |
| ... | @@ -193,7 +193,7 @@ class AttachmentService extends UploadService | ... | @@ -193,7 +193,7 @@ class AttachmentService extends UploadService |
| 193 | try { | 193 | try { |
| 194 | $storage->put($attachmentStoragePath, $attachmentData); | 194 | $storage->put($attachmentStoragePath, $attachmentData); |
| 195 | } catch (Exception $e) { | 195 | } catch (Exception $e) { |
| 196 | - throw new FileUploadException('File path ' . $attachmentStoragePath . ' could not be uploaded to. Ensure it is writable to the server.'); | 196 | + throw new FileUploadException(trans('errors.path_not_writable', ['filePath' => $attachmentStoragePath])); |
| 197 | } | 197 | } |
| 198 | return $attachmentPath; | 198 | return $attachmentPath; |
| 199 | } | 199 | } | ... | ... |
| ... | @@ -33,7 +33,7 @@ class EmailConfirmationService | ... | @@ -33,7 +33,7 @@ class EmailConfirmationService |
| 33 | public function sendConfirmation(User $user) | 33 | public function sendConfirmation(User $user) |
| 34 | { | 34 | { |
| 35 | if ($user->email_confirmed) { | 35 | if ($user->email_confirmed) { |
| 36 | - throw new ConfirmationEmailException('Email has already been confirmed, Try logging in.', '/login'); | 36 | + throw new ConfirmationEmailException(trans('errors.email_already_confirmed'), '/login'); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | $this->deleteConfirmationsByUser($user); | 39 | $this->deleteConfirmationsByUser($user); |
| ... | @@ -63,7 +63,7 @@ class EmailConfirmationService | ... | @@ -63,7 +63,7 @@ class EmailConfirmationService |
| 63 | * Gets an email confirmation by looking up the token, | 63 | * Gets an email confirmation by looking up the token, |
| 64 | * Ensures the token has not expired. | 64 | * Ensures the token has not expired. |
| 65 | * @param string $token | 65 | * @param string $token |
| 66 | - * @return EmailConfirmation | 66 | + * @return array|null|\stdClass |
| 67 | * @throws UserRegistrationException | 67 | * @throws UserRegistrationException |
| 68 | */ | 68 | */ |
| 69 | public function getEmailConfirmationFromToken($token) | 69 | public function getEmailConfirmationFromToken($token) |
| ... | @@ -72,14 +72,14 @@ class EmailConfirmationService | ... | @@ -72,14 +72,14 @@ class EmailConfirmationService |
| 72 | 72 | ||
| 73 | // If not found show error | 73 | // If not found show error |
| 74 | if ($emailConfirmation === null) { | 74 | if ($emailConfirmation === null) { |
| 75 | - throw new UserRegistrationException('This confirmation token is not valid or has already been used, Please try registering again.', '/register'); | 75 | + throw new UserRegistrationException(trans('errors.email_confirmation_invalid'), '/register'); |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | // If more than a day old | 78 | // If more than a day old |
| 79 | if (Carbon::now()->subDay()->gt(new Carbon($emailConfirmation->created_at))) { | 79 | if (Carbon::now()->subDay()->gt(new Carbon($emailConfirmation->created_at))) { |
| 80 | $user = $this->users->getById($emailConfirmation->user_id); | 80 | $user = $this->users->getById($emailConfirmation->user_id); |
| 81 | $this->sendConfirmation($user); | 81 | $this->sendConfirmation($user); |
| 82 | - throw new UserRegistrationException('The confirmation token has expired, A new confirmation email has been sent.', '/register/confirm'); | 82 | + throw new UserRegistrationException(trans('errors.email_confirmation_expired'), '/register/confirm'); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | $emailConfirmation->user = $this->users->getById($emailConfirmation->user_id); | 85 | $emailConfirmation->user = $this->users->getById($emailConfirmation->user_id); | ... | ... |
| 1 | <?php namespace BookStack\Services; | 1 | <?php namespace BookStack\Services; |
| 2 | 2 | ||
| 3 | - | ||
| 4 | use BookStack\Page; | 3 | use BookStack\Page; |
| 4 | +use BookStack\Repos\EntityRepo; | ||
| 5 | 5 | ||
| 6 | class ExportService | 6 | class ExportService |
| 7 | { | 7 | { |
| 8 | 8 | ||
| 9 | + protected $entityRepo; | ||
| 10 | + | ||
| 11 | + /** | ||
| 12 | + * ExportService constructor. | ||
| 13 | + * @param $entityRepo | ||
| 14 | + */ | ||
| 15 | + public function __construct(EntityRepo $entityRepo) | ||
| 16 | + { | ||
| 17 | + $this->entityRepo = $entityRepo; | ||
| 18 | + } | ||
| 19 | + | ||
| 9 | /** | 20 | /** |
| 10 | * Convert a page to a self-contained HTML file. | 21 | * Convert a page to a self-contained HTML file. |
| 11 | * Includes required CSS & image content. Images are base64 encoded into the HTML. | 22 | * Includes required CSS & image content. Images are base64 encoded into the HTML. |
| ... | @@ -15,7 +26,7 @@ class ExportService | ... | @@ -15,7 +26,7 @@ class ExportService |
| 15 | public function pageToContainedHtml(Page $page) | 26 | public function pageToContainedHtml(Page $page) |
| 16 | { | 27 | { |
| 17 | $cssContent = file_get_contents(public_path('/css/export-styles.css')); | 28 | $cssContent = file_get_contents(public_path('/css/export-styles.css')); |
| 18 | - $pageHtml = view('pages/export', ['page' => $page, 'css' => $cssContent])->render(); | 29 | + $pageHtml = view('pages/export', ['page' => $page, 'pageContent' => $this->entityRepo->renderPage($page), 'css' => $cssContent])->render(); |
| 19 | return $this->containHtml($pageHtml); | 30 | return $this->containHtml($pageHtml); |
| 20 | } | 31 | } |
| 21 | 32 | ||
| ... | @@ -27,9 +38,15 @@ class ExportService | ... | @@ -27,9 +38,15 @@ class ExportService |
| 27 | public function pageToPdf(Page $page) | 38 | public function pageToPdf(Page $page) |
| 28 | { | 39 | { |
| 29 | $cssContent = file_get_contents(public_path('/css/export-styles.css')); | 40 | $cssContent = file_get_contents(public_path('/css/export-styles.css')); |
| 30 | - $pageHtml = view('pages/pdf', ['page' => $page, 'css' => $cssContent])->render(); | 41 | + $pageHtml = view('pages/pdf', ['page' => $page, 'pageContent' => $this->entityRepo->renderPage($page), 'css' => $cssContent])->render(); |
| 42 | +// return $pageHtml; | ||
| 43 | + $useWKHTML = config('snappy.pdf.binary') !== false; | ||
| 31 | $containedHtml = $this->containHtml($pageHtml); | 44 | $containedHtml = $this->containHtml($pageHtml); |
| 32 | - $pdf = \PDF::loadHTML($containedHtml); | 45 | + if ($useWKHTML) { |
| 46 | + $pdf = \SnappyPDF::loadHTML($containedHtml); | ||
| 47 | + } else { | ||
| 48 | + $pdf = \PDF::loadHTML($containedHtml); | ||
| 49 | + } | ||
| 33 | return $pdf->output(); | 50 | return $pdf->output(); |
| 34 | } | 51 | } |
| 35 | 52 | ||
| ... | @@ -55,9 +72,13 @@ class ExportService | ... | @@ -55,9 +72,13 @@ class ExportService |
| 55 | $pathString = $srcString; | 72 | $pathString = $srcString; |
| 56 | } | 73 | } |
| 57 | if ($isLocal && !file_exists($pathString)) continue; | 74 | if ($isLocal && !file_exists($pathString)) continue; |
| 58 | - $imageContent = file_get_contents($pathString); | 75 | + try { |
| 59 | - $imageEncoded = 'data:image/' . pathinfo($pathString, PATHINFO_EXTENSION) . ';base64,' . base64_encode($imageContent); | 76 | + $imageContent = file_get_contents($pathString); |
| 60 | - $newImageString = str_replace($srcString, $imageEncoded, $oldImgString); | 77 | + $imageEncoded = 'data:image/' . pathinfo($pathString, PATHINFO_EXTENSION) . ';base64,' . base64_encode($imageContent); |
| 78 | + $newImageString = str_replace($srcString, $imageEncoded, $oldImgString); | ||
| 79 | + } catch (\ErrorException $e) { | ||
| 80 | + $newImageString = ''; | ||
| 81 | + } | ||
| 61 | $htmlContent = str_replace($oldImgString, $newImageString, $htmlContent); | 82 | $htmlContent = str_replace($oldImgString, $newImageString, $htmlContent); |
| 62 | } | 83 | } |
| 63 | } | 84 | } |
| ... | @@ -84,14 +105,14 @@ class ExportService | ... | @@ -84,14 +105,14 @@ class ExportService |
| 84 | 105 | ||
| 85 | /** | 106 | /** |
| 86 | * Converts the page contents into simple plain text. | 107 | * Converts the page contents into simple plain text. |
| 87 | - * This method filters any bad looking content to | 108 | + * This method filters any bad looking content to provide a nice final output. |
| 88 | - * provide a nice final output. | ||
| 89 | * @param Page $page | 109 | * @param Page $page |
| 90 | * @return mixed | 110 | * @return mixed |
| 91 | */ | 111 | */ |
| 92 | public function pageToPlainText(Page $page) | 112 | public function pageToPlainText(Page $page) |
| 93 | { | 113 | { |
| 94 | - $text = $page->text; | 114 | + $html = $this->entityRepo->renderPage($page); |
| 115 | + $text = strip_tags($html); | ||
| 95 | // Replace multiple spaces with single spaces | 116 | // Replace multiple spaces with single spaces |
| 96 | $text = preg_replace('/\ {2,}/', ' ', $text); | 117 | $text = preg_replace('/\ {2,}/', ' ', $text); |
| 97 | // Reduce multiple horrid whitespace characters. | 118 | // Reduce multiple horrid whitespace characters. | ... | ... |
| ... | @@ -59,7 +59,7 @@ class ImageService extends UploadService | ... | @@ -59,7 +59,7 @@ class ImageService extends UploadService |
| 59 | { | 59 | { |
| 60 | $imageName = $imageName ? $imageName : basename($url); | 60 | $imageName = $imageName ? $imageName : basename($url); |
| 61 | $imageData = file_get_contents($url); | 61 | $imageData = file_get_contents($url); |
| 62 | - if($imageData === false) throw new \Exception('Cannot get image from ' . $url); | 62 | + if($imageData === false) throw new \Exception(trans('errors.cannot_get_image_from_url', ['url' => $url])); |
| 63 | return $this->saveNew($imageName, $imageData, $type); | 63 | return $this->saveNew($imageName, $imageData, $type); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| ... | @@ -93,7 +93,7 @@ class ImageService extends UploadService | ... | @@ -93,7 +93,7 @@ class ImageService extends UploadService |
| 93 | $storage->put($fullPath, $imageData); | 93 | $storage->put($fullPath, $imageData); |
| 94 | $storage->setVisibility($fullPath, 'public'); | 94 | $storage->setVisibility($fullPath, 'public'); |
| 95 | } catch (Exception $e) { | 95 | } catch (Exception $e) { |
| 96 | - throw new ImageUploadException('Image Path ' . $fullPath . ' is not writable by the server.'); | 96 | + throw new ImageUploadException(trans('errors.path_not_writable', ['filePath' => $fullPath])); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | if ($this->isLocal()) $fullPath = str_replace_first('/public', '', $fullPath); | 99 | if ($this->isLocal()) $fullPath = str_replace_first('/public', '', $fullPath); |
| ... | @@ -160,7 +160,7 @@ class ImageService extends UploadService | ... | @@ -160,7 +160,7 @@ class ImageService extends UploadService |
| 160 | $thumb = $this->imageTool->make($storage->get($imagePath)); | 160 | $thumb = $this->imageTool->make($storage->get($imagePath)); |
| 161 | } catch (Exception $e) { | 161 | } catch (Exception $e) { |
| 162 | if ($e instanceof \ErrorException || $e instanceof NotSupportedException) { | 162 | if ($e instanceof \ErrorException || $e instanceof NotSupportedException) { |
| 163 | - throw new ImageUploadException('The server cannot create thumbnails. Please check you have the GD PHP extension installed.'); | 163 | + throw new ImageUploadException(trans('errors.cannot_create_thumbs')); |
| 164 | } else { | 164 | } else { |
| 165 | throw $e; | 165 | throw $e; |
| 166 | } | 166 | } | ... | ... |
| ... | @@ -94,7 +94,7 @@ class LdapService | ... | @@ -94,7 +94,7 @@ class LdapService |
| 94 | $ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass); | 94 | $ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | - if (!$ldapBind) throw new LdapException('LDAP access failed using ' . ($isAnonymous ? ' anonymous bind.' : ' given dn & pass details')); | 97 | + if (!$ldapBind) throw new LdapException(($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed'))); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | /** | 100 | /** |
| ... | @@ -109,15 +109,19 @@ class LdapService | ... | @@ -109,15 +109,19 @@ class LdapService |
| 109 | 109 | ||
| 110 | // Check LDAP extension in installed | 110 | // Check LDAP extension in installed |
| 111 | if (!function_exists('ldap_connect') && config('app.env') !== 'testing') { | 111 | if (!function_exists('ldap_connect') && config('app.env') !== 'testing') { |
| 112 | - throw new LdapException('LDAP PHP extension not installed'); | 112 | + throw new LdapException(trans('errors.ldap_extension_not_installed')); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | - // Get port from server string if specified. | 115 | + // Get port from server string and protocol if specified. |
| 116 | $ldapServer = explode(':', $this->config['server']); | 116 | $ldapServer = explode(':', $this->config['server']); |
| 117 | - $ldapConnection = $this->ldap->connect($ldapServer[0], count($ldapServer) > 1 ? $ldapServer[1] : 389); | 117 | + $hasProtocol = preg_match('/^ldaps{0,1}\:\/\//', $this->config['server']) === 1; |
| 118 | + if (!$hasProtocol) array_unshift($ldapServer, ''); | ||
| 119 | + $hostName = $ldapServer[0] . ($hasProtocol?':':'') . $ldapServer[1]; | ||
| 120 | + $defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389; | ||
| 121 | + $ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort); | ||
| 118 | 122 | ||
| 119 | if ($ldapConnection === false) { | 123 | if ($ldapConnection === false) { |
| 120 | - throw new LdapException('Cannot connect to ldap server, Initial connection failed'); | 124 | + throw new LdapException(trans('errors.ldap_cannot_connect')); |
| 121 | } | 125 | } |
| 122 | 126 | ||
| 123 | // Set any required options | 127 | // Set any required options | ... | ... |
| ... | @@ -8,8 +8,9 @@ use BookStack\Ownable; | ... | @@ -8,8 +8,9 @@ use BookStack\Ownable; |
| 8 | use BookStack\Page; | 8 | use BookStack\Page; |
| 9 | use BookStack\Role; | 9 | use BookStack\Role; |
| 10 | use BookStack\User; | 10 | use BookStack\User; |
| 11 | +use Illuminate\Database\Connection; | ||
| 12 | +use Illuminate\Database\Eloquent\Builder; | ||
| 11 | use Illuminate\Support\Collection; | 13 | use Illuminate\Support\Collection; |
| 12 | -use Illuminate\Support\Facades\Log; | ||
| 13 | 14 | ||
| 14 | class PermissionService | 15 | class PermissionService |
| 15 | { | 16 | { |
| ... | @@ -23,6 +24,8 @@ class PermissionService | ... | @@ -23,6 +24,8 @@ class PermissionService |
| 23 | public $chapter; | 24 | public $chapter; |
| 24 | public $page; | 25 | public $page; |
| 25 | 26 | ||
| 27 | + protected $db; | ||
| 28 | + | ||
| 26 | protected $jointPermission; | 29 | protected $jointPermission; |
| 27 | protected $role; | 30 | protected $role; |
| 28 | 31 | ||
| ... | @@ -31,18 +34,21 @@ class PermissionService | ... | @@ -31,18 +34,21 @@ class PermissionService |
| 31 | /** | 34 | /** |
| 32 | * PermissionService constructor. | 35 | * PermissionService constructor. |
| 33 | * @param JointPermission $jointPermission | 36 | * @param JointPermission $jointPermission |
| 37 | + * @param Connection $db | ||
| 34 | * @param Book $book | 38 | * @param Book $book |
| 35 | * @param Chapter $chapter | 39 | * @param Chapter $chapter |
| 36 | * @param Page $page | 40 | * @param Page $page |
| 37 | * @param Role $role | 41 | * @param Role $role |
| 38 | */ | 42 | */ |
| 39 | - public function __construct(JointPermission $jointPermission, Book $book, Chapter $chapter, Page $page, Role $role) | 43 | + public function __construct(JointPermission $jointPermission, Connection $db, Book $book, Chapter $chapter, Page $page, Role $role) |
| 40 | { | 44 | { |
| 45 | + $this->db = $db; | ||
| 41 | $this->jointPermission = $jointPermission; | 46 | $this->jointPermission = $jointPermission; |
| 42 | $this->role = $role; | 47 | $this->role = $role; |
| 43 | $this->book = $book; | 48 | $this->book = $book; |
| 44 | $this->chapter = $chapter; | 49 | $this->chapter = $chapter; |
| 45 | $this->page = $page; | 50 | $this->page = $page; |
| 51 | + // TODO - Update so admin still goes through filters | ||
| 46 | } | 52 | } |
| 47 | 53 | ||
| 48 | /** | 54 | /** |
| ... | @@ -151,7 +157,7 @@ class PermissionService | ... | @@ -151,7 +157,7 @@ class PermissionService |
| 151 | */ | 157 | */ |
| 152 | public function buildJointPermissionsForEntity(Entity $entity) | 158 | public function buildJointPermissionsForEntity(Entity $entity) |
| 153 | { | 159 | { |
| 154 | - $roles = $this->role->with('jointPermissions')->get(); | 160 | + $roles = $this->role->get(); |
| 155 | $entities = collect([$entity]); | 161 | $entities = collect([$entity]); |
| 156 | 162 | ||
| 157 | if ($entity->isA('book')) { | 163 | if ($entity->isA('book')) { |
| ... | @@ -171,7 +177,7 @@ class PermissionService | ... | @@ -171,7 +177,7 @@ class PermissionService |
| 171 | */ | 177 | */ |
| 172 | public function buildJointPermissionsForEntities(Collection $entities) | 178 | public function buildJointPermissionsForEntities(Collection $entities) |
| 173 | { | 179 | { |
| 174 | - $roles = $this->role->with('jointPermissions')->get(); | 180 | + $roles = $this->role->get(); |
| 175 | $this->deleteManyJointPermissionsForEntities($entities); | 181 | $this->deleteManyJointPermissionsForEntities($entities); |
| 176 | $this->createManyJointPermissions($entities, $roles); | 182 | $this->createManyJointPermissions($entities, $roles); |
| 177 | } | 183 | } |
| ... | @@ -302,6 +308,10 @@ class PermissionService | ... | @@ -302,6 +308,10 @@ class PermissionService |
| 302 | $explodedAction = explode('-', $action); | 308 | $explodedAction = explode('-', $action); |
| 303 | $restrictionAction = end($explodedAction); | 309 | $restrictionAction = end($explodedAction); |
| 304 | 310 | ||
| 311 | + if ($role->system_name === 'admin') { | ||
| 312 | + return $this->createJointPermissionDataArray($entity, $role, $action, true, true); | ||
| 313 | + } | ||
| 314 | + | ||
| 305 | if ($entity->isA('book')) { | 315 | if ($entity->isA('book')) { |
| 306 | 316 | ||
| 307 | if (!$entity->restricted) { | 317 | if (!$entity->restricted) { |
| ... | @@ -395,7 +405,7 @@ class PermissionService | ... | @@ -395,7 +405,7 @@ class PermissionService |
| 395 | $action = end($explodedPermission); | 405 | $action = end($explodedPermission); |
| 396 | $this->currentAction = $action; | 406 | $this->currentAction = $action; |
| 397 | 407 | ||
| 398 | - $nonJointPermissions = ['restrictions']; | 408 | + $nonJointPermissions = ['restrictions', 'image', 'attachment']; |
| 399 | 409 | ||
| 400 | // Handle non entity specific jointPermissions | 410 | // Handle non entity specific jointPermissions |
| 401 | if (in_array($explodedPermission[0], $nonJointPermissions)) { | 411 | if (in_array($explodedPermission[0], $nonJointPermissions)) { |
| ... | @@ -411,7 +421,6 @@ class PermissionService | ... | @@ -411,7 +421,6 @@ class PermissionService |
| 411 | $this->currentAction = $permission; | 421 | $this->currentAction = $permission; |
| 412 | } | 422 | } |
| 413 | 423 | ||
| 414 | - | ||
| 415 | $q = $this->entityRestrictionQuery($baseQuery)->count() > 0; | 424 | $q = $this->entityRestrictionQuery($baseQuery)->count() > 0; |
| 416 | $this->clean(); | 425 | $this->clean(); |
| 417 | return $q; | 426 | return $q; |
| ... | @@ -462,60 +471,67 @@ class PermissionService | ... | @@ -462,60 +471,67 @@ class PermissionService |
| 462 | } | 471 | } |
| 463 | 472 | ||
| 464 | /** | 473 | /** |
| 465 | - * Add restrictions for a page query | 474 | + * Get the children of a book in an efficient single query, Filtered by the permission system. |
| 466 | - * @param $query | 475 | + * @param integer $book_id |
| 467 | - * @param string $action | 476 | + * @param bool $filterDrafts |
| 468 | - * @return mixed | 477 | + * @return \Illuminate\Database\Query\Builder |
| 469 | */ | 478 | */ |
| 470 | - public function enforcePageRestrictions($query, $action = 'view') | 479 | + public function bookChildrenQuery($book_id, $filterDrafts = false) { |
| 471 | - { | 480 | + $pageSelect = $this->db->table('pages')->selectRaw("'BookStack\\\\Page' as entity_type, id, slug, name, text, '' as description, book_id, priority, chapter_id, draft")->where('book_id', '=', $book_id)->where(function($query) use ($filterDrafts) { |
| 472 | - // Prevent drafts being visible to others. | 481 | + $query->where('draft', '=', 0); |
| 473 | - $query = $query->where(function ($query) { | 482 | + if (!$filterDrafts) { |
| 474 | - $query->where('draft', '=', false); | 483 | + $query->orWhere(function($query) { |
| 475 | - if ($this->currentUser()) { | 484 | + $query->where('draft', '=', 1)->where('created_by', '=', $this->currentUser()->id); |
| 476 | - $query->orWhere(function ($query) { | ||
| 477 | - $query->where('draft', '=', true)->where('created_by', '=', $this->currentUser()->id); | ||
| 478 | }); | 485 | }); |
| 479 | } | 486 | } |
| 480 | }); | 487 | }); |
| 488 | + $chapterSelect = $this->db->table('chapters')->selectRaw("'BookStack\\\\Chapter' as entity_type, id, slug, name, '' as text, description, book_id, priority, 0 as chapter_id, 0 as draft")->where('book_id', '=', $book_id); | ||
| 489 | + $query = $this->db->query()->select('*')->from($this->db->raw("({$pageSelect->toSql()} UNION {$chapterSelect->toSql()}) AS U")) | ||
| 490 | + ->mergeBindings($pageSelect)->mergeBindings($chapterSelect); | ||
| 491 | + | ||
| 492 | + if (!$this->isAdmin()) { | ||
| 493 | + $whereQuery = $this->db->table('joint_permissions as jp')->selectRaw('COUNT(*)') | ||
| 494 | + ->whereRaw('jp.entity_id=U.id')->whereRaw('jp.entity_type=U.entity_type') | ||
| 495 | + ->where('jp.action', '=', 'view')->whereIn('jp.role_id', $this->getRoles()) | ||
| 496 | + ->where(function($query) { | ||
| 497 | + $query->where('jp.has_permission', '=', 1)->orWhere(function($query) { | ||
| 498 | + $query->where('jp.has_permission_own', '=', 1)->where('jp.created_by', '=', $this->currentUser()->id); | ||
| 499 | + }); | ||
| 500 | + }); | ||
| 501 | + $query->whereRaw("({$whereQuery->toSql()}) > 0")->mergeBindings($whereQuery); | ||
| 502 | + } | ||
| 481 | 503 | ||
| 482 | - return $this->enforceEntityRestrictions($query, $action); | 504 | + $query->orderBy('draft', 'desc')->orderBy('priority', 'asc'); |
| 483 | - } | 505 | + $this->clean(); |
| 484 | - | 506 | + return $query; |
| 485 | - /** | ||
| 486 | - * Add on permission restrictions to a chapter query. | ||
| 487 | - * @param $query | ||
| 488 | - * @param string $action | ||
| 489 | - * @return mixed | ||
| 490 | - */ | ||
| 491 | - public function enforceChapterRestrictions($query, $action = 'view') | ||
| 492 | - { | ||
| 493 | - return $this->enforceEntityRestrictions($query, $action); | ||
| 494 | - } | ||
| 495 | - | ||
| 496 | - /** | ||
| 497 | - * Add restrictions to a book query. | ||
| 498 | - * @param $query | ||
| 499 | - * @param string $action | ||
| 500 | - * @return mixed | ||
| 501 | - */ | ||
| 502 | - public function enforceBookRestrictions($query, $action = 'view') | ||
| 503 | - { | ||
| 504 | - return $this->enforceEntityRestrictions($query, $action); | ||
| 505 | } | 507 | } |
| 506 | 508 | ||
| 507 | /** | 509 | /** |
| 508 | * Add restrictions for a generic entity | 510 | * Add restrictions for a generic entity |
| 509 | - * @param $query | 511 | + * @param string $entityType |
| 512 | + * @param Builder|Entity $query | ||
| 510 | * @param string $action | 513 | * @param string $action |
| 511 | * @return mixed | 514 | * @return mixed |
| 512 | */ | 515 | */ |
| 513 | - public function enforceEntityRestrictions($query, $action = 'view') | 516 | + public function enforceEntityRestrictions($entityType, $query, $action = 'view') |
| 514 | { | 517 | { |
| 518 | + if (strtolower($entityType) === 'page') { | ||
| 519 | + // Prevent drafts being visible to others. | ||
| 520 | + $query = $query->where(function ($query) { | ||
| 521 | + $query->where('draft', '=', false); | ||
| 522 | + if ($this->currentUser()) { | ||
| 523 | + $query->orWhere(function ($query) { | ||
| 524 | + $query->where('draft', '=', true)->where('created_by', '=', $this->currentUser()->id); | ||
| 525 | + }); | ||
| 526 | + } | ||
| 527 | + }); | ||
| 528 | + } | ||
| 529 | + | ||
| 515 | if ($this->isAdmin()) { | 530 | if ($this->isAdmin()) { |
| 516 | $this->clean(); | 531 | $this->clean(); |
| 517 | return $query; | 532 | return $query; |
| 518 | } | 533 | } |
| 534 | + | ||
| 519 | $this->currentAction = $action; | 535 | $this->currentAction = $action; |
| 520 | return $this->entityRestrictionQuery($query); | 536 | return $this->entityRestrictionQuery($query); |
| 521 | } | 537 | } |
| ... | @@ -553,6 +569,7 @@ class PermissionService | ... | @@ -553,6 +569,7 @@ class PermissionService |
| 553 | }); | 569 | }); |
| 554 | }); | 570 | }); |
| 555 | }); | 571 | }); |
| 572 | + $this->clean(); | ||
| 556 | return $q; | 573 | return $q; |
| 557 | } | 574 | } |
| 558 | 575 | ||
| ... | @@ -601,7 +618,7 @@ class PermissionService | ... | @@ -601,7 +618,7 @@ class PermissionService |
| 601 | private function isAdmin() | 618 | private function isAdmin() |
| 602 | { | 619 | { |
| 603 | if ($this->isAdminUser === null) { | 620 | if ($this->isAdminUser === null) { |
| 604 | - $this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasRole('admin') : false; | 621 | + $this->isAdminUser = ($this->currentUser()->id !== null) ? $this->currentUser()->hasSystemRole('admin') : false; |
| 605 | } | 622 | } |
| 606 | 623 | ||
| 607 | return $this->isAdminUser; | 624 | return $this->isAdminUser; | ... | ... |
| 1 | <?php namespace BookStack\Services; | 1 | <?php namespace BookStack\Services; |
| 2 | 2 | ||
| 3 | use BookStack\Setting; | 3 | use BookStack\Setting; |
| 4 | +use BookStack\User; | ||
| 4 | use Illuminate\Contracts\Cache\Repository as Cache; | 5 | use Illuminate\Contracts\Cache\Repository as Cache; |
| 5 | 6 | ||
| 6 | /** | 7 | /** |
| ... | @@ -38,11 +39,24 @@ class SettingService | ... | @@ -38,11 +39,24 @@ class SettingService |
| 38 | */ | 39 | */ |
| 39 | public function get($key, $default = false) | 40 | public function get($key, $default = false) |
| 40 | { | 41 | { |
| 42 | + if ($default === false) $default = config('setting-defaults.' . $key, false); | ||
| 41 | $value = $this->getValueFromStore($key, $default); | 43 | $value = $this->getValueFromStore($key, $default); |
| 42 | return $this->formatValue($value, $default); | 44 | return $this->formatValue($value, $default); |
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | /** | 47 | /** |
| 48 | + * Get a user-specific setting from the database or cache. | ||
| 49 | + * @param User $user | ||
| 50 | + * @param $key | ||
| 51 | + * @param bool $default | ||
| 52 | + * @return bool|string | ||
| 53 | + */ | ||
| 54 | + public function getUser($user, $key, $default = false) | ||
| 55 | + { | ||
| 56 | + return $this->get($this->userKey($user->id, $key), $default); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 46 | * Gets a setting value from the cache or database. | 60 | * Gets a setting value from the cache or database. |
| 47 | * Looks at the system defaults if not cached or in database. | 61 | * Looks at the system defaults if not cached or in database. |
| 48 | * @param $key | 62 | * @param $key |
| ... | @@ -69,14 +83,6 @@ class SettingService | ... | @@ -69,14 +83,6 @@ class SettingService |
| 69 | return $value; | 83 | return $value; |
| 70 | } | 84 | } |
| 71 | 85 | ||
| 72 | - // Check the defaults set in the app config. | ||
| 73 | - $configPrefix = 'setting-defaults.' . $key; | ||
| 74 | - if (config()->has($configPrefix)) { | ||
| 75 | - $value = config($configPrefix); | ||
| 76 | - $this->cache->forever($cacheKey, $value); | ||
| 77 | - return $value; | ||
| 78 | - } | ||
| 79 | - | ||
| 80 | return $default; | 86 | return $default; |
| 81 | } | 87 | } |
| 82 | 88 | ||
| ... | @@ -119,6 +125,16 @@ class SettingService | ... | @@ -119,6 +125,16 @@ class SettingService |
| 119 | } | 125 | } |
| 120 | 126 | ||
| 121 | /** | 127 | /** |
| 128 | + * Check if a user setting is in the database. | ||
| 129 | + * @param $key | ||
| 130 | + * @return bool | ||
| 131 | + */ | ||
| 132 | + public function hasUser($key) | ||
| 133 | + { | ||
| 134 | + return $this->has($this->userKey($key)); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + /** | ||
| 122 | * Add a setting to the database. | 138 | * Add a setting to the database. |
| 123 | * @param $key | 139 | * @param $key |
| 124 | * @param $value | 140 | * @param $value |
| ... | @@ -136,6 +152,28 @@ class SettingService | ... | @@ -136,6 +152,28 @@ class SettingService |
| 136 | } | 152 | } |
| 137 | 153 | ||
| 138 | /** | 154 | /** |
| 155 | + * Put a user-specific setting into the database. | ||
| 156 | + * @param User $user | ||
| 157 | + * @param $key | ||
| 158 | + * @param $value | ||
| 159 | + * @return bool | ||
| 160 | + */ | ||
| 161 | + public function putUser($user, $key, $value) | ||
| 162 | + { | ||
| 163 | + return $this->put($this->userKey($user->id, $key), $value); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + /** | ||
| 167 | + * Convert a setting key into a user-specific key. | ||
| 168 | + * @param $key | ||
| 169 | + * @return string | ||
| 170 | + */ | ||
| 171 | + protected function userKey($userId, $key = '') | ||
| 172 | + { | ||
| 173 | + return 'user:' . $userId . ':' . $key; | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + /** | ||
| 139 | * Removes a setting from the database. | 177 | * Removes a setting from the database. |
| 140 | * @param $key | 178 | * @param $key |
| 141 | * @return bool | 179 | * @return bool |
| ... | @@ -151,6 +189,16 @@ class SettingService | ... | @@ -151,6 +189,16 @@ class SettingService |
| 151 | } | 189 | } |
| 152 | 190 | ||
| 153 | /** | 191 | /** |
| 192 | + * Delete settings for a given user id. | ||
| 193 | + * @param $userId | ||
| 194 | + * @return mixed | ||
| 195 | + */ | ||
| 196 | + public function deleteUserSettings($userId) | ||
| 197 | + { | ||
| 198 | + return $this->setting->where('setting_key', 'like', $this->userKey($userId) . '%')->delete(); | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + /** | ||
| 154 | * Gets a setting model from the database for the given key. | 202 | * Gets a setting model from the database for the given key. |
| 155 | * @param $key | 203 | * @param $key |
| 156 | * @return mixed | 204 | * @return mixed | ... | ... |
| ... | @@ -70,12 +70,12 @@ class SocialAuthService | ... | @@ -70,12 +70,12 @@ class SocialAuthService |
| 70 | 70 | ||
| 71 | // Check social account has not already been used | 71 | // Check social account has not already been used |
| 72 | if ($this->socialAccount->where('driver_id', '=', $socialUser->getId())->exists()) { | 72 | if ($this->socialAccount->where('driver_id', '=', $socialUser->getId())->exists()) { |
| 73 | - throw new UserRegistrationException('This ' . $socialDriver . ' account is already in use, Try logging in via the ' . $socialDriver . ' option.', '/login'); | 73 | + throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver]), '/login'); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | if ($this->userRepo->getByEmail($socialUser->getEmail())) { | 76 | if ($this->userRepo->getByEmail($socialUser->getEmail())) { |
| 77 | $email = $socialUser->getEmail(); | 77 | $email = $socialUser->getEmail(); |
| 78 | - throw new UserRegistrationException('The email ' . $email . ' is already in use. If you already have an account you can connect your ' . $socialDriver . ' account from your profile settings.', '/login'); | 78 | + throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver, 'email' => $email]), '/login'); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | return $socialUser; | 81 | return $socialUser; |
| ... | @@ -98,7 +98,6 @@ class SocialAuthService | ... | @@ -98,7 +98,6 @@ class SocialAuthService |
| 98 | 98 | ||
| 99 | // Get any attached social accounts or users | 99 | // Get any attached social accounts or users |
| 100 | $socialAccount = $this->socialAccount->where('driver_id', '=', $socialId)->first(); | 100 | $socialAccount = $this->socialAccount->where('driver_id', '=', $socialId)->first(); |
| 101 | - $user = $this->userRepo->getByEmail($socialUser->getEmail()); | ||
| 102 | $isLoggedIn = auth()->check(); | 101 | $isLoggedIn = auth()->check(); |
| 103 | $currentUser = user(); | 102 | $currentUser = user(); |
| 104 | 103 | ||
| ... | @@ -113,27 +112,26 @@ class SocialAuthService | ... | @@ -113,27 +112,26 @@ class SocialAuthService |
| 113 | if ($isLoggedIn && $socialAccount === null) { | 112 | if ($isLoggedIn && $socialAccount === null) { |
| 114 | $this->fillSocialAccount($socialDriver, $socialUser); | 113 | $this->fillSocialAccount($socialDriver, $socialUser); |
| 115 | $currentUser->socialAccounts()->save($this->socialAccount); | 114 | $currentUser->socialAccounts()->save($this->socialAccount); |
| 116 | - session()->flash('success', title_case($socialDriver) . ' account was successfully attached to your profile.'); | 115 | + session()->flash('success', trans('settings.users_social_connected', ['socialAccount' => title_case($socialDriver)])); |
| 117 | return redirect($currentUser->getEditUrl()); | 116 | return redirect($currentUser->getEditUrl()); |
| 118 | } | 117 | } |
| 119 | 118 | ||
| 120 | // When a user is logged in and the social account exists and is already linked to the current user. | 119 | // When a user is logged in and the social account exists and is already linked to the current user. |
| 121 | if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id === $currentUser->id) { | 120 | if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id === $currentUser->id) { |
| 122 | - session()->flash('error', 'This ' . title_case($socialDriver) . ' account is already attached to your profile.'); | 121 | + session()->flash('error', trans('errors.social_account_existing', ['socialAccount' => title_case($socialDriver)])); |
| 123 | return redirect($currentUser->getEditUrl()); | 122 | return redirect($currentUser->getEditUrl()); |
| 124 | } | 123 | } |
| 125 | 124 | ||
| 126 | // When a user is logged in, A social account exists but the users do not match. | 125 | // When a user is logged in, A social account exists but the users do not match. |
| 127 | - // Change the user that the social account is assigned to. | ||
| 128 | if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id != $currentUser->id) { | 126 | if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id != $currentUser->id) { |
| 129 | - session()->flash('success', 'This ' . title_case($socialDriver) . ' account is already used by another user.'); | 127 | + session()->flash('error', trans('errors.social_account_already_used_existing', ['socialAccount' => title_case($socialDriver)])); |
| 130 | return redirect($currentUser->getEditUrl()); | 128 | return redirect($currentUser->getEditUrl()); |
| 131 | } | 129 | } |
| 132 | 130 | ||
| 133 | // Otherwise let the user know this social account is not used by anyone. | 131 | // Otherwise let the user know this social account is not used by anyone. |
| 134 | - $message = 'This ' . $socialDriver . ' account is not linked to any users. Please attach it in your profile settings'; | 132 | + $message = trans('errors.social_account_not_used', ['socialAccount' => title_case($socialDriver)]); |
| 135 | if (setting('registration-enabled')) { | 133 | if (setting('registration-enabled')) { |
| 136 | - $message .= ' or, If you do not yet have an account, You can register an account using the ' . $socialDriver . ' option'; | 134 | + $message .= trans('errors.social_account_register_instructions', ['socialAccount' => title_case($socialDriver)]); |
| 137 | } | 135 | } |
| 138 | 136 | ||
| 139 | throw new SocialSignInException($message . '.', '/login'); | 137 | throw new SocialSignInException($message . '.', '/login'); |
| ... | @@ -157,8 +155,8 @@ class SocialAuthService | ... | @@ -157,8 +155,8 @@ class SocialAuthService |
| 157 | { | 155 | { |
| 158 | $driver = trim(strtolower($socialDriver)); | 156 | $driver = trim(strtolower($socialDriver)); |
| 159 | 157 | ||
| 160 | - if (!in_array($driver, $this->validSocialDrivers)) abort(404, 'Social Driver Not Found'); | 158 | + if (!in_array($driver, $this->validSocialDrivers)) abort(404, trans('errors.social_driver_not_found')); |
| 161 | - if (!$this->checkDriverConfigured($driver)) throw new SocialDriverNotConfigured("Your {$driver} social settings are not configured correctly."); | 159 | + if (!$this->checkDriverConfigured($driver)) throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => title_case($socialDriver)])); |
| 162 | 160 | ||
| 163 | return $driver; | 161 | return $driver; |
| 164 | } | 162 | } |
| ... | @@ -215,7 +213,7 @@ class SocialAuthService | ... | @@ -215,7 +213,7 @@ class SocialAuthService |
| 215 | { | 213 | { |
| 216 | session(); | 214 | session(); |
| 217 | user()->socialAccounts()->where('driver', '=', $socialDriver)->delete(); | 215 | user()->socialAccounts()->where('driver', '=', $socialDriver)->delete(); |
| 218 | - session()->flash('success', title_case($socialDriver) . ' account successfully detached'); | 216 | + session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => title_case($socialDriver)])); |
| 219 | return redirect(user()->getEditUrl()); | 217 | return redirect(user()->getEditUrl()); |
| 220 | } | 218 | } |
| 221 | 219 | ... | ... |
| ... | @@ -5,9 +5,7 @@ use BookStack\View; | ... | @@ -5,9 +5,7 @@ use BookStack\View; |
| 5 | 5 | ||
| 6 | class ViewService | 6 | class ViewService |
| 7 | { | 7 | { |
| 8 | - | ||
| 9 | protected $view; | 8 | protected $view; |
| 10 | - protected $user; | ||
| 11 | protected $permissionService; | 9 | protected $permissionService; |
| 12 | 10 | ||
| 13 | /** | 11 | /** |
| ... | @@ -18,7 +16,6 @@ class ViewService | ... | @@ -18,7 +16,6 @@ class ViewService |
| 18 | public function __construct(View $view, PermissionService $permissionService) | 16 | public function __construct(View $view, PermissionService $permissionService) |
| 19 | { | 17 | { |
| 20 | $this->view = $view; | 18 | $this->view = $view; |
| 21 | - $this->user = user(); | ||
| 22 | $this->permissionService = $permissionService; | 19 | $this->permissionService = $permissionService; |
| 23 | } | 20 | } |
| 24 | 21 | ||
| ... | @@ -29,8 +26,9 @@ class ViewService | ... | @@ -29,8 +26,9 @@ class ViewService |
| 29 | */ | 26 | */ |
| 30 | public function add(Entity $entity) | 27 | public function add(Entity $entity) |
| 31 | { | 28 | { |
| 32 | - if ($this->user === null) return 0; | 29 | + $user = user(); |
| 33 | - $view = $entity->views()->where('user_id', '=', $this->user->id)->first(); | 30 | + if ($user === null || $user->isDefault()) return 0; |
| 31 | + $view = $entity->views()->where('user_id', '=', $user->id)->first(); | ||
| 34 | // Add view if model exists | 32 | // Add view if model exists |
| 35 | if ($view) { | 33 | if ($view) { |
| 36 | $view->increment('views'); | 34 | $view->increment('views'); |
| ... | @@ -39,7 +37,7 @@ class ViewService | ... | @@ -39,7 +37,7 @@ class ViewService |
| 39 | 37 | ||
| 40 | // Otherwise create new view count | 38 | // Otherwise create new view count |
| 41 | $entity->views()->save($this->view->create([ | 39 | $entity->views()->save($this->view->create([ |
| 42 | - 'user_id' => $this->user->id, | 40 | + 'user_id' => $user->id, |
| 43 | 'views' => 1 | 41 | 'views' => 1 |
| 44 | ])); | 42 | ])); |
| 45 | 43 | ||
| ... | @@ -78,13 +76,14 @@ class ViewService | ... | @@ -78,13 +76,14 @@ class ViewService |
| 78 | */ | 76 | */ |
| 79 | public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false) | 77 | public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false) |
| 80 | { | 78 | { |
| 81 | - if ($this->user === null) return collect(); | 79 | + $user = user(); |
| 80 | + if ($user === null || $user->isDefault()) return collect(); | ||
| 82 | 81 | ||
| 83 | $query = $this->permissionService | 82 | $query = $this->permissionService |
| 84 | ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type'); | 83 | ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type'); |
| 85 | 84 | ||
| 86 | if ($filterModel) $query = $query->where('viewable_type', '=', get_class($filterModel)); | 85 | if ($filterModel) $query = $query->where('viewable_type', '=', get_class($filterModel)); |
| 87 | - $query = $query->where('user_id', '=', user()->id); | 86 | + $query = $query->where('user_id', '=', $user->id); |
| 88 | 87 | ||
| 89 | $viewables = $query->with('viewable')->orderBy('updated_at', 'desc') | 88 | $viewables = $query->with('viewable')->orderBy('updated_at', 'desc') |
| 90 | ->skip($count * $page)->take($count)->get()->pluck('viewable'); | 89 | ->skip($count * $page)->take($count)->get()->pluck('viewable'); | ... | ... |
| ... | @@ -75,6 +75,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon | ... | @@ -75,6 +75,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /** | 77 | /** |
| 78 | + * Check if the user has a role. | ||
| 79 | + * @param $role | ||
| 80 | + * @return mixed | ||
| 81 | + */ | ||
| 82 | + public function hasSystemRole($role) | ||
| 83 | + { | ||
| 84 | + return $this->roles->pluck('system_name')->contains('admin'); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 78 | * Get all permissions belonging to a the current user. | 88 | * Get all permissions belonging to a the current user. |
| 79 | * @param bool $cache | 89 | * @param bool $cache |
| 80 | * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough | 90 | * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough |
| ... | @@ -150,8 +160,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon | ... | @@ -150,8 +160,16 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon |
| 150 | */ | 160 | */ |
| 151 | public function getAvatar($size = 50) | 161 | public function getAvatar($size = 50) |
| 152 | { | 162 | { |
| 153 | - if ($this->image_id === 0 || $this->image_id === '0' || $this->image_id === null) return baseUrl('/user_avatar.png'); | 163 | + $default = baseUrl('/user_avatar.png'); |
| 154 | - return baseUrl($this->avatar->getThumb($size, $size, false)); | 164 | + $imageId = $this->image_id; |
| 165 | + if ($imageId === 0 || $imageId === '0' || $imageId === null) return $default; | ||
| 166 | + | ||
| 167 | + try { | ||
| 168 | + $avatar = baseUrl($this->avatar->getThumb($size, $size, false)); | ||
| 169 | + } catch (\Exception $err) { | ||
| 170 | + $avatar = $default; | ||
| 171 | + } | ||
| 172 | + return $avatar; | ||
| 155 | } | 173 | } |
| 156 | 174 | ||
| 157 | /** | 175 | /** | ... | ... |
| ... | @@ -60,11 +60,12 @@ function userCan($permission, Ownable $ownable = null) | ... | @@ -60,11 +60,12 @@ function userCan($permission, Ownable $ownable = null) |
| 60 | * Helper to access system settings. | 60 | * Helper to access system settings. |
| 61 | * @param $key | 61 | * @param $key |
| 62 | * @param bool $default | 62 | * @param bool $default |
| 63 | - * @return mixed | 63 | + * @return bool|string|\BookStack\Services\SettingService |
| 64 | */ | 64 | */ |
| 65 | -function setting($key, $default = false) | 65 | +function setting($key = null, $default = false) |
| 66 | { | 66 | { |
| 67 | $settingService = app(\BookStack\Services\SettingService::class); | 67 | $settingService = app(\BookStack\Services\SettingService::class); |
| 68 | + if (is_null($key)) return $settingService; | ||
| 68 | return $settingService->get($key, $default); | 69 | return $settingService->get($key, $default); |
| 69 | } | 70 | } |
| 70 | 71 | ... | ... |
| ... | @@ -15,7 +15,8 @@ | ... | @@ -15,7 +15,8 @@ |
| 15 | "league/flysystem-aws-s3-v3": "^1.0", | 15 | "league/flysystem-aws-s3-v3": "^1.0", |
| 16 | "barryvdh/laravel-dompdf": "^0.7", | 16 | "barryvdh/laravel-dompdf": "^0.7", |
| 17 | "predis/predis": "^1.1", | 17 | "predis/predis": "^1.1", |
| 18 | - "gathercontent/htmldiff": "^0.2.1" | 18 | + "gathercontent/htmldiff": "^0.2.1", |
| 19 | + "barryvdh/laravel-snappy": "^0.3.1" | ||
| 19 | }, | 20 | }, |
| 20 | "require-dev": { | 21 | "require-dev": { |
| 21 | "fzaninotto/faker": "~1.4", | 22 | "fzaninotto/faker": "~1.4", | ... | ... |
| ... | @@ -4,8 +4,8 @@ | ... | @@ -4,8 +4,8 @@ |
| 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", | 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", |
| 5 | "This file is @generated automatically" | 5 | "This file is @generated automatically" |
| 6 | ], | 6 | ], |
| 7 | - "hash": "3124d900cfe857392a94de479f3ff6d4", | 7 | + "hash": "2438a2f4a02adbea5f378f9e9408eb29", |
| 8 | - "content-hash": "a968767a73f77e66e865c276cf76eedf", | 8 | + "content-hash": "6add8bff71ecc86e0c90858590834a26", |
| 9 | "packages": [ | 9 | "packages": [ |
| 10 | { | 10 | { |
| 11 | "name": "aws/aws-sdk-php", | 11 | "name": "aws/aws-sdk-php", |
| ... | @@ -256,6 +256,58 @@ | ... | @@ -256,6 +256,58 @@ |
| 256 | "time": "2016-07-04 11:52:48" | 256 | "time": "2016-07-04 11:52:48" |
| 257 | }, | 257 | }, |
| 258 | { | 258 | { |
| 259 | + "name": "barryvdh/laravel-snappy", | ||
| 260 | + "version": "v0.3.1", | ||
| 261 | + "source": { | ||
| 262 | + "type": "git", | ||
| 263 | + "url": "https://github.com/barryvdh/laravel-snappy.git", | ||
| 264 | + "reference": "509a4497be63d8ee7ff464a3daf00d9edde08e21" | ||
| 265 | + }, | ||
| 266 | + "dist": { | ||
| 267 | + "type": "zip", | ||
| 268 | + "url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/509a4497be63d8ee7ff464a3daf00d9edde08e21", | ||
| 269 | + "reference": "509a4497be63d8ee7ff464a3daf00d9edde08e21", | ||
| 270 | + "shasum": "" | ||
| 271 | + }, | ||
| 272 | + "require": { | ||
| 273 | + "illuminate/filesystem": "5.0.x|5.1.x|5.2.x|5.3.x", | ||
| 274 | + "illuminate/support": "5.0.x|5.1.x|5.2.x|5.3.x", | ||
| 275 | + "knplabs/knp-snappy": "*", | ||
| 276 | + "php": ">=5.4.0" | ||
| 277 | + }, | ||
| 278 | + "type": "library", | ||
| 279 | + "extra": { | ||
| 280 | + "branch-alias": { | ||
| 281 | + "dev-master": "0.3-dev" | ||
| 282 | + } | ||
| 283 | + }, | ||
| 284 | + "autoload": { | ||
| 285 | + "psr-4": { | ||
| 286 | + "Barryvdh\\Snappy\\": "src/" | ||
| 287 | + } | ||
| 288 | + }, | ||
| 289 | + "notification-url": "https://packagist.org/downloads/", | ||
| 290 | + "license": [ | ||
| 291 | + "MIT" | ||
| 292 | + ], | ||
| 293 | + "authors": [ | ||
| 294 | + { | ||
| 295 | + "name": "Barry vd. Heuvel", | ||
| 296 | + "email": "barryvdh@gmail.com" | ||
| 297 | + } | ||
| 298 | + ], | ||
| 299 | + "description": "Snappy PDF/Image for Laravel 4", | ||
| 300 | + "keywords": [ | ||
| 301 | + "image", | ||
| 302 | + "laravel", | ||
| 303 | + "pdf", | ||
| 304 | + "snappy", | ||
| 305 | + "wkhtmltoimage", | ||
| 306 | + "wkhtmltopdf" | ||
| 307 | + ], | ||
| 308 | + "time": "2016-08-05 13:08:28" | ||
| 309 | + }, | ||
| 310 | + { | ||
| 259 | "name": "barryvdh/reflection-docblock", | 311 | "name": "barryvdh/reflection-docblock", |
| 260 | "version": "v2.0.4", | 312 | "version": "v2.0.4", |
| 261 | "source": { | 313 | "source": { |
| ... | @@ -998,6 +1050,71 @@ | ... | @@ -998,6 +1050,71 @@ |
| 998 | "time": "2015-12-05 17:17:57" | 1050 | "time": "2015-12-05 17:17:57" |
| 999 | }, | 1051 | }, |
| 1000 | { | 1052 | { |
| 1053 | + "name": "knplabs/knp-snappy", | ||
| 1054 | + "version": "0.4.3", | ||
| 1055 | + "source": { | ||
| 1056 | + "type": "git", | ||
| 1057 | + "url": "https://github.com/KnpLabs/snappy.git", | ||
| 1058 | + "reference": "44f7a9b37d5686fd7db4c1e9569a802a5d16923f" | ||
| 1059 | + }, | ||
| 1060 | + "dist": { | ||
| 1061 | + "type": "zip", | ||
| 1062 | + "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/44f7a9b37d5686fd7db4c1e9569a802a5d16923f", | ||
| 1063 | + "reference": "44f7a9b37d5686fd7db4c1e9569a802a5d16923f", | ||
| 1064 | + "shasum": "" | ||
| 1065 | + }, | ||
| 1066 | + "require": { | ||
| 1067 | + "php": ">=5.3.3", | ||
| 1068 | + "symfony/process": "~2.3|~3.0" | ||
| 1069 | + }, | ||
| 1070 | + "require-dev": { | ||
| 1071 | + "phpunit/phpunit": "~4.7" | ||
| 1072 | + }, | ||
| 1073 | + "suggest": { | ||
| 1074 | + "h4cc/wkhtmltoimage-amd64": "Provides wkhtmltoimage-amd64 binary for Linux-compatible machines, use version `~0.12` as dependency", | ||
| 1075 | + "h4cc/wkhtmltoimage-i386": "Provides wkhtmltoimage-i386 binary for Linux-compatible machines, use version `~0.12` as dependency", | ||
| 1076 | + "h4cc/wkhtmltopdf-amd64": "Provides wkhtmltopdf-amd64 binary for Linux-compatible machines, use version `~0.12` as dependency", | ||
| 1077 | + "h4cc/wkhtmltopdf-i386": "Provides wkhtmltopdf-i386 binary for Linux-compatible machines, use version `~0.12` as dependency", | ||
| 1078 | + "wemersonjanuario/wkhtmltopdf-windows": "Provides wkhtmltopdf executable for Windows, use version `~0.12` as dependency" | ||
| 1079 | + }, | ||
| 1080 | + "type": "library", | ||
| 1081 | + "extra": { | ||
| 1082 | + "branch-alias": { | ||
| 1083 | + "dev-master": "0.5.x-dev" | ||
| 1084 | + } | ||
| 1085 | + }, | ||
| 1086 | + "autoload": { | ||
| 1087 | + "psr-0": { | ||
| 1088 | + "Knp\\Snappy": "src/" | ||
| 1089 | + } | ||
| 1090 | + }, | ||
| 1091 | + "notification-url": "https://packagist.org/downloads/", | ||
| 1092 | + "license": [ | ||
| 1093 | + "MIT" | ||
| 1094 | + ], | ||
| 1095 | + "authors": [ | ||
| 1096 | + { | ||
| 1097 | + "name": "KNPLabs Team", | ||
| 1098 | + "homepage": "http://knplabs.com" | ||
| 1099 | + }, | ||
| 1100 | + { | ||
| 1101 | + "name": "Symfony Community", | ||
| 1102 | + "homepage": "http://github.com/KnpLabs/snappy/contributors" | ||
| 1103 | + } | ||
| 1104 | + ], | ||
| 1105 | + "description": "PHP5 library allowing thumbnail, snapshot or PDF generation from a url or a html page. Wrapper for wkhtmltopdf/wkhtmltoimage.", | ||
| 1106 | + "homepage": "http://github.com/KnpLabs/snappy", | ||
| 1107 | + "keywords": [ | ||
| 1108 | + "knp", | ||
| 1109 | + "knplabs", | ||
| 1110 | + "pdf", | ||
| 1111 | + "snapshot", | ||
| 1112 | + "thumbnail", | ||
| 1113 | + "wkhtmltopdf" | ||
| 1114 | + ], | ||
| 1115 | + "time": "2015-11-17 13:16:27" | ||
| 1116 | + }, | ||
| 1117 | + { | ||
| 1001 | "name": "laravel/framework", | 1118 | "name": "laravel/framework", |
| 1002 | "version": "v5.3.11", | 1119 | "version": "v5.3.11", |
| 1003 | "source": { | 1120 | "source": { | ... | ... |
| ... | @@ -148,6 +148,7 @@ return [ | ... | @@ -148,6 +148,7 @@ return [ |
| 148 | Barryvdh\DomPDF\ServiceProvider::class, | 148 | Barryvdh\DomPDF\ServiceProvider::class, |
| 149 | Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, | 149 | Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, |
| 150 | Barryvdh\Debugbar\ServiceProvider::class, | 150 | Barryvdh\Debugbar\ServiceProvider::class, |
| 151 | + Barryvdh\Snappy\ServiceProvider::class, | ||
| 151 | 152 | ||
| 152 | 153 | ||
| 153 | /* | 154 | /* |
| ... | @@ -218,6 +219,7 @@ return [ | ... | @@ -218,6 +219,7 @@ return [ |
| 218 | 219 | ||
| 219 | 'ImageTool' => Intervention\Image\Facades\Image::class, | 220 | 'ImageTool' => Intervention\Image\Facades\Image::class, |
| 220 | 'PDF' => Barryvdh\DomPDF\Facade::class, | 221 | 'PDF' => Barryvdh\DomPDF\Facade::class, |
| 222 | + 'SnappyPDF' => Barryvdh\Snappy\Facades\SnappyPdf::class, | ||
| 221 | 'Debugbar' => Barryvdh\Debugbar\Facade::class, | 223 | 'Debugbar' => Barryvdh\Debugbar\Facade::class, |
| 222 | 224 | ||
| 223 | /** | 225 | /** | ... | ... |
| ... | @@ -6,6 +6,7 @@ | ... | @@ -6,6 +6,7 @@ |
| 6 | return [ | 6 | return [ |
| 7 | 7 | ||
| 8 | 'app-name' => 'BookStack', | 8 | 'app-name' => 'BookStack', |
| 9 | + 'app-logo' => '', | ||
| 9 | 'app-name-header' => true, | 10 | 'app-name-header' => true, |
| 10 | 'app-editor' => 'wysiwyg', | 11 | 'app-editor' => 'wysiwyg', |
| 11 | 'app-color' => '#0288D1', | 12 | 'app-color' => '#0288D1', | ... | ... |
config/snappy.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + 'pdf' => [ | ||
| 5 | + 'enabled' => true, | ||
| 6 | + 'binary' => file_exists(base_path('wkhtmltopdf')) ? base_path('wkhtmltopdf') : env('WKHTMLTOPDF', false), | ||
| 7 | + 'timeout' => false, | ||
| 8 | + 'options' => [], | ||
| 9 | + 'env' => [], | ||
| 10 | + ], | ||
| 11 | + 'image' => [ | ||
| 12 | + 'enabled' => false, | ||
| 13 | + 'binary' => '/usr/local/bin/wkhtmltoimage', | ||
| 14 | + 'timeout' => false, | ||
| 15 | + 'options' => [], | ||
| 16 | + 'env' => [], | ||
| 17 | + ], | ||
| 18 | +]; |
| ... | @@ -59,4 +59,14 @@ $factory->define(BookStack\Tag::class, function ($faker) { | ... | @@ -59,4 +59,14 @@ $factory->define(BookStack\Tag::class, function ($faker) { |
| 59 | 'name' => $faker->city, | 59 | 'name' => $faker->city, |
| 60 | 'value' => $faker->sentence(3) | 60 | 'value' => $faker->sentence(3) |
| 61 | ]; | 61 | ]; |
| 62 | +}); | ||
| 63 | + | ||
| 64 | +$factory->define(BookStack\Image::class, function ($faker) { | ||
| 65 | + return [ | ||
| 66 | + 'name' => $faker->slug . '.jpg', | ||
| 67 | + 'url' => $faker->url, | ||
| 68 | + 'path' => $faker->url, | ||
| 69 | + 'type' => 'gallery', | ||
| 70 | + 'uploaded_to' => 0 | ||
| 71 | + ]; | ||
| 62 | }); | 72 | }); |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +use Illuminate\Support\Facades\Schema; | ||
| 4 | +use Illuminate\Database\Schema\Blueprint; | ||
| 5 | +use Illuminate\Database\Migrations\Migration; | ||
| 6 | + | ||
| 7 | +class CreateCacheTable extends Migration | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * Run the migrations. | ||
| 11 | + * | ||
| 12 | + * @return void | ||
| 13 | + */ | ||
| 14 | + public function up() | ||
| 15 | + { | ||
| 16 | + Schema::create('cache', function (Blueprint $table) { | ||
| 17 | + $table->string('key')->unique(); | ||
| 18 | + $table->text('value'); | ||
| 19 | + $table->integer('expiration'); | ||
| 20 | + }); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * Reverse the migrations. | ||
| 25 | + * | ||
| 26 | + * @return void | ||
| 27 | + */ | ||
| 28 | + public function down() | ||
| 29 | + { | ||
| 30 | + Schema::dropIfExists('cache'); | ||
| 31 | + } | ||
| 32 | +} |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +use Illuminate\Support\Facades\Schema; | ||
| 4 | +use Illuminate\Database\Schema\Blueprint; | ||
| 5 | +use Illuminate\Database\Migrations\Migration; | ||
| 6 | + | ||
| 7 | +class CreateSessionsTable extends Migration | ||
| 8 | +{ | ||
| 9 | + /** | ||
| 10 | + * Run the migrations. | ||
| 11 | + * | ||
| 12 | + * @return void | ||
| 13 | + */ | ||
| 14 | + public function up() | ||
| 15 | + { | ||
| 16 | + Schema::create('sessions', function (Blueprint $table) { | ||
| 17 | + $table->string('id')->unique(); | ||
| 18 | + $table->integer('user_id')->nullable(); | ||
| 19 | + $table->string('ip_address', 45)->nullable(); | ||
| 20 | + $table->text('user_agent')->nullable(); | ||
| 21 | + $table->text('payload'); | ||
| 22 | + $table->integer('last_activity'); | ||
| 23 | + }); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * Reverse the migrations. | ||
| 28 | + * | ||
| 29 | + * @return void | ||
| 30 | + */ | ||
| 31 | + public function down() | ||
| 32 | + { | ||
| 33 | + Schema::dropIfExists('sessions'); | ||
| 34 | + } | ||
| 35 | +} |
| 1 | { | 1 | { |
| 2 | "private": true, | 2 | "private": true, |
| 3 | "scripts": { | 3 | "scripts": { |
| 4 | - "prod": "gulp --production", | 4 | + "build": "gulp --production", |
| 5 | - "dev": "gulp watch" | 5 | + "dev": "gulp watch", |
| 6 | + "watch": "gulp watch" | ||
| 6 | }, | 7 | }, |
| 7 | "devDependencies": { | 8 | "devDependencies": { |
| 8 | "angular": "^1.5.5", | 9 | "angular": "^1.5.5", |
| ... | @@ -15,7 +16,9 @@ | ... | @@ -15,7 +16,9 @@ |
| 15 | "laravel-elixir": "^6.0.0-11", | 16 | "laravel-elixir": "^6.0.0-11", |
| 16 | "laravel-elixir-browserify-official": "^0.1.3", | 17 | "laravel-elixir-browserify-official": "^0.1.3", |
| 17 | "marked": "^0.3.5", | 18 | "marked": "^0.3.5", |
| 18 | - "moment": "^2.12.0", | 19 | + "moment": "^2.12.0" |
| 19 | - "zeroclipboard": "^2.2.0" | 20 | + }, |
| 21 | + "dependencies": { | ||
| 22 | + "clipboard": "^1.5.16" | ||
| 20 | } | 23 | } |
| 21 | } | 24 | } | ... | ... |
| ... | @@ -22,6 +22,7 @@ | ... | @@ -22,6 +22,7 @@ |
| 22 | <php> | 22 | <php> |
| 23 | <env name="APP_ENV" value="testing"/> | 23 | <env name="APP_ENV" value="testing"/> |
| 24 | <env name="APP_DEBUG" value="false"/> | 24 | <env name="APP_DEBUG" value="false"/> |
| 25 | + <env name="APP_LANG" value="en"/> | ||
| 25 | <env name="CACHE_DRIVER" value="array"/> | 26 | <env name="CACHE_DRIVER" value="array"/> |
| 26 | <env name="SESSION_DRIVER" value="array"/> | 27 | <env name="SESSION_DRIVER" value="array"/> |
| 27 | <env name="QUEUE_DRIVER" value="sync"/> | 28 | <env name="QUEUE_DRIVER" value="sync"/> | ... | ... |
public/ZeroClipboard.swf
deleted
100644 → 0
No preview for this file type
| ... | @@ -17,25 +17,42 @@ A platform for storing and organising information and documentation. General inf | ... | @@ -17,25 +17,42 @@ A platform for storing and organising information and documentation. General inf |
| 17 | 17 | ||
| 18 | All development on BookStack is currently done on the master branch. When it's time for a release the master branch is merged into release with built & minified CSS & JS then tagged at it's version. Here are the current development requirements: | 18 | All development on BookStack is currently done on the master branch. When it's time for a release the master branch is merged into release with built & minified CSS & JS then tagged at it's version. Here are the current development requirements: |
| 19 | 19 | ||
| 20 | -* [Node.js](https://nodejs.org/en/) | 20 | +* [Node.js](https://nodejs.org/en/) v6.9+ |
| 21 | -* [Gulp](http://gulpjs.com/) | ||
| 22 | 21 | ||
| 23 | -SASS is used to help the CSS development and the JavaScript is run through browserify/babel to allow for writing ES6 code. Both of these are done using gulp. | 22 | +SASS is used to help the CSS development and the JavaScript is run through browserify/babel to allow for writing ES6 code. Both of these are done using gulp. To run the build task you can use the following commands: |
| 23 | + | ||
| 24 | +``` bash | ||
| 25 | +# Build and minify for production | ||
| 26 | +npm run-script build | ||
| 27 | + | ||
| 28 | +# Build for dev (With sourcemaps) and watch for changes | ||
| 29 | +npm run-script dev | ||
| 30 | +``` | ||
| 24 | 31 | ||
| 25 | BookStack has many integration tests that use Laravel's built-in testing capabilities which makes use of PHPUnit. To use you will need PHPUnit installed and accessible via command line. There is a `mysql_testing` database defined within the app config which is what is used by PHPUnit. This database is set with the following database name, user name and password defined as `bookstack-test`. You will have to create that database and credentials before testing. | 32 | BookStack has many integration tests that use Laravel's built-in testing capabilities which makes use of PHPUnit. To use you will need PHPUnit installed and accessible via command line. There is a `mysql_testing` database defined within the app config which is what is used by PHPUnit. This database is set with the following database name, user name and password defined as `bookstack-test`. You will have to create that database and credentials before testing. |
| 26 | 33 | ||
| 27 | The testing database will also need migrating and seeding beforehand. This can be done with the following commands: | 34 | The testing database will also need migrating and seeding beforehand. This can be done with the following commands: |
| 28 | 35 | ||
| 29 | -``` | 36 | +``` bash |
| 30 | php artisan migrate --database=mysql_testing | 37 | php artisan migrate --database=mysql_testing |
| 31 | php artisan db:seed --class=DummyContentSeeder --database=mysql_testing | 38 | php artisan db:seed --class=DummyContentSeeder --database=mysql_testing |
| 32 | ``` | 39 | ``` |
| 33 | 40 | ||
| 34 | Once done you can run `phpunit` in the application root directory to run all tests. | 41 | Once done you can run `phpunit` in the application root directory to run all tests. |
| 35 | 42 | ||
| 43 | +## Translations | ||
| 44 | + | ||
| 45 | +As part of BookStack v0.14 support for translations has been built in. All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`. | ||
| 46 | + | ||
| 47 | + Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time. | ||
| 48 | + | ||
| 49 | +## Website, Docs & Blog | ||
| 50 | + | ||
| 51 | +The website project docs & Blog can be found in the [BookStackApp/website](https://github.com/BookStackApp/website) repo. | ||
| 52 | + | ||
| 36 | ## License | 53 | ## License |
| 37 | 54 | ||
| 38 | -BookStack is provided under the MIT License. | 55 | +The BookStack source is provided under the MIT License. |
| 39 | 56 | ||
| 40 | ## Attribution | 57 | ## Attribution |
| 41 | 58 | ||
| ... | @@ -53,5 +70,11 @@ These are the great projects used to help build BookStack: | ... | @@ -53,5 +70,11 @@ These are the great projects used to help build BookStack: |
| 53 | * [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html) | 70 | * [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html) |
| 54 | * [Marked](https://github.com/chjj/marked) | 71 | * [Marked](https://github.com/chjj/marked) |
| 55 | * [Moment.js](http://momentjs.com/) | 72 | * [Moment.js](http://momentjs.com/) |
| 73 | +* [BarryVD](https://github.com/barryvdh) | ||
| 74 | + * [Debugbar](https://github.com/barryvdh/laravel-debugbar) | ||
| 75 | + * [Dompdf](https://github.com/barryvdh/laravel-dompdf) | ||
| 76 | + * [Snappy (WKHTML2PDF)](https://github.com/barryvdh/laravel-snappy) | ||
| 77 | + * [Laravel IDE helper](https://github.com/barryvdh/laravel-ide-helper) | ||
| 78 | +* [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html) | ||
| 56 | 79 | ||
| 57 | Additionally, Thank you [BrowserStack](https://www.browserstack.com/) for supporting us and making cross-browser testing easy. | 80 | Additionally, Thank you [BrowserStack](https://www.browserstack.com/) for supporting us and making cross-browser testing easy. | ... | ... |
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
| 1 | "use strict"; | 1 | "use strict"; |
| 2 | 2 | ||
| 3 | // AngularJS - Create application and load components | 3 | // AngularJS - Create application and load components |
| 4 | -var angular = require('angular'); | 4 | +import angular from "angular"; |
| 5 | -var ngResource = require('angular-resource'); | 5 | +import "angular-resource"; |
| 6 | -var ngAnimate = require('angular-animate'); | 6 | +import "angular-animate"; |
| 7 | -var ngSanitize = require('angular-sanitize'); | 7 | +import "angular-sanitize"; |
| 8 | -require('angular-ui-sortable'); | 8 | +import "angular-ui-sortable"; |
| 9 | 9 | ||
| 10 | // Url retrieval function | 10 | // Url retrieval function |
| 11 | window.baseUrl = function(path) { | 11 | window.baseUrl = function(path) { |
| ... | @@ -15,7 +15,13 @@ window.baseUrl = function(path) { | ... | @@ -15,7 +15,13 @@ window.baseUrl = function(path) { |
| 15 | return basePath + '/' + path; | 15 | return basePath + '/' + path; |
| 16 | }; | 16 | }; |
| 17 | 17 | ||
| 18 | -var ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); | 18 | +let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); |
| 19 | + | ||
| 20 | +// Translation setup | ||
| 21 | +// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system | ||
| 22 | +import Translations from "./translations" | ||
| 23 | +let translator = new Translations(window.translations); | ||
| 24 | +window.trans = translator.get.bind(translator); | ||
| 19 | 25 | ||
| 20 | // Global Event System | 26 | // Global Event System |
| 21 | class EventManager { | 27 | class EventManager { |
| ... | @@ -25,9 +31,9 @@ class EventManager { | ... | @@ -25,9 +31,9 @@ class EventManager { |
| 25 | 31 | ||
| 26 | emit(eventName, eventData) { | 32 | emit(eventName, eventData) { |
| 27 | if (typeof this.listeners[eventName] === 'undefined') return this; | 33 | if (typeof this.listeners[eventName] === 'undefined') return this; |
| 28 | - var eventsToStart = this.listeners[eventName]; | 34 | + let eventsToStart = this.listeners[eventName]; |
| 29 | for (let i = 0; i < eventsToStart.length; i++) { | 35 | for (let i = 0; i < eventsToStart.length; i++) { |
| 30 | - var event = eventsToStart[i]; | 36 | + let event = eventsToStart[i]; |
| 31 | event(eventData); | 37 | event(eventData); |
| 32 | } | 38 | } |
| 33 | return this; | 39 | return this; |
| ... | @@ -55,10 +61,9 @@ Controllers(ngApp, window.Events); | ... | @@ -55,10 +61,9 @@ Controllers(ngApp, window.Events); |
| 55 | // Smooth scrolling | 61 | // Smooth scrolling |
| 56 | jQuery.fn.smoothScrollTo = function () { | 62 | jQuery.fn.smoothScrollTo = function () { |
| 57 | if (this.length === 0) return; | 63 | if (this.length === 0) return; |
| 58 | - let scrollElem = document.documentElement.scrollTop === 0 ? document.body : document.documentElement; | 64 | + $('html, body').animate({ |
| 59 | - $(scrollElem).animate({ | ||
| 60 | scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin | 65 | scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin |
| 61 | - }, 800); // Adjust to change animations speed (ms) | 66 | + }, 300); // Adjust to change animations speed (ms) |
| 62 | return this; | 67 | return this; |
| 63 | }; | 68 | }; |
| 64 | 69 | ||
| ... | @@ -70,93 +75,83 @@ jQuery.expr[":"].contains = $.expr.createPseudo(function (arg) { | ... | @@ -70,93 +75,83 @@ jQuery.expr[":"].contains = $.expr.createPseudo(function (arg) { |
| 70 | }); | 75 | }); |
| 71 | 76 | ||
| 72 | // Global jQuery Elements | 77 | // Global jQuery Elements |
| 73 | -$(function () { | 78 | +let notifications = $('.notification'); |
| 74 | - | 79 | +let successNotification = notifications.filter('.pos'); |
| 75 | - var notifications = $('.notification'); | 80 | +let errorNotification = notifications.filter('.neg'); |
| 76 | - var successNotification = notifications.filter('.pos'); | 81 | +let warningNotification = notifications.filter('.warning'); |
| 77 | - var errorNotification = notifications.filter('.neg'); | 82 | +// Notification Events |
| 78 | - var warningNotification = notifications.filter('.warning'); | 83 | +window.Events.listen('success', function (text) { |
| 79 | - // Notification Events | 84 | + successNotification.hide(); |
| 80 | - window.Events.listen('success', function (text) { | 85 | + successNotification.find('span').text(text); |
| 81 | - successNotification.hide(); | 86 | + setTimeout(() => { |
| 82 | - successNotification.find('span').text(text); | 87 | + successNotification.show(); |
| 88 | + }, 1); | ||
| 89 | +}); | ||
| 90 | +window.Events.listen('warning', function (text) { | ||
| 91 | + warningNotification.find('span').text(text); | ||
| 92 | + warningNotification.show(); | ||
| 93 | +}); | ||
| 94 | +window.Events.listen('error', function (text) { | ||
| 95 | + errorNotification.find('span').text(text); | ||
| 96 | + errorNotification.show(); | ||
| 97 | +}); | ||
| 98 | + | ||
| 99 | +// Notification hiding | ||
| 100 | +notifications.click(function () { | ||
| 101 | + $(this).fadeOut(100); | ||
| 102 | +}); | ||
| 103 | + | ||
| 104 | +// Chapter page list toggles | ||
| 105 | +$('.chapter-toggle').click(function (e) { | ||
| 106 | + e.preventDefault(); | ||
| 107 | + $(this).toggleClass('open'); | ||
| 108 | + $(this).closest('.chapter').find('.inset-list').slideToggle(180); | ||
| 109 | +}); | ||
| 110 | + | ||
| 111 | +// Back to top button | ||
| 112 | +$('#back-to-top').click(function() { | ||
| 113 | + $('#header').smoothScrollTo(); | ||
| 114 | +}); | ||
| 115 | +let scrollTopShowing = false; | ||
| 116 | +let scrollTop = document.getElementById('back-to-top'); | ||
| 117 | +let scrollTopBreakpoint = 1200; | ||
| 118 | +window.addEventListener('scroll', function() { | ||
| 119 | + let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0; | ||
| 120 | + if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) { | ||
| 121 | + scrollTop.style.display = 'block'; | ||
| 122 | + scrollTopShowing = true; | ||
| 83 | setTimeout(() => { | 123 | setTimeout(() => { |
| 84 | - successNotification.show(); | 124 | + scrollTop.style.opacity = 0.4; |
| 85 | }, 1); | 125 | }, 1); |
| 86 | - }); | 126 | + } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) { |
| 87 | - window.Events.listen('warning', function (text) { | 127 | + scrollTop.style.opacity = 0; |
| 88 | - warningNotification.find('span').text(text); | 128 | + scrollTopShowing = false; |
| 89 | - warningNotification.show(); | 129 | + setTimeout(() => { |
| 90 | - }); | 130 | + scrollTop.style.display = 'none'; |
| 91 | - window.Events.listen('error', function (text) { | 131 | + }, 500); |
| 92 | - errorNotification.find('span').text(text); | ||
| 93 | - errorNotification.show(); | ||
| 94 | - }); | ||
| 95 | - | ||
| 96 | - // Notification hiding | ||
| 97 | - notifications.click(function () { | ||
| 98 | - $(this).fadeOut(100); | ||
| 99 | - }); | ||
| 100 | - | ||
| 101 | - // Chapter page list toggles | ||
| 102 | - $('.chapter-toggle').click(function (e) { | ||
| 103 | - e.preventDefault(); | ||
| 104 | - $(this).toggleClass('open'); | ||
| 105 | - $(this).closest('.chapter').find('.inset-list').slideToggle(180); | ||
| 106 | - }); | ||
| 107 | - | ||
| 108 | - // Back to top button | ||
| 109 | - $('#back-to-top').click(function() { | ||
| 110 | - $('#header').smoothScrollTo(); | ||
| 111 | - }); | ||
| 112 | - var scrollTopShowing = false; | ||
| 113 | - var scrollTop = document.getElementById('back-to-top'); | ||
| 114 | - var scrollTopBreakpoint = 1200; | ||
| 115 | - window.addEventListener('scroll', function() { | ||
| 116 | - let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0; | ||
| 117 | - if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) { | ||
| 118 | - scrollTop.style.display = 'block'; | ||
| 119 | - scrollTopShowing = true; | ||
| 120 | - setTimeout(() => { | ||
| 121 | - scrollTop.style.opacity = 0.4; | ||
| 122 | - }, 1); | ||
| 123 | - } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) { | ||
| 124 | - scrollTop.style.opacity = 0; | ||
| 125 | - scrollTopShowing = false; | ||
| 126 | - setTimeout(() => { | ||
| 127 | - scrollTop.style.display = 'none'; | ||
| 128 | - }, 500); | ||
| 129 | - } | ||
| 130 | - }); | ||
| 131 | - | ||
| 132 | - // Common jQuery actions | ||
| 133 | - $('[data-action="expand-entity-list-details"]').click(function() { | ||
| 134 | - $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240); | ||
| 135 | - }); | ||
| 136 | - | ||
| 137 | - // Popup close | ||
| 138 | - $('.popup-close').click(function() { | ||
| 139 | - $(this).closest('.overlay').fadeOut(240); | ||
| 140 | - }); | ||
| 141 | - $('.overlay').click(function(event) { | ||
| 142 | - if (!$(event.target).hasClass('overlay')) return; | ||
| 143 | - $(this).fadeOut(240); | ||
| 144 | - }); | ||
| 145 | - | ||
| 146 | - // Prevent markdown display link click redirect | ||
| 147 | - $('.markdown-display').on('click', 'a', function(event) { | ||
| 148 | - event.preventDefault(); | ||
| 149 | - window.open($(this).attr('href')); | ||
| 150 | - }); | ||
| 151 | - | ||
| 152 | - // Detect IE for css | ||
| 153 | - if(navigator.userAgent.indexOf('MSIE')!==-1 | ||
| 154 | - || navigator.appVersion.indexOf('Trident/') > 0 | ||
| 155 | - || navigator.userAgent.indexOf('Safari') !== -1){ | ||
| 156 | - $('body').addClass('flexbox-support'); | ||
| 157 | } | 132 | } |
| 133 | +}); | ||
| 158 | 134 | ||
| 135 | +// Common jQuery actions | ||
| 136 | +$('[data-action="expand-entity-list-details"]').click(function() { | ||
| 137 | + $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240); | ||
| 159 | }); | 138 | }); |
| 160 | 139 | ||
| 140 | +// Popup close | ||
| 141 | +$('.popup-close').click(function() { | ||
| 142 | + $(this).closest('.overlay').fadeOut(240); | ||
| 143 | +}); | ||
| 144 | +$('.overlay').click(function(event) { | ||
| 145 | + if (!$(event.target).hasClass('overlay')) return; | ||
| 146 | + $(this).fadeOut(240); | ||
| 147 | +}); | ||
| 148 | + | ||
| 149 | +// Detect IE for css | ||
| 150 | +if(navigator.userAgent.indexOf('MSIE')!==-1 | ||
| 151 | + || navigator.appVersion.indexOf('Trident/') > 0 | ||
| 152 | + || navigator.userAgent.indexOf('Safari') !== -1){ | ||
| 153 | + $('body').addClass('flexbox-support'); | ||
| 154 | +} | ||
| 155 | + | ||
| 161 | // Page specific items | 156 | // Page specific items |
| 162 | -require('./pages/page-show'); | 157 | +import "./pages/page-show"; | ... | ... |
This diff is collapsed.
Click to expand it.
| 1 | "use strict"; | 1 | "use strict"; |
| 2 | // Configure ZeroClipboard | 2 | // Configure ZeroClipboard |
| 3 | -var zeroClipBoard = require('zeroclipboard'); | 3 | +import Clipboard from "clipboard"; |
| 4 | -zeroClipBoard.config({ | ||
| 5 | - swfPath: window.baseUrl('/ZeroClipboard.swf') | ||
| 6 | -}); | ||
| 7 | 4 | ||
| 8 | -window.setupPageShow = module.exports = function (pageId) { | 5 | +export default window.setupPageShow = function (pageId) { |
| 9 | 6 | ||
| 10 | // Set up pointer | 7 | // Set up pointer |
| 11 | - var $pointer = $('#pointer').detach(); | 8 | + let $pointer = $('#pointer').detach(); |
| 12 | - var $pointerInner = $pointer.children('div.pointer').first(); | 9 | + let pointerShowing = false; |
| 13 | - var isSelection = false; | 10 | + let $pointerInner = $pointer.children('div.pointer').first(); |
| 11 | + let isSelection = false; | ||
| 12 | + let pointerModeLink = true; | ||
| 13 | + let pointerSectionId = ''; | ||
| 14 | 14 | ||
| 15 | // Select all contents on input click | 15 | // Select all contents on input click |
| 16 | $pointer.on('click', 'input', function (e) { | 16 | $pointer.on('click', 'input', function (e) { |
| ... | @@ -18,35 +18,53 @@ window.setupPageShow = module.exports = function (pageId) { | ... | @@ -18,35 +18,53 @@ window.setupPageShow = module.exports = function (pageId) { |
| 18 | e.stopPropagation(); | 18 | e.stopPropagation(); |
| 19 | }); | 19 | }); |
| 20 | 20 | ||
| 21 | - // Set up copy-to-clipboard | 21 | + // Pointer mode toggle |
| 22 | - new zeroClipBoard($pointer.find('button').first()[0]); | 22 | + $pointer.on('click', 'span.icon', event => { |
| 23 | + let $icon = $(event.currentTarget); | ||
| 24 | + pointerModeLink = !pointerModeLink; | ||
| 25 | + $icon.html(pointerModeLink ? '<i class="zmdi zmdi-link"></i>' : '<i class="zmdi zmdi-square-down"></i>'); | ||
| 26 | + updatePointerContent(); | ||
| 27 | + }); | ||
| 28 | + | ||
| 29 | + // Set up clipboard | ||
| 30 | + let clipboard = new Clipboard('#pointer button'); | ||
| 23 | 31 | ||
| 24 | // Hide pointer when clicking away | 32 | // Hide pointer when clicking away |
| 25 | - $(document.body).find('*').on('click focus', function (e) { | 33 | + $(document.body).find('*').on('click focus', event => { |
| 26 | - if (!isSelection) { | 34 | + if (!pointerShowing || isSelection) return; |
| 27 | - $pointer.detach(); | 35 | + let target = $(event.target); |
| 28 | - } | 36 | + if (target.is('.zmdi') || $(event.target).closest('#pointer').length === 1) return; |
| 37 | + | ||
| 38 | + $pointer.detach(); | ||
| 39 | + pointerShowing = false; | ||
| 29 | }); | 40 | }); |
| 30 | 41 | ||
| 42 | + function updatePointerContent() { | ||
| 43 | + let inputText = pointerModeLink ? window.baseUrl(`/link/${pageId}#${pointerSectionId}`) : `{{@${pageId}#${pointerSectionId}}}`; | ||
| 44 | + if (pointerModeLink && inputText.indexOf('http') !== 0) inputText = window.location.protocol + "//" + window.location.host + inputText; | ||
| 45 | + | ||
| 46 | + $pointer.find('input').val(inputText); | ||
| 47 | + } | ||
| 48 | + | ||
| 31 | // Show pointer when selecting a single block of tagged content | 49 | // Show pointer when selecting a single block of tagged content |
| 32 | $('.page-content [id^="bkmrk"]').on('mouseup keyup', function (e) { | 50 | $('.page-content [id^="bkmrk"]').on('mouseup keyup', function (e) { |
| 33 | e.stopPropagation(); | 51 | e.stopPropagation(); |
| 34 | - var selection = window.getSelection(); | 52 | + let selection = window.getSelection(); |
| 35 | if (selection.toString().length === 0) return; | 53 | if (selection.toString().length === 0) return; |
| 36 | 54 | ||
| 37 | // Show pointer and set link | 55 | // Show pointer and set link |
| 38 | - var $elem = $(this); | 56 | + let $elem = $(this); |
| 39 | - let link = window.baseUrl('/link/' + pageId + '#' + $elem.attr('id')); | 57 | + pointerSectionId = $elem.attr('id'); |
| 40 | - if (link.indexOf('http') !== 0) link = window.location.protocol + "//" + window.location.host + link; | 58 | + updatePointerContent(); |
| 41 | - $pointer.find('input').val(link); | 59 | + |
| 42 | - $pointer.find('button').first().attr('data-clipboard-text', link); | ||
| 43 | $elem.before($pointer); | 60 | $elem.before($pointer); |
| 44 | $pointer.show(); | 61 | $pointer.show(); |
| 62 | + pointerShowing = true; | ||
| 45 | 63 | ||
| 46 | // Set pointer to sit near mouse-up position | 64 | // Set pointer to sit near mouse-up position |
| 47 | - var pointerLeftOffset = (e.pageX - $elem.offset().left - ($pointerInner.width() / 2)); | 65 | + let pointerLeftOffset = (e.pageX - $elem.offset().left - ($pointerInner.width() / 2)); |
| 48 | if (pointerLeftOffset < 0) pointerLeftOffset = 0; | 66 | if (pointerLeftOffset < 0) pointerLeftOffset = 0; |
| 49 | - var pointerLeftOffsetPercent = (pointerLeftOffset / $elem.width()) * 100; | 67 | + let pointerLeftOffsetPercent = (pointerLeftOffset / $elem.width()) * 100; |
| 50 | $pointerInner.css('left', pointerLeftOffsetPercent + '%'); | 68 | $pointerInner.css('left', pointerLeftOffsetPercent + '%'); |
| 51 | 69 | ||
| 52 | isSelection = true; | 70 | isSelection = true; |
| ... | @@ -57,10 +75,12 @@ window.setupPageShow = module.exports = function (pageId) { | ... | @@ -57,10 +75,12 @@ window.setupPageShow = module.exports = function (pageId) { |
| 57 | 75 | ||
| 58 | // Go to, and highlight if necessary, the specified text. | 76 | // Go to, and highlight if necessary, the specified text. |
| 59 | function goToText(text) { | 77 | function goToText(text) { |
| 60 | - var idElem = $('.page-content #' + text).first(); | 78 | + let idElem = document.getElementById(text); |
| 61 | - if (idElem.length !== 0) { | 79 | + $('.page-content [data-highlighted]').attr('data-highlighted', '').css('background-color', ''); |
| 62 | - idElem.smoothScrollTo(); | 80 | + if (idElem !== null) { |
| 63 | - idElem.css('background-color', 'rgba(244, 249, 54, 0.25)'); | 81 | + let $idElem = $(idElem); |
| 82 | + let color = $('#custom-styles').attr('data-color-light'); | ||
| 83 | + $idElem.css('background-color', color).attr('data-highlighted', 'true').smoothScrollTo(); | ||
| 64 | } else { | 84 | } else { |
| 65 | $('.page-content').find(':contains("' + text + '")').smoothScrollTo(); | 85 | $('.page-content').find(':contains("' + text + '")').smoothScrollTo(); |
| 66 | } | 86 | } |
| ... | @@ -68,19 +88,24 @@ window.setupPageShow = module.exports = function (pageId) { | ... | @@ -68,19 +88,24 @@ window.setupPageShow = module.exports = function (pageId) { |
| 68 | 88 | ||
| 69 | // Check the hash on load | 89 | // Check the hash on load |
| 70 | if (window.location.hash) { | 90 | if (window.location.hash) { |
| 71 | - var text = window.location.hash.replace(/\%20/g, ' ').substr(1); | 91 | + let text = window.location.hash.replace(/\%20/g, ' ').substr(1); |
| 72 | goToText(text); | 92 | goToText(text); |
| 73 | } | 93 | } |
| 74 | 94 | ||
| 95 | + // Sidebar page nav click event | ||
| 96 | + $('.sidebar-page-nav').on('click', 'a', event => { | ||
| 97 | + goToText(event.target.getAttribute('href').substr(1)); | ||
| 98 | + }); | ||
| 99 | + | ||
| 75 | // Make the book-tree sidebar stick in view on scroll | 100 | // Make the book-tree sidebar stick in view on scroll |
| 76 | - var $window = $(window); | 101 | + let $window = $(window); |
| 77 | - var $bookTree = $(".book-tree"); | 102 | + let $bookTree = $(".book-tree"); |
| 78 | - var $bookTreeParent = $bookTree.parent(); | 103 | + let $bookTreeParent = $bookTree.parent(); |
| 79 | // Check the page is scrollable and the content is taller than the tree | 104 | // Check the page is scrollable and the content is taller than the tree |
| 80 | - var pageScrollable = ($(document).height() > $window.height()) && ($bookTree.height() < $('.page-content').height()); | 105 | + let pageScrollable = ($(document).height() > $window.height()) && ($bookTree.height() < $('.page-content').height()); |
| 81 | // Get current tree's width and header height | 106 | // Get current tree's width and header height |
| 82 | - var headerHeight = $("#header").height() + $(".toolbar").height(); | 107 | + let headerHeight = $("#header").height() + $(".toolbar").height(); |
| 83 | - var isFixed = $window.scrollTop() > headerHeight; | 108 | + let isFixed = $window.scrollTop() > headerHeight; |
| 84 | // Function to fix the tree as a sidebar | 109 | // Function to fix the tree as a sidebar |
| 85 | function stickTree() { | 110 | function stickTree() { |
| 86 | $bookTree.width($bookTreeParent.width() + 15); | 111 | $bookTree.width($bookTreeParent.width() + 15); |
| ... | @@ -95,7 +120,7 @@ window.setupPageShow = module.exports = function (pageId) { | ... | @@ -95,7 +120,7 @@ window.setupPageShow = module.exports = function (pageId) { |
| 95 | } | 120 | } |
| 96 | // Checks if the tree stickiness state should change | 121 | // Checks if the tree stickiness state should change |
| 97 | function checkTreeStickiness(skipCheck) { | 122 | function checkTreeStickiness(skipCheck) { |
| 98 | - var shouldBeFixed = $window.scrollTop() > headerHeight; | 123 | + let shouldBeFixed = $window.scrollTop() > headerHeight; |
| 99 | if (shouldBeFixed && (!isFixed || skipCheck)) { | 124 | if (shouldBeFixed && (!isFixed || skipCheck)) { |
| 100 | stickTree(); | 125 | stickTree(); |
| 101 | } else if (!shouldBeFixed && (isFixed || skipCheck)) { | 126 | } else if (!shouldBeFixed && (isFixed || skipCheck)) { | ... | ... |
resources/assets/js/translations.js
0 → 100644
| 1 | +/** | ||
| 2 | + * Translation Manager | ||
| 3 | + * Handles the JavaScript side of translating strings | ||
| 4 | + * in a way which fits with Laravel. | ||
| 5 | + */ | ||
| 6 | +class Translator { | ||
| 7 | + | ||
| 8 | + /** | ||
| 9 | + * Create an instance, Passing in the required translations | ||
| 10 | + * @param translations | ||
| 11 | + */ | ||
| 12 | + constructor(translations) { | ||
| 13 | + this.store = translations; | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * Get a translation, Same format as laravel's 'trans' helper | ||
| 18 | + * @param key | ||
| 19 | + * @param replacements | ||
| 20 | + * @returns {*} | ||
| 21 | + */ | ||
| 22 | + get(key, replacements) { | ||
| 23 | + let splitKey = key.split('.'); | ||
| 24 | + let value = splitKey.reduce((a, b) => { | ||
| 25 | + return a != undefined ? a[b] : a; | ||
| 26 | + }, this.store); | ||
| 27 | + | ||
| 28 | + if (value === undefined) { | ||
| 29 | + console.log(`Translation with key "${key}" does not exist`); | ||
| 30 | + value = key; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + if (replacements === undefined) return value; | ||
| 34 | + | ||
| 35 | + let replaceMatches = value.match(/:([\S]+)/g); | ||
| 36 | + if (replaceMatches === null) return value; | ||
| 37 | + replaceMatches.forEach(match => { | ||
| 38 | + let key = match.substring(1); | ||
| 39 | + if (typeof replacements[key] === 'undefined') return; | ||
| 40 | + value = value.replace(match, replacements[key]); | ||
| 41 | + }); | ||
| 42 | + return value; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +export default Translator |
| ... | @@ -136,9 +136,6 @@ | ... | @@ -136,9 +136,6 @@ |
| 136 | background-color: #EEE; | 136 | background-color: #EEE; |
| 137 | padding: $-s; | 137 | padding: $-s; |
| 138 | display: block; | 138 | display: block; |
| 139 | - > * { | ||
| 140 | - display: inline-block; | ||
| 141 | - } | ||
| 142 | &:before { | 139 | &:before { |
| 143 | font-family: 'Material-Design-Iconic-Font'; | 140 | font-family: 'Material-Design-Iconic-Font'; |
| 144 | padding-right: $-s; | 141 | padding-right: $-s; | ... | ... |
| ... | @@ -70,9 +70,6 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { | ... | @@ -70,9 +70,6 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { |
| 70 | #entity-selector-wrap .popup-body .form-group { | 70 | #entity-selector-wrap .popup-body .form-group { |
| 71 | margin: 0; | 71 | margin: 0; |
| 72 | } | 72 | } |
| 73 | -//body.ie #entity-selector-wrap .popup-body .form-group { | ||
| 74 | -// min-height: 60vh; | ||
| 75 | -//} | ||
| 76 | 73 | ||
| 77 | .image-manager-body { | 74 | .image-manager-body { |
| 78 | min-height: 70vh; | 75 | min-height: 70vh; |
| ... | @@ -465,4 +462,8 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { | ... | @@ -465,4 +462,8 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { |
| 465 | border-bottom-width: 3px; | 462 | border-bottom-width: 3px; |
| 466 | } | 463 | } |
| 467 | } | 464 | } |
| 465 | +} | ||
| 466 | + | ||
| 467 | +.image-picker .none { | ||
| 468 | + display: none; | ||
| 468 | } | 469 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -33,7 +33,7 @@ | ... | @@ -33,7 +33,7 @@ |
| 33 | position: relative; | 33 | position: relative; |
| 34 | z-index: 5; | 34 | z-index: 5; |
| 35 | textarea { | 35 | textarea { |
| 36 | - font-family: 'Roboto Mono'; | 36 | + font-family: 'Roboto Mono', monospace; |
| 37 | font-style: normal; | 37 | font-style: normal; |
| 38 | font-weight: 400; | 38 | font-weight: 400; |
| 39 | padding: $-xs $-m; | 39 | padding: $-xs $-m; |
| ... | @@ -55,6 +55,7 @@ | ... | @@ -55,6 +55,7 @@ |
| 55 | display: flex; | 55 | display: flex; |
| 56 | flex-direction: column; | 56 | flex-direction: column; |
| 57 | border: 1px solid #DDD; | 57 | border: 1px solid #DDD; |
| 58 | + width: 50%; | ||
| 58 | } | 59 | } |
| 59 | .markdown-display { | 60 | .markdown-display { |
| 60 | padding: 0 $-m 0; | 61 | padding: 0 $-m 0; |
| ... | @@ -68,7 +69,7 @@ | ... | @@ -68,7 +69,7 @@ |
| 68 | .editor-toolbar { | 69 | .editor-toolbar { |
| 69 | width: 100%; | 70 | width: 100%; |
| 70 | padding: $-xs $-m; | 71 | padding: $-xs $-m; |
| 71 | - font-family: 'Roboto Mono'; | 72 | + font-family: 'Roboto Mono', monospace; |
| 72 | font-size: 11px; | 73 | font-size: 11px; |
| 73 | line-height: 1.6; | 74 | line-height: 1.6; |
| 74 | border-bottom: 1px solid #DDD; | 75 | border-bottom: 1px solid #DDD; |
| ... | @@ -267,9 +268,4 @@ input.outline { | ... | @@ -267,9 +268,4 @@ input.outline { |
| 267 | 268 | ||
| 268 | .image-picker img { | 269 | .image-picker img { |
| 269 | background-color: #BBB; | 270 | background-color: #BBB; |
| 270 | -} | ||
| 271 | - | ||
| 272 | -div[toggle-switch] { | ||
| 273 | - height: 18px; | ||
| 274 | - width: 150px; | ||
| 275 | } | 271 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -322,6 +322,9 @@ ul.pagination { | ... | @@ -322,6 +322,9 @@ ul.pagination { |
| 322 | font-size: 0.75em; | 322 | font-size: 0.75em; |
| 323 | margin-top: $-xs; | 323 | margin-top: $-xs; |
| 324 | } | 324 | } |
| 325 | + .text-muted p.text-muted { | ||
| 326 | + margin-top: 0; | ||
| 327 | + } | ||
| 325 | .page.draft .text-page { | 328 | .page.draft .text-page { |
| 326 | color: $color-page-draft; | 329 | color: $color-page-draft; |
| 327 | } | 330 | } | ... | ... |
| ... | @@ -138,6 +138,10 @@ | ... | @@ -138,6 +138,10 @@ |
| 138 | font-size: 18px; | 138 | font-size: 18px; |
| 139 | padding-top: 4px; | 139 | padding-top: 4px; |
| 140 | } | 140 | } |
| 141 | + span.icon { | ||
| 142 | + cursor: pointer; | ||
| 143 | + user-select: none; | ||
| 144 | + } | ||
| 141 | .button { | 145 | .button { |
| 142 | line-height: 1; | 146 | line-height: 1; |
| 143 | margin: 0 0 0 -4px; | 147 | margin: 0 0 0 -4px; | ... | ... |
| ... | @@ -35,6 +35,12 @@ table.table { | ... | @@ -35,6 +35,12 @@ table.table { |
| 35 | tr:hover { | 35 | tr:hover { |
| 36 | background-color: #EEE; | 36 | background-color: #EEE; |
| 37 | } | 37 | } |
| 38 | + .text-right { | ||
| 39 | + text-align: right; | ||
| 40 | + } | ||
| 41 | + .text-center { | ||
| 42 | + text-align: center; | ||
| 43 | + } | ||
| 38 | } | 44 | } |
| 39 | 45 | ||
| 40 | table.no-style { | 46 | table.no-style { | ... | ... |
| ... | @@ -109,6 +109,9 @@ em, i, .italic { | ... | @@ -109,6 +109,9 @@ em, i, .italic { |
| 109 | small, p.small, span.small, .text-small { | 109 | small, p.small, span.small, .text-small { |
| 110 | font-size: 0.8em; | 110 | font-size: 0.8em; |
| 111 | color: lighten($text-dark, 20%); | 111 | color: lighten($text-dark, 20%); |
| 112 | + small, p.small, span.small, .text-small { | ||
| 113 | + font-size: 1em; | ||
| 114 | + } | ||
| 112 | } | 115 | } |
| 113 | 116 | ||
| 114 | sup, .superscript { | 117 | sup, .superscript { |
| ... | @@ -172,6 +175,7 @@ pre code { | ... | @@ -172,6 +175,7 @@ pre code { |
| 172 | background-color: transparent; | 175 | background-color: transparent; |
| 173 | border: 0; | 176 | border: 0; |
| 174 | font-size: 1em; | 177 | font-size: 1em; |
| 178 | + display: block; | ||
| 175 | } | 179 | } |
| 176 | /* | 180 | /* |
| 177 | * Text colors | 181 | * Text colors | ... | ... |
| ... | @@ -16,7 +16,7 @@ return [ | ... | @@ -16,7 +16,7 @@ return [ |
| 16 | 'app_name_desc' => 'Dieser Name wird im Header und E-Mails angezeigt.', | 16 | 'app_name_desc' => 'Dieser Name wird im Header und E-Mails angezeigt.', |
| 17 | 'app_name_header' => 'Anwendungsname im Header anzeigen?', | 17 | 'app_name_header' => 'Anwendungsname im Header anzeigen?', |
| 18 | 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', | 18 | 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', |
| 19 | - 'app_secure_images' => 'Erh&oml;hte Sicherheit für Bilduploads aktivieren?', | 19 | + 'app_secure_images' => 'Erhöhte Sicherheit für Bilduploads aktivieren?', |
| 20 | 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten vor die Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnindexes deaktiviert sind, um einen einfachen Zugrif zu verhindern.', | 20 | 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten vor die Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnindexes deaktiviert sind, um einen einfachen Zugrif zu verhindern.', |
| 21 | 'app_editor' => 'Seiteneditor', | 21 | 'app_editor' => 'Seiteneditor', |
| 22 | 'app_editor_desc' => 'Wählen sie den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.', | 22 | 'app_editor_desc' => 'Wählen sie den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.', | ... | ... |
| ... | @@ -14,7 +14,49 @@ return [ | ... | @@ -14,7 +14,49 @@ return [ |
| 14 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', | 14 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', |
| 15 | 15 | ||
| 16 | /** | 16 | /** |
| 17 | - * Email Confirmation Text | 17 | + * Login & Register |
| 18 | + */ | ||
| 19 | + 'sign_up' => 'Sign up', | ||
| 20 | + 'log_in' => 'Log in', | ||
| 21 | + 'logout' => 'Logout', | ||
| 22 | + | ||
| 23 | + 'name' => 'Name', | ||
| 24 | + 'username' => 'Username', | ||
| 25 | + 'email' => 'Email', | ||
| 26 | + 'password' => 'Password', | ||
| 27 | + 'password_confirm' => 'Confirm Password', | ||
| 28 | + 'password_hint' => 'Must be over 5 characters', | ||
| 29 | + 'forgot_password' => 'Forgot Password?', | ||
| 30 | + 'remember_me' => 'Remember Me', | ||
| 31 | + 'ldap_email_hint' => 'Please enter an email to use for this account.', | ||
| 32 | + 'create_account' => 'Create Account', | ||
| 33 | + 'social_login' => 'Social Login', | ||
| 34 | + 'social_registration' => 'Social Registration', | ||
| 35 | + 'social_registration_text' => 'Register and sign in using another service.', | ||
| 36 | + | ||
| 37 | + 'register_thanks' => 'Thanks for registering!', | ||
| 38 | + 'register_confirm' => 'Please check your email and click the confirmation button to access :appName.', | ||
| 39 | + 'registrations_disabled' => 'Registrations are currently disabled', | ||
| 40 | + 'registration_email_domain_invalid' => 'That email domain does not have access to this application', | ||
| 41 | + 'register_success' => 'Thanks for signing up! You are now registered and signed in.', | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * Password Reset | ||
| 46 | + */ | ||
| 47 | + 'reset_password' => 'Reset Password', | ||
| 48 | + 'reset_password_send_instructions' => 'Enter your email below and you will be sent an email with a password reset link.', | ||
| 49 | + 'reset_password_send_button' => 'Send Reset Link', | ||
| 50 | + 'reset_password_sent_success' => 'A password reset link has been sent to :email.', | ||
| 51 | + 'reset_password_success' => 'Your password has been successfully reset.', | ||
| 52 | + | ||
| 53 | + 'email_reset_subject' => 'Reset your :appName password', | ||
| 54 | + 'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.', | ||
| 55 | + 'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.', | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * Email Confirmation | ||
| 18 | */ | 60 | */ |
| 19 | 'email_confirm_subject' => 'Confirm your email on :appName', | 61 | 'email_confirm_subject' => 'Confirm your email on :appName', |
| 20 | 'email_confirm_greeting' => 'Thanks for joining :appName!', | 62 | 'email_confirm_greeting' => 'Thanks for joining :appName!', |
| ... | @@ -23,4 +65,10 @@ return [ | ... | @@ -23,4 +65,10 @@ return [ |
| 23 | 'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.', | 65 | 'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.', |
| 24 | 'email_confirm_success' => 'Your email has been confirmed!', | 66 | 'email_confirm_success' => 'Your email has been confirmed!', |
| 25 | 'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.', | 67 | 'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.', |
| 68 | + | ||
| 69 | + 'email_not_confirmed' => 'Email Address Not Confirmed', | ||
| 70 | + 'email_not_confirmed_text' => 'Your email address has not yet been confirmed.', | ||
| 71 | + 'email_not_confirmed_click_link' => 'Please click the link in the email that was sent shortly after you registered.', | ||
| 72 | + 'email_not_confirmed_resend' => 'If you cannot find the email you can re-send the confirmation email by submitting the form below.', | ||
| 73 | + 'email_not_confirmed_resend_button' => 'Resend Confirmation Email', | ||
| 26 | ]; | 74 | ]; |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
resources/lang/en/common.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + | ||
| 4 | + /** | ||
| 5 | + * Buttons | ||
| 6 | + */ | ||
| 7 | + 'cancel' => 'Cancel', | ||
| 8 | + 'confirm' => 'Confirm', | ||
| 9 | + 'back' => 'Back', | ||
| 10 | + 'save' => 'Save', | ||
| 11 | + 'continue' => 'Continue', | ||
| 12 | + 'select' => 'Select', | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * Form Labels | ||
| 16 | + */ | ||
| 17 | + 'name' => 'Name', | ||
| 18 | + 'description' => 'Description', | ||
| 19 | + 'role' => 'Role', | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * Actions | ||
| 23 | + */ | ||
| 24 | + 'actions' => 'Actions', | ||
| 25 | + 'view' => 'View', | ||
| 26 | + 'create' => 'Create', | ||
| 27 | + 'update' => 'Update', | ||
| 28 | + 'edit' => 'Edit', | ||
| 29 | + 'sort' => 'Sort', | ||
| 30 | + 'move' => 'Move', | ||
| 31 | + 'delete' => 'Delete', | ||
| 32 | + 'search' => 'Search', | ||
| 33 | + 'search_clear' => 'Clear Search', | ||
| 34 | + 'reset' => 'Reset', | ||
| 35 | + 'remove' => 'Remove', | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * Misc | ||
| 40 | + */ | ||
| 41 | + 'deleted_user' => 'Deleted User', | ||
| 42 | + 'no_activity' => 'No activity to show', | ||
| 43 | + 'no_items' => 'No items available', | ||
| 44 | + 'back_to_top' => 'Back to top', | ||
| 45 | + 'toggle_details' => 'Toggle Details', | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * Header | ||
| 49 | + */ | ||
| 50 | + 'view_profile' => 'View Profile', | ||
| 51 | + 'edit_profile' => 'Edit Profile', | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * Email Content | ||
| 55 | + */ | ||
| 56 | + 'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:', | ||
| 57 | + 'email_rights' => 'All rights reserved', | ||
| 58 | +]; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/lang/en/components.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + | ||
| 4 | + /** | ||
| 5 | + * Image Manager | ||
| 6 | + */ | ||
| 7 | + 'image_select' => 'Image Select', | ||
| 8 | + 'image_all' => 'All', | ||
| 9 | + 'image_all_title' => 'View all images', | ||
| 10 | + 'image_book_title' => 'View images uploaded to this book', | ||
| 11 | + 'image_page_title' => 'View images uploaded to this page', | ||
| 12 | + 'image_search_hint' => 'Search by image name', | ||
| 13 | + 'image_uploaded' => 'Uploaded :uploadedDate', | ||
| 14 | + 'image_load_more' => 'Load More', | ||
| 15 | + 'image_image_name' => 'Image Name', | ||
| 16 | + 'image_delete_confirm' => 'This image is used in the pages below, Click delete again to confirm you want to delete this image.', | ||
| 17 | + 'image_select_image' => 'Select Image', | ||
| 18 | + 'image_dropzone' => 'Drop images or click here to upload', | ||
| 19 | + 'images_deleted' => 'Images Deleted', | ||
| 20 | + 'image_preview' => 'Image Preview', | ||
| 21 | + 'image_upload_success' => 'Image uploaded successfully', | ||
| 22 | + 'image_update_success' => 'Image details successfully updated', | ||
| 23 | + 'image_delete_success' => 'Image successfully deleted' | ||
| 24 | +]; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/lang/en/entities.php
0 → 100644
This diff is collapsed.
Click to expand it.
| ... | @@ -6,7 +6,65 @@ return [ | ... | @@ -6,7 +6,65 @@ return [ |
| 6 | * Error text strings. | 6 | * Error text strings. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | - // Pages | 9 | + // Permissions |
| 10 | 'permission' => 'You do not have permission to access the requested page.', | 10 | 'permission' => 'You do not have permission to access the requested page.', |
| 11 | - 'permissionJson' => 'You do not have permission to perform the requested action.' | 11 | + 'permissionJson' => 'You do not have permission to perform the requested action.', |
| 12 | + | ||
| 13 | + // Auth | ||
| 14 | + 'error_user_exists_different_creds' => 'A user with the email :email already exists but with different credentials.', | ||
| 15 | + 'email_already_confirmed' => 'Email has already been confirmed, Try logging in.', | ||
| 16 | + 'email_confirmation_invalid' => 'This confirmation token is not valid or has already been used, Please try registering again.', | ||
| 17 | + 'email_confirmation_expired' => 'The confirmation token has expired, A new confirmation email has been sent.', | ||
| 18 | + 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', | ||
| 19 | + 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', | ||
| 20 | + 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', | ||
| 21 | + 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', | ||
| 22 | + 'social_no_action_defined' => 'No action defined', | ||
| 23 | + 'social_account_in_use' => 'This :socialAccount account is already in use, Try logging in via the :socialAccount option.', | ||
| 24 | + 'social_account_email_in_use' => 'The email :email is already in use. If you already have an account you can connect your :socialAccount account from your profile settings.', | ||
| 25 | + 'social_account_existing' => 'This :socialAccount is already attached to your profile.', | ||
| 26 | + 'social_account_already_used_existing' => 'This :socialAccount account is already used by another user.', | ||
| 27 | + 'social_account_not_used' => 'This :socialAccount account is not linked to any users. Please attach it in your profile settings. ', | ||
| 28 | + 'social_account_register_instructions' => 'If you do not yet have an account, You can register an account using the :socialAccount option.', | ||
| 29 | + 'social_driver_not_found' => 'Social driver not found', | ||
| 30 | + 'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.', | ||
| 31 | + | ||
| 32 | + // System | ||
| 33 | + 'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.', | ||
| 34 | + 'cannot_get_image_from_url' => 'Cannot get image from :url', | ||
| 35 | + 'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.', | ||
| 36 | + 'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.', | ||
| 37 | + 'image_upload_error' => 'An error occurred uploading the image', | ||
| 38 | + | ||
| 39 | + // Attachments | ||
| 40 | + 'attachment_page_mismatch' => 'Page mismatch during attachment update', | ||
| 41 | + | ||
| 42 | + // Pages | ||
| 43 | + 'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page', | ||
| 44 | + | ||
| 45 | + // Entities | ||
| 46 | + 'entity_not_found' => 'Entity not found', | ||
| 47 | + 'book_not_found' => 'Book not found', | ||
| 48 | + 'page_not_found' => 'Page not found', | ||
| 49 | + 'chapter_not_found' => 'Chapter not found', | ||
| 50 | + 'selected_book_not_found' => 'The selected book was not found', | ||
| 51 | + 'selected_book_chapter_not_found' => 'The selected Book or Chapter was not found', | ||
| 52 | + 'guests_cannot_save_drafts' => 'Guests cannot save drafts', | ||
| 53 | + | ||
| 54 | + // Users | ||
| 55 | + 'users_cannot_delete_only_admin' => 'You cannot delete the only admin', | ||
| 56 | + 'users_cannot_delete_guest' => 'You cannot delete the guest user', | ||
| 57 | + | ||
| 58 | + // Roles | ||
| 59 | + 'role_cannot_be_edited' => 'This role cannot be edited', | ||
| 60 | + 'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted', | ||
| 61 | + 'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role', | ||
| 62 | + | ||
| 63 | + // Error pages | ||
| 64 | + '404_page_not_found' => 'Page Not Found', | ||
| 65 | + 'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.', | ||
| 66 | + 'return_home' => 'Return to home', | ||
| 67 | + 'error_occurred' => 'An Error Occurred', | ||
| 68 | + 'app_down' => ':appName is down right now', | ||
| 69 | + 'back_soon' => 'It will be back up soon.', | ||
| 12 | ]; | 70 | ]; |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| 1 | <?php | 1 | <?php |
| 2 | 2 | ||
| 3 | return [ | 3 | return [ |
| 4 | - | 4 | + |
| 5 | /** | 5 | /** |
| 6 | * Settings text strings | 6 | * Settings text strings |
| 7 | * Contains all text strings used in the general settings sections of BookStack | 7 | * Contains all text strings used in the general settings sections of BookStack |
| 8 | * including users and roles. | 8 | * including users and roles. |
| 9 | */ | 9 | */ |
| 10 | - | 10 | + |
| 11 | 'settings' => 'Settings', | 11 | 'settings' => 'Settings', |
| 12 | 'settings_save' => 'Save Settings', | 12 | 'settings_save' => 'Save Settings', |
| 13 | - | 13 | + 'settings_save_success' => 'Settings saved', |
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * App settings | ||
| 17 | + */ | ||
| 18 | + | ||
| 14 | 'app_settings' => 'App Settings', | 19 | 'app_settings' => 'App Settings', |
| 15 | 'app_name' => 'Application name', | 20 | 'app_name' => 'Application name', |
| 16 | 'app_name_desc' => 'This name is shown in the header and any emails.', | 21 | 'app_name_desc' => 'This name is shown in the header and any emails.', |
| ... | @@ -27,6 +32,10 @@ return [ | ... | @@ -27,6 +32,10 @@ return [ |
| 27 | 'app_primary_color' => 'Application primary color', | 32 | 'app_primary_color' => 'Application primary color', |
| 28 | 'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.', | 33 | 'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.', |
| 29 | 34 | ||
| 35 | + /** | ||
| 36 | + * Registration settings | ||
| 37 | + */ | ||
| 38 | + | ||
| 30 | 'reg_settings' => 'Registration Settings', | 39 | 'reg_settings' => 'Registration Settings', |
| 31 | 'reg_allow' => 'Allow registration?', | 40 | 'reg_allow' => 'Allow registration?', |
| 32 | 'reg_default_role' => 'Default user role after registration', | 41 | 'reg_default_role' => 'Default user role after registration', |
| ... | @@ -36,4 +45,79 @@ return [ | ... | @@ -36,4 +45,79 @@ return [ |
| 36 | 'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application. <br> Note that users will be able to change their email addresses after successful registration.', | 45 | 'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application. <br> Note that users will be able to change their email addresses after successful registration.', |
| 37 | 'reg_confirm_restrict_domain_placeholder' => 'No restriction set', | 46 | 'reg_confirm_restrict_domain_placeholder' => 'No restriction set', |
| 38 | 47 | ||
| 39 | -]; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 48 | + /** | ||
| 49 | + * Role settings | ||
| 50 | + */ | ||
| 51 | + | ||
| 52 | + 'roles' => 'Roles', | ||
| 53 | + 'role_user_roles' => 'User Roles', | ||
| 54 | + 'role_create' => 'Create New Role', | ||
| 55 | + 'role_create_success' => 'Role successfully created', | ||
| 56 | + 'role_delete' => 'Delete Role', | ||
| 57 | + 'role_delete_confirm' => 'This will delete the role with the name \':roleName\'.', | ||
| 58 | + 'role_delete_users_assigned' => 'This role has :userCount users assigned to it. If you would like to migrate the users from this role select a new role below.', | ||
| 59 | + 'role_delete_no_migration' => "Don't migrate users", | ||
| 60 | + 'role_delete_sure' => 'Are you sure you want to delete this role?', | ||
| 61 | + 'role_delete_success' => 'Role successfully deleted', | ||
| 62 | + 'role_edit' => 'Edit Role', | ||
| 63 | + 'role_details' => 'Role Details', | ||
| 64 | + 'role_name' => 'Role Name', | ||
| 65 | + 'role_desc' => 'Short Description of Role', | ||
| 66 | + 'role_system' => 'System Permissions', | ||
| 67 | + 'role_manage_users' => 'Manage users', | ||
| 68 | + 'role_manage_roles' => 'Manage roles & role permissions', | ||
| 69 | + 'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions', | ||
| 70 | + 'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages', | ||
| 71 | + 'role_manage_settings' => 'Manage app settings', | ||
| 72 | + 'role_asset' => 'Asset Permissions', | ||
| 73 | + 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', | ||
| 74 | + 'role_all' => 'All', | ||
| 75 | + 'role_own' => 'Own', | ||
| 76 | + 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', | ||
| 77 | + 'role_save' => 'Save Role', | ||
| 78 | + 'role_update_success' => 'Role successfully updated', | ||
| 79 | + 'role_users' => 'Users in this role', | ||
| 80 | + 'role_users_none' => 'No users are currently assigned to this role', | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * Users | ||
| 84 | + */ | ||
| 85 | + | ||
| 86 | + 'users' => 'Users', | ||
| 87 | + 'user_profile' => 'User Profile', | ||
| 88 | + 'users_add_new' => 'Add New User', | ||
| 89 | + 'users_search' => 'Search Users', | ||
| 90 | + 'users_role' => 'User Roles', | ||
| 91 | + 'users_external_auth_id' => 'External Authentication ID', | ||
| 92 | + 'users_password_warning' => 'Only fill the below if you would like to change your password:', | ||
| 93 | + 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', | ||
| 94 | + 'users_delete' => 'Delete User', | ||
| 95 | + 'users_delete_named' => 'Delete user :userName', | ||
| 96 | + 'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.', | ||
| 97 | + 'users_delete_confirm' => 'Are you sure you want to delete this user?', | ||
| 98 | + 'users_delete_success' => 'Users successfully removed', | ||
| 99 | + 'users_edit' => 'Edit User', | ||
| 100 | + 'users_edit_profile' => 'Edit Profile', | ||
| 101 | + 'users_edit_success' => 'User successfully updated', | ||
| 102 | + 'users_avatar' => 'User Avatar', | ||
| 103 | + 'users_avatar_desc' => 'This image should be approx 256px square.', | ||
| 104 | + 'users_preferred_language' => 'Preferred Language', | ||
| 105 | + 'users_social_accounts' => 'Social Accounts', | ||
| 106 | + 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.', | ||
| 107 | + 'users_social_connect' => 'Connect Account', | ||
| 108 | + 'users_social_disconnect' => 'Disconnect Account', | ||
| 109 | + 'users_social_connected' => ':socialAccount account was successfully attached to your profile.', | ||
| 110 | + 'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.', | ||
| 111 | + | ||
| 112 | + // Since these labels are already localized this array does not need to be | ||
| 113 | + // translated in the language-specific files. | ||
| 114 | + // DELETE BELOW IF COPIED FROM EN | ||
| 115 | + /////////////////////////////////// | ||
| 116 | + 'language_select' => [ | ||
| 117 | + 'en' => 'English', | ||
| 118 | + 'de' => 'Deutsch', | ||
| 119 | + 'fr' => 'Français', | ||
| 120 | + 'pt_BR' => 'Português do Brasil' | ||
| 121 | + ] | ||
| 122 | + /////////////////////////////////// | ||
| 123 | +]; | ... | ... |
| ... | @@ -87,8 +87,8 @@ return [ | ... | @@ -87,8 +87,8 @@ return [ |
| 87 | */ | 87 | */ |
| 88 | 88 | ||
| 89 | 'custom' => [ | 89 | 'custom' => [ |
| 90 | - 'attribute-name' => [ | 90 | + 'password-confirm' => [ |
| 91 | - 'rule-name' => 'custom-message', | 91 | + 'required_with' => 'Password confirmation required', |
| 92 | ], | 92 | ], |
| 93 | ], | 93 | ], |
| 94 | 94 | ... | ... |
resources/lang/fr/activities.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * Activity text strings. | ||
| 7 | + * Is used for all the text within activity logs & notifications. | ||
| 8 | + */ | ||
| 9 | + | ||
| 10 | + // Pages | ||
| 11 | + 'page_create' => 'a créé la page', | ||
| 12 | + 'page_create_notification' => 'Page créée avec succès', | ||
| 13 | + 'page_update' => 'a modifié la page', | ||
| 14 | + 'page_update_notification' => 'Page modifiée avec succès', | ||
| 15 | + 'page_delete' => 'a supprimé la page', | ||
| 16 | + 'page_delete_notification' => 'Page supprimée avec succès', | ||
| 17 | + 'page_restore' => 'a restauré la page', | ||
| 18 | + 'page_restore_notification' => 'Page réstaurée avec succès', | ||
| 19 | + 'page_move' => 'a déplacé la page', | ||
| 20 | + | ||
| 21 | + // Chapters | ||
| 22 | + 'chapter_create' => 'a créé le chapitre', | ||
| 23 | + 'chapter_create_notification' => 'Chapitre créé avec succès', | ||
| 24 | + 'chapter_update' => 'a modifié le chapitre', | ||
| 25 | + 'chapter_update_notification' => 'Chapitre modifié avec succès', | ||
| 26 | + 'chapter_delete' => 'a supprimé le chapitre', | ||
| 27 | + 'chapter_delete_notification' => 'Chapitre supprimé avec succès', | ||
| 28 | + 'chapter_move' => 'a déplacé le chapitre', | ||
| 29 | + | ||
| 30 | + // Books | ||
| 31 | + 'book_create' => 'a créé le livre', | ||
| 32 | + 'book_create_notification' => 'Livre créé avec succès', | ||
| 33 | + 'book_update' => 'a modifié le livre', | ||
| 34 | + 'book_update_notification' => 'Livre modifié avec succès', | ||
| 35 | + 'book_delete' => 'a supprimé le livre', | ||
| 36 | + 'book_delete_notification' => 'Livre supprimé avec succès', | ||
| 37 | + 'book_sort' => 'a réordonné le livre', | ||
| 38 | + 'book_sort_notification' => 'Livre réordonné avec succès', | ||
| 39 | + | ||
| 40 | +]; |
resources/lang/fr/auth.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + /* | ||
| 4 | + |-------------------------------------------------------------------------- | ||
| 5 | + | Authentication Language Lines | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | | ||
| 8 | + | The following language lines are used during authentication for various | ||
| 9 | + | messages that we need to display to the user. You are free to modify | ||
| 10 | + | these language lines according to your application's requirements. | ||
| 11 | + | | ||
| 12 | + */ | ||
| 13 | + 'failed' => 'Ces informations ne correspondent a aucun compte.', | ||
| 14 | + 'throttle' => "Trop d'essais, veuillez réessayer dans :seconds secondes.", | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * Login & Register | ||
| 18 | + */ | ||
| 19 | + 'sign_up' => "S'inscrire", | ||
| 20 | + 'log_in' => 'Se connecter', | ||
| 21 | + 'logout' => 'Se déconnecter', | ||
| 22 | + | ||
| 23 | + 'name' => 'Nom', | ||
| 24 | + 'username' => "Nom d'utilisateur", | ||
| 25 | + 'email' => 'E-mail', | ||
| 26 | + 'password' => 'Mot de passe', | ||
| 27 | + 'password_confirm' => 'Confirmez le mot de passe', | ||
| 28 | + 'password_hint' => 'Doit faire plus de 5 caractères', | ||
| 29 | + 'forgot_password' => 'Mot de passe oublié?', | ||
| 30 | + 'remember_me' => 'Se souvenir de moi', | ||
| 31 | + 'ldap_email_hint' => "Merci d'entrer une adresse e-mail pour ce compte", | ||
| 32 | + 'create_account' => 'Créer un compte', | ||
| 33 | + 'social_login' => 'Social Login', | ||
| 34 | + 'social_registration' => 'Enregistrement Social', | ||
| 35 | + 'social_registration_text' => "S'inscrire et se connecter avec un réseau social", | ||
| 36 | + | ||
| 37 | + 'register_thanks' => 'Merci pour votre enregistrement', | ||
| 38 | + 'register_confirm' => 'Vérifiez vos e-mails et cliquer sur le lien de confirmation pour rejoindre :appName.', | ||
| 39 | + 'registrations_disabled' => "L'inscription est désactivée pour le moment", | ||
| 40 | + 'registration_email_domain_invalid' => 'Cette adresse e-mail ne peux pas adcéder à l\'application', | ||
| 41 | + 'register_success' => 'Merci pour votre inscription. Vous êtes maintenant inscrit(e) et connecté(e)', | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * Password Reset | ||
| 46 | + */ | ||
| 47 | + 'reset_password' => 'Reset Password', | ||
| 48 | + 'reset_password_send_instructions' => 'Entrez votre adresse e-mail ci-dessous et un e-mail avec un lien de réinitialisation de mot de passe vous sera envoyé', | ||
| 49 | + 'reset_password_send_button' => 'Envoyer un lien de réinitialisation', | ||
| 50 | + 'reset_password_sent_success' => 'Un lien de réinitialisation a été envoyé à :email.', | ||
| 51 | + 'reset_password_success' => 'Votre mot de passe a été réinitialisé avec succès.', | ||
| 52 | + | ||
| 53 | + 'email_reset_subject' => 'Réinitialisez votre mot de passe pour :appName', | ||
| 54 | + 'email_reset_text' => 'Vous recevez cet e-mail parceque nous avons reçu une demande de réinitialisation pour votre compte', | ||
| 55 | + 'email_reset_not_requested' => 'Si vous n\'avez pas effectué cette demande, vous pouvez ignorer cet e-mail.', | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * Email Confirmation | ||
| 60 | + */ | ||
| 61 | + 'email_confirm_subject' => 'Confirmez votre adresse e-mail pour :appName', | ||
| 62 | + 'email_confirm_greeting' => 'Merci d\'avoir rejoint :appName!', | ||
| 63 | + 'email_confirm_text' => 'Merci de confirmer en cliquant sur le lien ci-dessous:', | ||
| 64 | + 'email_confirm_action' => 'Confirmez votre adresse e-mail', | ||
| 65 | + 'email_confirm_send_error' => 'La confirmation par e-mail est requise mais le système n\'a pas pu envoyer l\'e-mail. Contactez l\'administrateur système.', | ||
| 66 | + 'email_confirm_success' => 'Votre adresse e-mail a été confirmée!', | ||
| 67 | + 'email_confirm_resent' => 'L\'e-mail de confirmation a été ré-envoyé. Vérifiez votre boîte de récéption.', | ||
| 68 | + | ||
| 69 | + 'email_not_confirmed' => 'Adresse e-mail non confirmée', | ||
| 70 | + 'email_not_confirmed_text' => 'Votre adresse e-mail n\'a pas été confirmée.', | ||
| 71 | + 'email_not_confirmed_click_link' => 'Merci de cliquer sur le lien dans l\'e-mail qui vous a été envoyé après l\'enregistrement.', | ||
| 72 | + 'email_not_confirmed_resend' => 'Si vous ne retrouvez plus l\'e-mail, vous pouvez renvoyer un e-mail de confirmation en utilisant le formulaire ci-dessous.', | ||
| 73 | + 'email_not_confirmed_resend_button' => 'Renvoyez l\'e-mail de confirmation', | ||
| 74 | +]; |
resources/lang/fr/common.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + | ||
| 4 | + /** | ||
| 5 | + * Buttons | ||
| 6 | + */ | ||
| 7 | + 'cancel' => 'Annuler', | ||
| 8 | + 'confirm' => 'Confirmer', | ||
| 9 | + 'back' => 'Retour', | ||
| 10 | + 'save' => 'Enregistrer', | ||
| 11 | + 'continue' => 'Continuer', | ||
| 12 | + 'select' => 'Selectionner', | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * Form Labels | ||
| 16 | + */ | ||
| 17 | + 'name' => 'Nom', | ||
| 18 | + 'description' => 'Description', | ||
| 19 | + 'role' => 'Rôle', | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * Actions | ||
| 23 | + */ | ||
| 24 | + 'actions' => 'Actions', | ||
| 25 | + 'view' => 'Voir', | ||
| 26 | + 'create' => 'Créer', | ||
| 27 | + 'update' => 'Modifier', | ||
| 28 | + 'edit' => 'Editer', | ||
| 29 | + 'sort' => 'Trier', | ||
| 30 | + 'move' => 'Déplacer', | ||
| 31 | + 'delete' => 'Supprimer', | ||
| 32 | + 'search' => 'Chercher', | ||
| 33 | + 'search_clear' => 'Réinitialiser la recherche', | ||
| 34 | + 'reset' => 'Réinitialiser', | ||
| 35 | + 'remove' => 'Enlever', | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * Misc | ||
| 40 | + */ | ||
| 41 | + 'deleted_user' => 'Utilisateur supprimé', | ||
| 42 | + 'no_activity' => 'Aucune activité', | ||
| 43 | + 'no_items' => 'Aucun élément', | ||
| 44 | + 'back_to_top' => 'Retour en haut', | ||
| 45 | + 'toggle_details' => 'Afficher les détails', | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * Header | ||
| 49 | + */ | ||
| 50 | + 'view_profile' => 'Voir le profil', | ||
| 51 | + 'edit_profile' => 'Modifier le profil', | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * Email Content | ||
| 55 | + */ | ||
| 56 | + 'email_action_help' => 'Si vous rencontrez des problèmes pour cliquer le bouton ":actionText", copiez et collez l\'adresse ci-dessous dans votre navigateur:', | ||
| 57 | + 'email_rights' => 'Tous droits réservés', | ||
| 58 | +]; |
resources/lang/fr/components.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + | ||
| 4 | + /** | ||
| 5 | + * Image Manager | ||
| 6 | + */ | ||
| 7 | + 'image_select' => 'Selectionner une image', | ||
| 8 | + 'image_all' => 'Toutes', | ||
| 9 | + 'image_all_title' => 'Voir toutes les images', | ||
| 10 | + 'image_book_title' => 'Voir les images ajoutées à ce livre', | ||
| 11 | + 'image_page_title' => 'Voir les images ajoutées à cette page', | ||
| 12 | + 'image_search_hint' => 'Rechercher par nom d\'image', | ||
| 13 | + 'image_uploaded' => 'Ajoutée le :uploadedDate', | ||
| 14 | + 'image_load_more' => 'Charger plus', | ||
| 15 | + 'image_image_name' => 'Nom de l\'image', | ||
| 16 | + 'image_delete_confirm' => 'Cette image est utilisée dans les pages ci-dessous. Confirmez que vous souhaitez bien supprimer cette image.', | ||
| 17 | + 'image_select_image' => 'Selectionner l\'image', | ||
| 18 | + 'image_dropzone' => 'Glissez les images ici ou cliquez pour les ajouter', | ||
| 19 | + 'images_deleted' => 'Images supprimées', | ||
| 20 | + 'image_preview' => 'Prévisualiser l\'image', | ||
| 21 | + 'image_upload_success' => 'Image ajoutée avec succès', | ||
| 22 | + 'image_update_success' => 'Détails de l\'image mis à jour', | ||
| 23 | + 'image_delete_success' => 'Image supprimée avec succès' | ||
| 24 | +]; |
resources/lang/fr/entities.php
0 → 100644
This diff is collapsed.
Click to expand it.
resources/lang/fr/errors.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * Error text strings. | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | + // Permissions | ||
| 10 | + 'permission' => 'Vous n\'avez pas les droits pour accéder à cette page.', | ||
| 11 | + 'permissionJson' => 'Vous n\'avez pas les droits pour exécuter cette action.', | ||
| 12 | + | ||
| 13 | + // Auth | ||
| 14 | + 'error_user_exists_different_creds' => 'Un utilisateur avec l\'adresse :email existe déjà.', | ||
| 15 | + 'email_already_confirmed' => 'Cet e-mail a déjà été validé, vous pouvez vous connecter.', | ||
| 16 | + 'email_confirmation_invalid' => 'Cette confirmation est invalide. Veuillez essayer de vous inscrire à nouveau.', | ||
| 17 | + 'email_confirmation_expired' => 'Le jeton de confirmation est perimé. Un nouvel e-mail vous a été envoyé.', | ||
| 18 | + 'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti', | ||
| 19 | + 'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe', | ||
| 20 | + 'ldap_extension_not_installed' => 'L\'extention LDAP PHP n\'est pas installée', | ||
| 21 | + 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', | ||
| 22 | + 'social_no_action_defined' => 'No action defined', | ||
| 23 | + 'social_account_in_use' => 'Cet compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.', | ||
| 24 | + 'social_account_email_in_use' => 'L\'email :email Est déjà utilisé. Si vous avez déjà un compte :socialAccount, vous pouvez le joindre à votre profil existant.', | ||
| 25 | + 'social_account_existing' => 'Ce compte :socialAccount est déjà rattaché à votre profil.', | ||
| 26 | + 'social_account_already_used_existing' => 'Ce compte :socialAccount est déjà utilisé par un autre utilisateur.', | ||
| 27 | + 'social_account_not_used' => 'Ce compte :socialAccount n\'est lié à aucun utilisateur. ', | ||
| 28 | + 'social_account_register_instructions' => 'Si vous n\'avez pas encore de compte, vous pouvez le lier avec l\'option :socialAccount.', | ||
| 29 | + 'social_driver_not_found' => 'Social driver not found', | ||
| 30 | + 'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.', | ||
| 31 | + | ||
| 32 | + // System | ||
| 33 | + 'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.', | ||
| 34 | + 'cannot_get_image_from_url' => 'Impossible de récupérer l\'image depuis :url', | ||
| 35 | + 'cannot_create_thumbs' => 'Le serveur ne peux pas créer de miniatures, vérifier que l\extensions GD PHP est installée.', | ||
| 36 | + 'server_upload_limit' => 'La taille du fichier est trop grande.', | ||
| 37 | + 'image_upload_error' => 'Une erreur est survenue pendant l\'envoi de l\'image', | ||
| 38 | + | ||
| 39 | + // Attachments | ||
| 40 | + 'attachment_page_mismatch' => 'Page mismatch during attachment update', | ||
| 41 | + | ||
| 42 | + // Pages | ||
| 43 | + 'page_draft_autosave_fail' => 'Le brouillon n\'a pas pu être sauvé. Vérifiez votre connexion internet', | ||
| 44 | + | ||
| 45 | + // Entities | ||
| 46 | + 'entity_not_found' => 'Entité non trouvée', | ||
| 47 | + 'book_not_found' => 'Livre non trouvé', | ||
| 48 | + 'page_not_found' => 'Page non trouvée', | ||
| 49 | + 'chapter_not_found' => 'Chapitre non trouvé', | ||
| 50 | + 'selected_book_not_found' => 'Ce livre n\'a pas été trouvé', | ||
| 51 | + 'selected_book_chapter_not_found' => 'Ce livre ou chapitre n\'a pas été trouvé', | ||
| 52 | + 'guests_cannot_save_drafts' => 'Les invités ne peuvent pas sauver de brouillons', | ||
| 53 | + | ||
| 54 | + // Users | ||
| 55 | + 'users_cannot_delete_only_admin' => 'Vous ne pouvez pas supprimer le dernier admin', | ||
| 56 | + 'users_cannot_delete_guest' => 'Vous ne pouvez pas supprimer l\'utilisateur invité', | ||
| 57 | + | ||
| 58 | + // Roles | ||
| 59 | + 'role_cannot_be_edited' => 'Ce rôle ne peut pas être modifié', | ||
| 60 | + 'role_system_cannot_be_deleted' => 'Ceci est un rôle du système et on ne peut pas le supprimer', | ||
| 61 | + 'role_registration_default_cannot_delete' => 'Ce rôle ne peut pas être supprimé tant qu\'il est le rôle par défaut', | ||
| 62 | + | ||
| 63 | + // Error pages | ||
| 64 | + '404_page_not_found' => 'Page non trouvée', | ||
| 65 | + 'sorry_page_not_found' => 'Désolé, cette page n\'a pas pu être trouvée.', | ||
| 66 | + 'return_home' => 'Retour à l\'accueil', | ||
| 67 | + 'error_occurred' => 'Une erreur est survenue', | ||
| 68 | + 'app_down' => ':appName n\'est pas en service pour le moment', | ||
| 69 | + 'back_soon' => 'Nous serons bientôt de retour.', | ||
| 70 | +]; |
resources/lang/fr/pagination.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /* | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | Pagination Language Lines | ||
| 8 | + |-------------------------------------------------------------------------- | ||
| 9 | + | | ||
| 10 | + | The following language lines are used by the paginator library to build | ||
| 11 | + | the simple pagination links. You are free to change them to anything | ||
| 12 | + | you want to customize your views to better match your application. | ||
| 13 | + | | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + 'previous' => '« Précédent', | ||
| 17 | + 'next' => 'Suivant »', | ||
| 18 | + | ||
| 19 | +]; |
resources/lang/fr/passwords.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /* | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | Password Reminder Language Lines | ||
| 8 | + |-------------------------------------------------------------------------- | ||
| 9 | + | | ||
| 10 | + | The following language lines are the default lines which match reasons | ||
| 11 | + | that are given by the password broker for a password update attempt | ||
| 12 | + | has failed, such as for an invalid token or invalid new password. | ||
| 13 | + | | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + 'password' => 'Les mots de passe doivent faire au moins 6 caractères et correspondre à la confirmation.', | ||
| 17 | + 'user' => "Nous n'avons pas trouvé d'utilisateur avec cette adresse.", | ||
| 18 | + 'token' => 'Le jeton de réinitialisation est invalide.', | ||
| 19 | + 'sent' => 'Nous vous avons envoyé un lien de réinitialisation de mot de passe!', | ||
| 20 | + 'reset' => 'Votre mot de passe a été réinitialisé!', | ||
| 21 | + | ||
| 22 | +]; |
resources/lang/fr/settings.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * Settings text strings | ||
| 7 | + * Contains all text strings used in the general settings sections of BookStack | ||
| 8 | + * including users and roles. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + 'settings' => 'Préférences', | ||
| 12 | + 'settings_save' => 'Enregistrer les préférences', | ||
| 13 | + 'settings_save_success' => 'Préférences enregistrées', | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * App settings | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + 'app_settings' => 'Préférences de l\'application', | ||
| 20 | + 'app_name' => 'Nom de l\'application', | ||
| 21 | + 'app_name_desc' => 'Ce nom est affiché dans l\'en-tête et les e-mails.', | ||
| 22 | + 'app_name_header' => 'Afficher le nom dans l\'en-tête?', | ||
| 23 | + 'app_public_viewing' => 'Accepter le visionnage public des pages?', | ||
| 24 | + 'app_secure_images' => 'Activer l\'ajout d\'image sécurisé?', | ||
| 25 | + 'app_secure_images_desc' => 'Pour des questions de performances, toutes les images sont publiques. Cette option ajoute une chaîne aléatoire difficile à deviner dans les URLs des images.', | ||
| 26 | + 'app_editor' => 'Editeur des pages', | ||
| 27 | + 'app_editor_desc' => 'Sélectionnez l\'éditeur qui sera utilisé pour modifier les pages.', | ||
| 28 | + 'app_custom_html' => 'HTML personnalisé dans l\'en-tête', | ||
| 29 | + 'app_custom_html_desc' => 'Le contenu inséré ici sera jouté en bas de la balise <head> de toutes les pages. Vous pouvez l\'utiliser pour ajouter du CSS personnalisé ou un tracker analytique.', | ||
| 30 | + 'app_logo' => 'Logo de l\'Application', | ||
| 31 | + 'app_logo_desc' => 'Cette image doit faire 43px de hauteur. <br>Les images plus larges seront réduites.', | ||
| 32 | + 'app_primary_color' => 'Couleur principale de l\'application', | ||
| 33 | + 'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.', | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * Registration settings | ||
| 37 | + */ | ||
| 38 | + | ||
| 39 | + 'reg_settings' => 'Préférence pour l\'inscription', | ||
| 40 | + 'reg_allow' => 'Accepter l\'inscription?', | ||
| 41 | + 'reg_default_role' => 'Rôle par défaut lors de l\'inscription', | ||
| 42 | + 'reg_confirm_email' => 'Obliger la confirmation par e-mail?', | ||
| 43 | + 'reg_confirm_email_desc' => 'Si la restriction de domaine est activée, la confirmation sera automatiquement obligatoire et cette valeur sera ignorée.', | ||
| 44 | + 'reg_confirm_restrict_domain' => 'Restreindre l\'inscription à un domaine', | ||
| 45 | + 'reg_confirm_restrict_domain_desc' => 'Entrez une liste de domaines acceptés lors de l\'inscription, séparés par une virgule. Les utilisateur recevront un e-mail de confirmation à cette adresse. <br> Les utilisateurs pourront changer leur adresse après inscription s\'ils le souhaitent.', | ||
| 46 | + 'reg_confirm_restrict_domain_placeholder' => 'Aucune restriction en place', | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * Role settings | ||
| 50 | + */ | ||
| 51 | + | ||
| 52 | + 'roles' => 'Rôles', | ||
| 53 | + 'role_user_roles' => 'Rôles des utilisateurs', | ||
| 54 | + 'role_create' => 'Créer un nouveau rôle', | ||
| 55 | + 'role_create_success' => 'Rôle créé avec succès', | ||
| 56 | + 'role_delete' => 'Supprimer le rôle', | ||
| 57 | + 'role_delete_confirm' => 'Ceci va supprimer le rôle \':roleName\'.', | ||
| 58 | + 'role_delete_users_assigned' => 'Ce rôle a :userCount utilisateurs assignés. Vous pouvez choisir un rôle de remplacement pour ces utilisateurs.', | ||
| 59 | + 'role_delete_no_migration' => "Ne pas assigner de nouveau rôle", | ||
| 60 | + 'role_delete_sure' => 'Êtes vous sûr(e) de vouloir supprimer ce rôle?', | ||
| 61 | + 'role_delete_success' => 'Le rôle a été supprimé avec succès', | ||
| 62 | + 'role_edit' => 'Modifier le rôle', | ||
| 63 | + 'role_details' => 'Détails du rôle', | ||
| 64 | + 'role_name' => 'Nom du Rôle', | ||
| 65 | + 'role_desc' => 'Courte description du rôle', | ||
| 66 | + 'role_system' => 'Permissions système', | ||
| 67 | + 'role_manage_users' => 'Gérer les utilisateurs', | ||
| 68 | + 'role_manage_roles' => 'Gérer les rôles et permissions', | ||
| 69 | + 'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages', | ||
| 70 | + 'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres chapitres et pages', | ||
| 71 | + 'role_manage_settings' => 'Gérer les préférences de l\'application', | ||
| 72 | + 'role_asset' => 'Asset Permissions', | ||
| 73 | + 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', | ||
| 74 | + 'role_all' => 'Tous', | ||
| 75 | + 'role_own' => 'Propres', | ||
| 76 | + 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', | ||
| 77 | + 'role_save' => 'Enregistrer le rôle', | ||
| 78 | + 'role_update_success' => 'Rôle mis à jour avec succès', | ||
| 79 | + 'role_users' => 'Utilisateurs ayant ce rôle', | ||
| 80 | + 'role_users_none' => 'Aucun utilisateur avec ce rôle actuellement', | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * Users | ||
| 84 | + */ | ||
| 85 | + | ||
| 86 | + 'users' => 'Utilisateurs', | ||
| 87 | + 'user_profile' => 'Profil d\'utilisateur', | ||
| 88 | + 'users_add_new' => 'Ajouter un nouvel utilisateur', | ||
| 89 | + 'users_search' => 'Chercher les utilisateurs', | ||
| 90 | + 'users_role' => 'Rôles des utilisateurs', | ||
| 91 | + 'users_external_auth_id' => 'Identifiant d\'authentification externe', | ||
| 92 | + 'users_password_warning' => 'Remplissez ce fomulaire uniquement si vous souhaitez changer de mot de passe:', | ||
| 93 | + 'users_system_public' => 'Cet utilisateur représente les invités visitant votre instance. Il est assigné automatiquement aux invités.', | ||
| 94 | + 'users_delete' => 'Supprimer un utilisateur', | ||
| 95 | + 'users_delete_named' => 'Supprimer l\'utilisateur :userName', | ||
| 96 | + 'users_delete_warning' => 'Ceci va supprimer \':userName\' du système.', | ||
| 97 | + 'users_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cet utilisateur?', | ||
| 98 | + 'users_delete_success' => 'Utilisateurs supprimés avec succès', | ||
| 99 | + 'users_edit' => 'Modifier l\'utilisateur', | ||
| 100 | + 'users_edit_profile' => 'Modifier le profil', | ||
| 101 | + 'users_edit_success' => 'Utilisateur mis à jour avec succès', | ||
| 102 | + 'users_avatar' => 'Avatar de l\'utilisateur', | ||
| 103 | + 'users_avatar_desc' => 'Cette image doit être un carré d\'environ 256px.', | ||
| 104 | + 'users_preferred_language' => 'Langue préférée', | ||
| 105 | + 'users_social_accounts' => 'Comptes sociaux', | ||
| 106 | + 'users_social_accounts_info' => 'Vous pouvez connecter des réseaux sociaux à votre compte pour vous connecter plus rapidement. Déconnecter un compte n\'enlèvera pas les accès autorisés précédemment sur votre compte de réseau social.', | ||
| 107 | + 'users_social_connect' => 'Connecter le compte', | ||
| 108 | + 'users_social_disconnect' => 'Déconnecter le compte', | ||
| 109 | + 'users_social_connected' => 'Votre compte :socialAccount a élté ajouté avec succès.', | ||
| 110 | + 'users_social_disconnected' => 'Votre compte :socialAccount a été déconnecté avec succès', | ||
| 111 | + | ||
| 112 | +]; |
resources/lang/fr/validation.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /* | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | Validation Language Lines | ||
| 8 | + |-------------------------------------------------------------------------- | ||
| 9 | + | | ||
| 10 | + | The following language lines contain the default error messages used by | ||
| 11 | + | the validator class. Some of these rules have multiple versions such | ||
| 12 | + | as the size rules. Feel free to tweak each of these messages here. | ||
| 13 | + | | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + 'accepted' => ':attribute doit être accepté.', | ||
| 17 | + 'active_url' => ':attribute n\'est pas une URL valide.', | ||
| 18 | + 'after' => ':attribute doit être supérieur à :date.', | ||
| 19 | + 'alpha' => ':attribute ne doit contenir que des lettres.', | ||
| 20 | + 'alpha_dash' => ':attribute doit contenir uniquement des lettres, chiffres et traits d\'union.', | ||
| 21 | + 'alpha_num' => ':attribute doit contenir uniquement des chiffres et des lettres.', | ||
| 22 | + 'array' => ':attribute doit être un tableau.', | ||
| 23 | + 'before' => ':attribute doit être inférieur à :date.', | ||
| 24 | + 'between' => [ | ||
| 25 | + 'numeric' => ':attribute doit être compris entre :min et :max.', | ||
| 26 | + 'file' => ':attribute doit être compris entre :min et :max kilobytes.', | ||
| 27 | + 'string' => ':attribute doit être compris entre :min et :max caractères.', | ||
| 28 | + 'array' => ':attribute doit être compris entre :min et :max éléments.', | ||
| 29 | + ], | ||
| 30 | + 'boolean' => ':attribute doit être vrai ou faux.', | ||
| 31 | + 'confirmed' => ':attribute la confirmation n\'est pas valide.', | ||
| 32 | + 'date' => ':attribute n\'est pas une date valide.', | ||
| 33 | + 'date_format' => ':attribute ne correspond pas au format :format.', | ||
| 34 | + 'different' => ':attribute et :other doivent être différents l\'un de l\'autre.', | ||
| 35 | + 'digits' => ':attribute doit être de longueur :digits.', | ||
| 36 | + 'digits_between' => ':attribute doit avoir une longueur entre :min et :max.', | ||
| 37 | + 'email' => ':attribute doit être une adresse e-mail valide.', | ||
| 38 | + 'filled' => ':attribute est un champ requis.', | ||
| 39 | + 'exists' => 'L\'attribut :attribute est invalide.', | ||
| 40 | + 'image' => ':attribute doit être une image.', | ||
| 41 | + 'in' => 'L\'attribut :attribute est invalide.', | ||
| 42 | + 'integer' => ':attribute doit être un chiffre entier.', | ||
| 43 | + 'ip' => ':attribute doit être une adresse IP valide.', | ||
| 44 | + 'max' => [ | ||
| 45 | + 'numeric' => ':attribute ne doit pas excéder :max.', | ||
| 46 | + 'file' => ':attribute ne doit pas excéder :max kilobytes.', | ||
| 47 | + 'string' => ':attribute ne doit pas excéder :max caractères.', | ||
| 48 | + 'array' => ':attribute ne doit pas contenir plus de :max éléments.', | ||
| 49 | + ], | ||
| 50 | + 'mimes' => ':attribute doit être un fichier de type :values.', | ||
| 51 | + 'min' => [ | ||
| 52 | + 'numeric' => ':attribute doit être au moins :min.', | ||
| 53 | + 'file' => ':attribute doit faire au moins :min kilobytes.', | ||
| 54 | + 'string' => ':attribute doit contenir au moins :min caractères.', | ||
| 55 | + 'array' => ':attribute doit contenir au moins :min éléments.', | ||
| 56 | + ], | ||
| 57 | + 'not_in' => 'L\'attribut sélectionné :attribute est invalide.', | ||
| 58 | + 'numeric' => ':attribute doit être un nombre.', | ||
| 59 | + 'regex' => ':attribute a un format invalide.', | ||
| 60 | + 'required' => ':attribute est un champ requis.', | ||
| 61 | + 'required_if' => ':attribute est requis si :other est :value.', | ||
| 62 | + 'required_with' => ':attribute est requis si :values est présent.', | ||
| 63 | + 'required_with_all' => ':attribute est requis si :values est présent.', | ||
| 64 | + 'required_without' => ':attribute est requis si:values n\'est pas présent.', | ||
| 65 | + 'required_without_all' => ':attribute est requis si aucun des valeurs :values n\'est présente.', | ||
| 66 | + 'same' => ':attribute et :other doivent être identiques.', | ||
| 67 | + 'size' => [ | ||
| 68 | + 'numeric' => ':attribute doit avoir la taille :size.', | ||
| 69 | + 'file' => ':attribute doit peser :size kilobytes.', | ||
| 70 | + 'string' => ':attribute doit contenir :size caractères.', | ||
| 71 | + 'array' => ':attribute doit contenir :size éléments.', | ||
| 72 | + ], | ||
| 73 | + 'string' => ':attribute doit être une chaîne de caractères.', | ||
| 74 | + 'timezone' => ':attribute doit être une zone valide.', | ||
| 75 | + 'unique' => ':attribute est déjà utilisé.', | ||
| 76 | + 'url' => ':attribute a un format invalide.', | ||
| 77 | + | ||
| 78 | + /* | ||
| 79 | + |-------------------------------------------------------------------------- | ||
| 80 | + | Custom Validation Language Lines | ||
| 81 | + |-------------------------------------------------------------------------- | ||
| 82 | + | | ||
| 83 | + | Here you may specify custom validation messages for attributes using the | ||
| 84 | + | convention "attribute.rule" to name the lines. This makes it quick to | ||
| 85 | + | specify a specific custom language line for a given attribute rule. | ||
| 86 | + | | ||
| 87 | + */ | ||
| 88 | + | ||
| 89 | + 'custom' => [ | ||
| 90 | + 'password-confirm' => [ | ||
| 91 | + 'required_with' => 'La confirmation du mot de passe est requise', | ||
| 92 | + ], | ||
| 93 | + ], | ||
| 94 | + | ||
| 95 | + /* | ||
| 96 | + |-------------------------------------------------------------------------- | ||
| 97 | + | Custom Validation Attributes | ||
| 98 | + |-------------------------------------------------------------------------- | ||
| 99 | + | | ||
| 100 | + | The following language lines are used to swap attribute place-holders | ||
| 101 | + | with something more reader friendly such as E-Mail Address instead | ||
| 102 | + | of "email". This simply helps us make messages a little cleaner. | ||
| 103 | + | | ||
| 104 | + */ | ||
| 105 | + | ||
| 106 | + 'attributes' => [], | ||
| 107 | + | ||
| 108 | +]; |
resources/lang/pt_BR/activities.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * Activity text strings. | ||
| 7 | + * Is used for all the text within activity logs & notifications. | ||
| 8 | + */ | ||
| 9 | + | ||
| 10 | + // Pages | ||
| 11 | + 'page_create' => 'página criada', | ||
| 12 | + 'page_create_notification' => 'Página criada com sucesso', | ||
| 13 | + 'page_update' => 'página atualizada', | ||
| 14 | + 'page_update_notification' => 'Página atualizada com sucesso', | ||
| 15 | + 'page_delete' => 'página excluída', | ||
| 16 | + 'page_delete_notification' => 'Página excluída com sucesso', | ||
| 17 | + 'page_restore' => 'página restaurada', | ||
| 18 | + 'page_restore_notification' => 'Página restaurada com sucesso', | ||
| 19 | + 'page_move' => 'página movida', | ||
| 20 | + | ||
| 21 | + // Chapters | ||
| 22 | + 'chapter_create' => 'capítulo criado', | ||
| 23 | + 'chapter_create_notification' => 'Capítulo criado com sucesso', | ||
| 24 | + 'chapter_update' => 'capítulo atualizado', | ||
| 25 | + 'chapter_update_notification' => 'capítulo atualizado com sucesso', | ||
| 26 | + 'chapter_delete' => 'capítulo excluído', | ||
| 27 | + 'chapter_delete_notification' => 'Capítulo excluído com sucesso', | ||
| 28 | + 'chapter_move' => 'capitulo movido', | ||
| 29 | + | ||
| 30 | + // Books | ||
| 31 | + 'book_create' => 'livro criado', | ||
| 32 | + 'book_create_notification' => 'Livro criado com sucesso', | ||
| 33 | + 'book_update' => 'livro atualizado', | ||
| 34 | + 'book_update_notification' => 'Livro atualizado com sucesso', | ||
| 35 | + 'book_delete' => 'livro excluído', | ||
| 36 | + 'book_delete_notification' => 'Livro excluído com sucesso', | ||
| 37 | + 'book_sort' => 'livro classificado', | ||
| 38 | + 'book_sort_notification' => 'Livro reclassificado com sucesso', | ||
| 39 | + | ||
| 40 | +]; |
resources/lang/pt_BR/auth.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + /* | ||
| 4 | + |-------------------------------------------------------------------------- | ||
| 5 | + | Authentication Language Lines | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | | ||
| 8 | + | The following language lines are used during authentication for various | ||
| 9 | + | messages that we need to display to the user. You are free to modify | ||
| 10 | + | these language lines according to your application's requirements. | ||
| 11 | + | | ||
| 12 | + */ | ||
| 13 | + 'failed' => 'As credenciais fornecidas não puderam ser validadas em nossos registros..', | ||
| 14 | + 'throttle' => 'Muitas tentativas de login. Por favor, tente novamente em :seconds segundos.', | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * Login & Register | ||
| 18 | + */ | ||
| 19 | + 'sign_up' => 'Registrar-se', | ||
| 20 | + 'log_in' => 'Entrar', | ||
| 21 | + 'logout' => 'Sair', | ||
| 22 | + | ||
| 23 | + 'name' => 'Nome', | ||
| 24 | + 'username' => 'Nome de Usuário', | ||
| 25 | + 'email' => 'E-mail', | ||
| 26 | + 'password' => 'Senha', | ||
| 27 | + 'password_confirm' => 'Confirmar Senha', | ||
| 28 | + 'password_hint' => 'Senha deverá ser maior que 5 caracteres', | ||
| 29 | + 'forgot_password' => 'Esqueceu a senha?', | ||
| 30 | + 'remember_me' => 'Lembrar de mim', | ||
| 31 | + 'ldap_email_hint' => 'Por favor, digite um e-mail para essa conta.', | ||
| 32 | + 'create_account' => 'Criar conta', | ||
| 33 | + 'social_login' => 'Login social', | ||
| 34 | + 'social_registration' => 'Registro social', | ||
| 35 | + 'social_registration_text' => 'Registre e entre usando outro serviço.', | ||
| 36 | + | ||
| 37 | + 'register_thanks' => 'Obrigado por efetuar o registro!', | ||
| 38 | + 'register_confirm' => 'Por favor, verifique seu e-mail e clique no botão de confirmação para acessar :appName.', | ||
| 39 | + 'registrations_disabled' => 'Registros estão temporariamente desabilitados', | ||
| 40 | + 'registration_email_domain_invalid' => 'O domínio de e-mail usado não tem acesso permitido a essa aplicação', | ||
| 41 | + 'register_success' => 'Obrigado por se registrar! Você agora encontra-se registrado e logado..', | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * Password Reset | ||
| 46 | + */ | ||
| 47 | + 'reset_password' => 'Resetar senha', | ||
| 48 | + 'reset_password_send_instructions' => 'Digite seu e-mail abaixo e o sistema enviará uma mensagem com o link de reset de senha.', | ||
| 49 | + 'reset_password_send_button' => 'Enviar o link de reset de senha', | ||
| 50 | + 'reset_password_sent_success' => 'Um link de reset de senha foi enviado para :email.', | ||
| 51 | + 'reset_password_success' => 'Sua senha foi resetada com sucesso.', | ||
| 52 | + | ||
| 53 | + 'email_reset_subject' => 'Resetar a senha de :appName', | ||
| 54 | + 'email_reset_text' => 'Você recebeu esse e-mail pois recebemos uma solicitação de reset de senha para sua conta.', | ||
| 55 | + 'email_reset_not_requested' => 'Caso não tenha sido você a solicitar o reset de senha, ignore esse e-mail.', | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * Email Confirmation | ||
| 60 | + */ | ||
| 61 | + 'email_confirm_subject' => 'Confirme seu e-mail para :appName', | ||
| 62 | + 'email_confirm_greeting' => 'Obrigado por se registrar em :appName!', | ||
| 63 | + 'email_confirm_text' => 'Por favor, confirme seu endereço de e-mail clicando no botão abaixo:', | ||
| 64 | + 'email_confirm_action' => 'Confirmar E-mail', | ||
| 65 | + 'email_confirm_send_error' => 'E-mail de confirmação é requerido, mas o sistema não pôde enviar a mensagem. Por favor, entre em contato com o admin para se certificar que o serviço de envio de e-mails está corretamente configurado.', | ||
| 66 | + 'email_confirm_success' => 'Seu e-mail foi confirmado!', | ||
| 67 | + 'email_confirm_resent' => 'E-mail de confirmação reenviado. Por favor, cheque sua caixa postal.', | ||
| 68 | + | ||
| 69 | + 'email_not_confirmed' => 'Endereço de e-mail não foi confirmado', | ||
| 70 | + 'email_not_confirmed_text' => 'Seu endereço de e-mail ainda não foi confirmado.', | ||
| 71 | + 'email_not_confirmed_click_link' => 'Por favor, clique no link no e-mail que foi enviado após o registro.', | ||
| 72 | + 'email_not_confirmed_resend' => 'Caso não encontre o e-mail você poderá reenviar a confirmação usando o formulário abaixo.', | ||
| 73 | + 'email_not_confirmed_resend_button' => 'Reenviar o e-mail de confirmação', | ||
| 74 | +]; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/lang/pt_BR/common.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + | ||
| 4 | + /** | ||
| 5 | + * Buttons | ||
| 6 | + */ | ||
| 7 | + 'cancel' => 'Cancelar', | ||
| 8 | + 'confirm' => 'Confirmar', | ||
| 9 | + 'back' => 'Voltar', | ||
| 10 | + 'save' => 'Salvar', | ||
| 11 | + 'continue' => 'Continuar', | ||
| 12 | + 'select' => 'Selecionar', | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * Form Labels | ||
| 16 | + */ | ||
| 17 | + 'name' => 'Nome', | ||
| 18 | + 'description' => 'Descrição', | ||
| 19 | + 'role' => 'Regra', | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * Actions | ||
| 23 | + */ | ||
| 24 | + 'actions' => 'Ações', | ||
| 25 | + 'view' => 'Visualizar', | ||
| 26 | + 'create' => 'Criar', | ||
| 27 | + 'update' => 'Atualizar', | ||
| 28 | + 'edit' => 'Editar', | ||
| 29 | + 'sort' => 'Ordenar', | ||
| 30 | + 'move' => 'Mover', | ||
| 31 | + 'delete' => 'Excluir', | ||
| 32 | + 'search' => 'Pesquisar', | ||
| 33 | + 'search_clear' => 'Limpar Pesquisa', | ||
| 34 | + 'reset' => 'Resetar', | ||
| 35 | + 'remove' => 'Remover', | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * Misc | ||
| 40 | + */ | ||
| 41 | + 'deleted_user' => 'Usuário excluído', | ||
| 42 | + 'no_activity' => 'Nenhuma atividade a mostrar', | ||
| 43 | + 'no_items' => 'Nenhum item disponível', | ||
| 44 | + 'back_to_top' => 'Voltar ao topo', | ||
| 45 | + 'toggle_details' => 'Alternar Detalhes', | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * Header | ||
| 49 | + */ | ||
| 50 | + 'view_profile' => 'Visualizar Perfil', | ||
| 51 | + 'edit_profile' => 'Editar Perfil', | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * Email Content | ||
| 55 | + */ | ||
| 56 | + 'email_action_help' => 'Se você estiver tendo problemas ao clicar o botão ":actionText", copie e cole a URL abaixo no seu navegador:', | ||
| 57 | + 'email_rights' => 'Todos os direitos reservados', | ||
| 58 | +]; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/lang/pt_BR/components.php
0 → 100644
| 1 | +<?php | ||
| 2 | +return [ | ||
| 3 | + | ||
| 4 | + /** | ||
| 5 | + * Image Manager | ||
| 6 | + */ | ||
| 7 | + 'image_select' => 'Selecionar imagem', | ||
| 8 | + 'image_all' => 'Todos', | ||
| 9 | + 'image_all_title' => 'Visualizar todas as imagens', | ||
| 10 | + 'image_book_title' => 'Visualizar imagens relacionadas a esse livro', | ||
| 11 | + 'image_page_title' => 'visualizar imagens relacionadas a essa página', | ||
| 12 | + 'image_search_hint' => 'Pesquisar imagem por nome', | ||
| 13 | + 'image_uploaded' => 'Carregado :uploadedDate', | ||
| 14 | + 'image_load_more' => 'Carregar Mais', | ||
| 15 | + 'image_image_name' => 'Nome da Imagem', | ||
| 16 | + 'image_delete_confirm' => 'Essa imagem é usada nas páginas abaixo. Clique em Excluir novamente para confirmar que você deseja mesmo eliminar a imagem.', | ||
| 17 | + 'image_select_image' => 'Selecionar Imagem', | ||
| 18 | + 'image_dropzone' => 'Arraste imagens ou clique aqui para fazer upload', | ||
| 19 | + 'images_deleted' => 'Imagens excluídas', | ||
| 20 | + 'image_preview' => 'Virtualização de Imagem', | ||
| 21 | + 'image_upload_success' => 'Upload de imagem efetuado com sucesso', | ||
| 22 | + 'image_update_success' => 'Upload de detalhes da imagem efetuado com sucesso', | ||
| 23 | + 'image_delete_success' => 'Imagem excluída com sucesso' | ||
| 24 | +]; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/lang/pt_BR/entities.php
0 → 100644
This diff is collapsed.
Click to expand it.
resources/lang/pt_BR/errors.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * Error text strings. | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | + // Permissions | ||
| 10 | + 'permission' => 'Você não tem permissões para acessar a página requerida.', | ||
| 11 | + 'permissionJson' => 'Você não tem permissão para realizar a ação requerida.', | ||
| 12 | + | ||
| 13 | + // Auth | ||
| 14 | + 'error_user_exists_different_creds' => 'Um usuário com o e-mail :email já existe mas com credenciais diferentes.', | ||
| 15 | + 'email_already_confirmed' => 'E-mail já foi confirmado. Tente efetuar o login.', | ||
| 16 | + 'email_confirmation_invalid' => 'Esse token de confirmação não é válido ou já foi utilizado. Por favor, tente efetuar o registro novamente.', | ||
| 17 | + 'email_confirmation_expired' => 'O token de confirmação já expirou. Um novo e-mail foi enviado.', | ||
| 18 | + 'ldap_fail_anonymous' => 'O acesso LDAP falhou ao tentar usar o anonymous bind', | ||
| 19 | + 'ldap_fail_authed' => 'O acesso LDAPfalou ao tentar os detalhes do dn e senha fornecidos', | ||
| 20 | + 'ldap_extension_not_installed' => 'As extensões LDAP PHP não estão instaladas', | ||
| 21 | + 'ldap_cannot_connect' => 'Não foi possível conectar ao servidor LDAP. Conexão inicial falhou', | ||
| 22 | + 'social_no_action_defined' => 'Nenhuma ação definida', | ||
| 23 | + 'social_account_in_use' => 'Essa conta :socialAccount já está em uso. Por favor, tente se logar usando a opção :socialAccount', | ||
| 24 | + 'social_account_email_in_use' => 'O e-mail :email já está e muso. Se você já tem uma conta você poderá se conectar a conta :socialAccount a partir das configurações de seu perfil.', | ||
| 25 | + 'social_account_existing' => 'Essa conta :socialAccount já está atrelada a esse perfil.', | ||
| 26 | + 'social_account_already_used_existing' => 'Essa conta :socialAccount já está sendo usada por outro usuário.', | ||
| 27 | + 'social_account_not_used' => 'Essa conta :socialAccount não está atrelada a nenhum usuário. Por favor, faça o link da conta com suas configurações de perfil. ', | ||
| 28 | + 'social_account_register_instructions' => 'Se você não tem uma conta, você poderá fazer o registro usando a opção :socialAccount', | ||
| 29 | + 'social_driver_not_found' => 'Social driver não encontrado', | ||
| 30 | + 'social_driver_not_configured' => 'Seus parâmetros socials de :socialAccount não estão configurados corretamente.', | ||
| 31 | + | ||
| 32 | + // System | ||
| 33 | + 'path_not_writable' => 'O caminho de destino (:filePath) de upload de arquivo não possui permissão de escrita. Certifique-se que ele possui direitos de escrita no servidor.', | ||
| 34 | + 'cannot_get_image_from_url' => 'Não foi possivel capturar a imagem a partir de :url', | ||
| 35 | + 'cannot_create_thumbs' => 'O servidor não pôde criar as miniaturas de imagem. Por favor, verifique se a extensão GD PHP está instalada.', | ||
| 36 | + 'server_upload_limit' => 'O servidor não permite o upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.', | ||
| 37 | + 'image_upload_error' => 'Um erro aconteceu enquanto o servidor tentava efetuar o upload da imagem', | ||
| 38 | + | ||
| 39 | + // Attachments | ||
| 40 | + 'attachment_page_mismatch' => 'Erro de \'Page mismatch\' durante a atualização do anexo', | ||
| 41 | + | ||
| 42 | + // Pages | ||
| 43 | + 'page_draft_autosave_fail' => 'Falou ao tentar salvar o rascunho. Certifique-se que a conexão de internet está funcional antes de tentar salvar essa página', | ||
| 44 | + | ||
| 45 | + // Entities | ||
| 46 | + 'entity_not_found' => 'Entidade não encontrada', | ||
| 47 | + 'book_not_found' => 'Livro não encontrado', | ||
| 48 | + 'page_not_found' => 'Página não encontrada', | ||
| 49 | + 'chapter_not_found' => 'Capítulo não encontrado', | ||
| 50 | + 'selected_book_not_found' => 'O livro selecionado não foi encontrado', | ||
| 51 | + 'selected_book_chapter_not_found' => 'O Livro selecionado ou Capítulo não foi encontrado', | ||
| 52 | + 'guests_cannot_save_drafts' => 'Convidados não podem salvar rascunhos', | ||
| 53 | + | ||
| 54 | + // Users | ||
| 55 | + 'users_cannot_delete_only_admin' => 'Você não pode excluir o conteúdo, apenas o admin.', | ||
| 56 | + 'users_cannot_delete_guest' => 'Você não pode excluir o usuário convidado', | ||
| 57 | + | ||
| 58 | + // Roles | ||
| 59 | + 'role_cannot_be_edited' => 'Esse perfil não poed ser editado', | ||
| 60 | + 'role_system_cannot_be_deleted' => 'Esse perfil é um perfil de sistema e não pode ser excluído', | ||
| 61 | + 'role_registration_default_cannot_delete' => 'Esse perfil não poderá se excluído enquando estiver registrado como o perfil padrão', | ||
| 62 | + | ||
| 63 | + // Error pages | ||
| 64 | + '404_page_not_found' => 'Página não encontrada', | ||
| 65 | + 'sorry_page_not_found' => 'Desculpe, a página que você está procurando não pôde ser encontrada.', | ||
| 66 | + 'return_home' => 'Retornar à página principal', | ||
| 67 | + 'error_occurred' => 'Um erro ocorreu', | ||
| 68 | + 'app_down' => ':appName está fora do ar no momento', | ||
| 69 | + 'back_soon' => 'Voltaremos em seguida.', | ||
| 70 | +]; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/lang/pt_BR/pagination.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /* | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | Pagination Language Lines | ||
| 8 | + |-------------------------------------------------------------------------- | ||
| 9 | + | | ||
| 10 | + | The following language lines are used by the paginator library to build | ||
| 11 | + | the simple pagination links. You are free to change them to anything | ||
| 12 | + | you want to customize your views to better match your application. | ||
| 13 | + | | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + 'previous' => '« Anterior', | ||
| 17 | + 'next' => 'Próximo »', | ||
| 18 | + | ||
| 19 | +]; |
resources/lang/pt_BR/passwords.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +return [ | ||
| 4 | + | ||
| 5 | + /* | ||
| 6 | + |-------------------------------------------------------------------------- | ||
| 7 | + | Password Reminder Language Lines | ||
| 8 | + |-------------------------------------------------------------------------- | ||
| 9 | + | | ||
| 10 | + | The following language lines are the default lines which match reasons | ||
| 11 | + | that are given by the password broker for a password update attempt | ||
| 12 | + | has failed, such as for an invalid token or invalid new password. | ||
| 13 | + | | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + 'password' => 'Senhas devem ter ao menos 6 caraceres e combinar com os atributos mínimos para a senha.', | ||
| 17 | + 'user' => "Não pudemos encontrar um usuário com o e-mail fornecido.", | ||
| 18 | + 'token' => 'O token de reset de senha é inválido.', | ||
| 19 | + 'sent' => 'Enviamos para seu e-mail o link de reset de senha!', | ||
| 20 | + 'reset' => 'Sua senha foi resetada com sucesso!', | ||
| 21 | + | ||
| 22 | +]; |
resources/lang/pt_BR/settings.php
0 → 100644
This diff is collapsed.
Click to expand it.
resources/lang/pt_BR/validation.php
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
resources/views/books/_breadcrumbs.blade.php
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
resources/views/pages/_breadcrumbs.blade.php
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
tests/Entity/PageContentTest.php
0 → 100644
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
-
Please register or sign in to post a comment