Merge branch 'master' into release

This commit is contained in:
Dan Brown 2022-01-10 18:23:19 +00:00
commit ed08bbcecc
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
24 changed files with 157 additions and 104 deletions

View File

@ -210,3 +210,4 @@ Tomáš Batelka (Vofy) :: Czech
Mundo Racional (ismael.mesquita) :: Portuguese, Brazilian Mundo Racional (ismael.mesquita) :: Portuguese, Brazilian
Zarik (3apuk) :: Russian Zarik (3apuk) :: Russian
Ali Shaatani (a.shaatani) :: Arabic Ali Shaatani (a.shaatani) :: Arabic
ChacMaster :: Portuguese, Brazilian

View File

@ -59,7 +59,7 @@ class Deletion extends Model implements Loggable
/** /**
* Get a URL for this specific deletion. * Get a URL for this specific deletion.
*/ */
public function getUrl($path): string public function getUrl(string $path = 'restore'): string
{ {
return url("/settings/recycle-bin/{$this->id}/" . ltrim($path, '/')); return url("/settings/recycle-bin/{$this->id}/" . ltrim($path, '/'));
} }

View File

@ -36,6 +36,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property string $slug * @property string $slug
* @property Carbon $created_at * @property Carbon $created_at
* @property Carbon $updated_at * @property Carbon $updated_at
* @property Carbon $deleted_at
* @property int $created_by * @property int $created_by
* @property int $updated_by * @property int $updated_by
* @property bool $restricted * @property bool $restricted

View File

@ -46,19 +46,10 @@ class PageRevision extends Model
/** /**
* Get the url for this revision. * Get the url for this revision.
*
* @param null|string $path
*
* @return string
*/ */
public function getUrl($path = null) public function getUrl(string $path = ''): string
{ {
$url = $this->page->getUrl() . '/revisions/' . $this->id; return $this->page->getUrl('/revisions/' . $this->id . '/' . ltrim($path, '/'));
if ($path) {
return $url . '/' . trim($path, '/');
}
return $url;
} }
/** /**

View File

@ -24,7 +24,7 @@ class BookSortMap
public static function fromJson(string $json): self public static function fromJson(string $json): self
{ {
$map = new static(); $map = new BookSortMap();
$mapData = json_decode($json); $mapData = json_decode($json);
foreach ($mapData as $mapDataItem) { foreach ($mapData as $mapDataItem) {

View File

@ -22,9 +22,12 @@ class TrashCan
{ {
/** /**
* Send a shelf to the recycle bin. * Send a shelf to the recycle bin.
*
* @throws NotifyException
*/ */
public function softDestroyShelf(Bookshelf $shelf) public function softDestroyShelf(Bookshelf $shelf)
{ {
$this->ensureDeletable($shelf);
Deletion::createForEntity($shelf); Deletion::createForEntity($shelf);
$shelf->delete(); $shelf->delete();
} }
@ -36,6 +39,7 @@ class TrashCan
*/ */
public function softDestroyBook(Book $book) public function softDestroyBook(Book $book)
{ {
$this->ensureDeletable($book);
Deletion::createForEntity($book); Deletion::createForEntity($book);
foreach ($book->pages as $page) { foreach ($book->pages as $page) {
@ -57,6 +61,7 @@ class TrashCan
public function softDestroyChapter(Chapter $chapter, bool $recordDelete = true) public function softDestroyChapter(Chapter $chapter, bool $recordDelete = true)
{ {
if ($recordDelete) { if ($recordDelete) {
$this->ensureDeletable($chapter);
Deletion::createForEntity($chapter); Deletion::createForEntity($chapter);
} }
@ -77,19 +82,47 @@ class TrashCan
public function softDestroyPage(Page $page, bool $recordDelete = true) public function softDestroyPage(Page $page, bool $recordDelete = true)
{ {
if ($recordDelete) { if ($recordDelete) {
$this->ensureDeletable($page);
Deletion::createForEntity($page); Deletion::createForEntity($page);
} }
// Check if set as custom homepage & remove setting if not used or throw error if active $page->delete();
$customHome = setting('app-homepage', '0:'); }
if (intval($page->id) === intval(explode(':', $customHome)[0])) {
if (setting('app-homepage-type') === 'page') { /**
throw new NotifyException(trans('errors.page_custom_home_deletion'), $page->getUrl()); * Ensure the given entity is deletable.
* Is not for permissions, but logical conditions within the application.
* Will throw if not deletable.
*
* @throws NotifyException
*/
protected function ensureDeletable(Entity $entity): void
{
$customHomeId = intval(explode(':', setting('app-homepage', '0:'))[0]);
$customHomeActive = setting('app-homepage-type') === 'page';
$removeCustomHome = false;
// Check custom homepage usage for pages
if ($entity instanceof Page && $entity->id === $customHomeId) {
if ($customHomeActive) {
throw new NotifyException(trans('errors.page_custom_home_deletion'), $entity->getUrl());
} }
setting()->remove('app-homepage'); $removeCustomHome = true;
} }
$page->delete(); // Check custom homepage usage within chapters or books
if ($entity instanceof Chapter || $entity instanceof Book) {
if ($entity->pages()->where('id', '=', $customHomeId)->exists()) {
if ($customHomeActive) {
throw new NotifyException(trans('errors.page_custom_home_deletion'), $entity->getUrl());
}
$removeCustomHome = true;
}
}
if ($removeCustomHome) {
setting()->remove('app-homepage');
}
} }
/** /**

View File

@ -48,6 +48,8 @@ abstract class Controller extends BaseController
/** /**
* On a permission error redirect to home and display. * On a permission error redirect to home and display.
* the error as a notification. * the error as a notification.
*
* @return never
*/ */
protected function showPermissionError() protected function showPermissionError()
{ {

BIN
public/loading_error.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -74,6 +74,10 @@ class ImageManager {
this.listContainer.addEventListener('event-emit-select-image', this.onImageSelectEvent.bind(this)); this.listContainer.addEventListener('event-emit-select-image', this.onImageSelectEvent.bind(this));
this.listContainer.addEventListener('error', event => {
event.target.src = baseUrl('loading_error.png');
}, true);
onSelect(this.selectButton, () => { onSelect(this.selectButton, () => {
if (this.callback) { if (this.callback) {
this.callback(this.lastSelected); this.callback(this.lastSelected);

View File

@ -395,8 +395,9 @@ class MarkdownEditor {
actionInsertImage() { actionInsertImage() {
const cursorPos = this.cm.getCursor('from'); const cursorPos = this.cm.getCursor('from');
window.ImageManager.show(image => { window.ImageManager.show(image => {
const imageUrl = image.thumbs.display || image.url;
let selectedText = this.cm.getSelection(); let selectedText = this.cm.getSelection();
let newText = "[![" + (selectedText || image.name) + "](" + image.thumbs.display + ")](" + image.url + ")"; let newText = "[![" + (selectedText || image.name) + "](" + imageUrl + ")](" + image.url + ")";
this.cm.focus(); this.cm.focus();
this.cm.replaceSelection(newText); this.cm.replaceSelection(newText);
this.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length); this.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length);

View File

@ -563,8 +563,9 @@ class WysiwygEditor {
} }
// Replace the actively selected content with the linked image // Replace the actively selected content with the linked image
const imageUrl = image.thumbs.display || image.url;
let html = `<a href="${image.url}" target="_blank">`; let html = `<a href="${image.url}" target="_blank">`;
html += `<img src="${image.thumbs.display}" alt="${image.name}">`; html += `<img src="${imageUrl}" alt="${image.name}">`;
html += '</a>'; html += '</a>';
win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html); win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html);
}, 'gallery'); }, 'gallery');
@ -723,8 +724,9 @@ class WysiwygEditor {
tooltip: 'Insert an image', tooltip: 'Insert an image',
onclick: function () { onclick: function () {
window.ImageManager.show(function (image) { window.ImageManager.show(function (image) {
const imageUrl = image.thumbs.display || image.url;
let html = `<a href="${image.url}" target="_blank">`; let html = `<a href="${image.url}" target="_blank">`;
html += `<img src="${image.thumbs.display}" alt="${image.name}">`; html += `<img src="${imageUrl}" alt="${image.name}">`;
html += '</a>'; html += '</a>';
editor.execCommand('mceInsertContent', false, html); editor.execCommand('mceInsertContent', false, html);
}, 'gallery'); }, 'gallery');

View File

@ -74,7 +74,7 @@ return [
'status' => 'Stav', 'status' => 'Stav',
'status_active' => 'Aktivní', 'status_active' => 'Aktivní',
'status_inactive' => 'Neaktivní', 'status_inactive' => 'Neaktivní',
'never' => 'Never', 'never' => 'Nikdy',
// Header // Header
'header_menu_expand' => 'Rozbalit menu v záhlaví', 'header_menu_expand' => 'Rozbalit menu v záhlaví',

View File

@ -64,7 +64,7 @@ return [
'email_not_confirmed_resend_button' => 'Reenviar Correo Electrónico de confirmación', 'email_not_confirmed_resend_button' => 'Reenviar Correo Electrónico de confirmación',
// User Invite // User Invite
'user_invite_email_subject' => 'As sido invitado a unirte a :appName!', 'user_invite_email_subject' => 'Has sido invitado a unirte a :appName!',
'user_invite_email_greeting' => 'Se ha creado una cuenta para usted en :appName.', 'user_invite_email_greeting' => 'Se ha creado una cuenta para usted en :appName.',
'user_invite_email_text' => 'Clica en el botón a continuación para ajustar una contraseña y poder acceder:', 'user_invite_email_text' => 'Clica en el botón a continuación para ajustar una contraseña y poder acceder:',
'user_invite_email_action' => 'Ajustar la Contraseña de la Cuenta', 'user_invite_email_action' => 'Ajustar la Contraseña de la Cuenta',

View File

@ -21,7 +21,7 @@ return [
'email' => 'メールアドレス', 'email' => 'メールアドレス',
'password' => 'パスワード', 'password' => 'パスワード',
'password_confirm' => 'パスワード (確認)', 'password_confirm' => 'パスワード (確認)',
'password_hint' => 'Must be at least 8 characters', 'password_hint' => '8文字以上で設定する必要があります',
'forgot_password' => 'パスワードをお忘れですか?', 'forgot_password' => 'パスワードをお忘れですか?',
'remember_me' => 'ログイン情報を保存する', 'remember_me' => 'ログイン情報を保存する',
'ldap_email_hint' => 'このアカウントで使用するEメールアドレスを入力してください。', 'ldap_email_hint' => 'このアカウントで使用するEメールアドレスを入力してください。',
@ -54,7 +54,7 @@ return [
'email_confirm_text' => '以下のボタンを押し、メールアドレスを確認してください:', 'email_confirm_text' => '以下のボタンを押し、メールアドレスを確認してください:',
'email_confirm_action' => 'メールアドレスを確認', 'email_confirm_action' => 'メールアドレスを確認',
'email_confirm_send_error' => 'Eメールの確認が必要でしたが、システム上でEメールの送信ができませんでした。管理者に連絡し、Eメールが正しく設定されていることを確認してください。', 'email_confirm_send_error' => 'Eメールの確認が必要でしたが、システム上でEメールの送信ができませんでした。管理者に連絡し、Eメールが正しく設定されていることを確認してください。',
'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.', 'email_confirm_success' => 'メールアドレスが確認されました!このメールアドレスでログインできるようになりました。',
'email_confirm_resent' => '確認メールを再送信しました。受信トレイを確認してください。', 'email_confirm_resent' => '確認メールを再送信しました。受信トレイを確認してください。',
'email_not_confirmed' => 'Eメールアドレスが確認できていません', 'email_not_confirmed' => 'Eメールアドレスが確認できていません',
@ -71,7 +71,7 @@ return [
'user_invite_page_welcome' => ':appNameへようこそ', 'user_invite_page_welcome' => ':appNameへようこそ',
'user_invite_page_text' => 'アカウントの設定を完了してアクセスするには、今後の訪問時に:appNameにログインするためのパスワードを設定する必要があります。', 'user_invite_page_text' => 'アカウントの設定を完了してアクセスするには、今後の訪問時に:appNameにログインするためのパスワードを設定する必要があります。',
'user_invite_page_confirm_button' => 'パスワードを確定', 'user_invite_page_confirm_button' => 'パスワードを確定',
'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!', 'user_invite_success_login' => 'パスワードが設定されました。設定したパスワードで:appNameにログインできるようになりました',
// Multi-factor Authentication // Multi-factor Authentication
'mfa_setup' => '多要素認証を設定', 'mfa_setup' => '多要素認証を設定',

View File

@ -85,10 +85,10 @@ return [
'light_mode' => 'ライトモード', 'light_mode' => 'ライトモード',
// Layout tabs // Layout tabs
'tab_info' => 'Info', 'tab_info' => '情報',
'tab_info_label' => 'Tab: Show Secondary Information', 'tab_info_label' => 'タブ: サブコンテンツを表示',
'tab_content' => 'Content', 'tab_content' => '内容',
'tab_content_label' => 'Tab: Show Primary Content', 'tab_content_label' => 'タブ: メインコンテンツを表示',
// Email Content // Email Content
'email_action_help' => '":actionText" をクリックできない場合、以下のURLをコピーしブラウザで開いてください:', 'email_action_help' => '":actionText" をクリックできない場合、以下のURLをコピーしブラウザで開いてください:',

View File

@ -22,7 +22,7 @@ return [
'meta_created_name' => '作成: :timeLength (:user)', 'meta_created_name' => '作成: :timeLength (:user)',
'meta_updated' => '更新: :timeLength', 'meta_updated' => '更新: :timeLength',
'meta_updated_name' => '更新: :timeLength (:user)', 'meta_updated_name' => '更新: :timeLength (:user)',
'meta_owned_name' => 'Owned by :user', 'meta_owned_name' => '所有者: :user',
'entity_select' => 'エンティティ選択', 'entity_select' => 'エンティティ選択',
'images' => '画像', 'images' => '画像',
'my_recent_drafts' => '最近の下書き', 'my_recent_drafts' => '最近の下書き',
@ -36,14 +36,14 @@ return [
'export_html' => 'Webページ', 'export_html' => 'Webページ',
'export_pdf' => 'PDF', 'export_pdf' => 'PDF',
'export_text' => 'テキストファイル', 'export_text' => 'テキストファイル',
'export_md' => 'Markdown File', 'export_md' => 'Markdown',
// Permissions and restrictions // Permissions and restrictions
'permissions' => '権限', 'permissions' => '権限',
'permissions_intro' => 'この設定は各ユーザの役割よりも優先して適用されます。', 'permissions_intro' => 'この設定は各ユーザの役割よりも優先して適用されます。',
'permissions_enable' => 'カスタム権限設定を有効にする', 'permissions_enable' => 'カスタム権限設定を有効にする',
'permissions_save' => '権限を保存', 'permissions_save' => '権限を保存',
'permissions_owner' => 'Owner', 'permissions_owner' => '所有者',
// Search // Search
'search_results' => '検索結果', 'search_results' => '検索結果',
@ -143,8 +143,8 @@ return [
'books_sort_chapters_last' => 'チャプターを後に', 'books_sort_chapters_last' => 'チャプターを後に',
'books_sort_show_other' => '他のブックを表示', 'books_sort_show_other' => '他のブックを表示',
'books_sort_save' => '並び順を保存', 'books_sort_save' => '並び順を保存',
'books_copy' => 'Copy Book', 'books_copy' => 'ブックをコピー',
'books_copy_success' => 'Book successfully copied', 'books_copy_success' => 'ブックが正常にコピーされました',
// Chapters // Chapters
'chapter' => 'チャプター', 'chapter' => 'チャプター',
@ -163,8 +163,8 @@ return [
'chapters_move' => 'チャプターを移動', 'chapters_move' => 'チャプターを移動',
'chapters_move_named' => 'チャプター「:chapterName」を移動', 'chapters_move_named' => 'チャプター「:chapterName」を移動',
'chapter_move_success' => 'チャプターを「:bookName」に移動しました', 'chapter_move_success' => 'チャプターを「:bookName」に移動しました',
'chapters_copy' => 'Copy Chapter', 'chapters_copy' => 'チャプターをコピー',
'chapters_copy_success' => 'Chapter successfully copied', 'chapters_copy_success' => 'チャプターが正常にコピーされました',
'chapters_permissions' => 'チャプター権限', 'chapters_permissions' => 'チャプター権限',
'chapters_empty' => 'まだチャプター内にページはありません。', 'chapters_empty' => 'まだチャプター内にページはありません。',
'chapters_permissions_active' => 'チャプターの権限は有効です', 'chapters_permissions_active' => 'チャプターの権限は有効です',
@ -215,16 +215,16 @@ return [
'pages_copy_success' => 'ページが正常にコピーされました', 'pages_copy_success' => 'ページが正常にコピーされました',
'pages_permissions' => 'ページの権限設定', 'pages_permissions' => 'ページの権限設定',
'pages_permissions_success' => 'ページの権限を更新しました', 'pages_permissions_success' => 'ページの権限を更新しました',
'pages_revision' => 'Revision', 'pages_revision' => '編集履歴',
'pages_revisions' => '編集履歴', 'pages_revisions' => '編集履歴',
'pages_revisions_named' => ':pageName のリビジョン', 'pages_revisions_named' => ':pageName のリビジョン',
'pages_revision_named' => ':pageName のリビジョン', 'pages_revision_named' => ':pageName のリビジョン',
'pages_revision_restored_from' => 'Restored from #:id; :summary', 'pages_revision_restored_from' => '#:id :summary から復元',
'pages_revisions_created_by' => '作成者', 'pages_revisions_created_by' => '作成者',
'pages_revisions_date' => '日付', 'pages_revisions_date' => '日付',
'pages_revisions_number' => '#', 'pages_revisions_number' => '#',
'pages_revisions_numbered' => 'Revision #:id', 'pages_revisions_numbered' => 'リビジョン #:id',
'pages_revisions_numbered_changes' => 'Revision #:id Changes', 'pages_revisions_numbered_changes' => 'リビジョン #:id の変更',
'pages_revisions_changelog' => '説明', 'pages_revisions_changelog' => '説明',
'pages_revisions_changes' => '変更点', 'pages_revisions_changes' => '変更点',
'pages_revisions_current' => '現在のバージョン', 'pages_revisions_current' => '現在のバージョン',
@ -333,15 +333,15 @@ return [
// Revision // Revision
'revision_delete_confirm' => 'このリビジョンを削除しますか?', 'revision_delete_confirm' => 'このリビジョンを削除しますか?',
'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', 'revision_restore_confirm' => 'このリビジョンを復元してよろしいですか?現在のページの内容が置換されます。',
'revision_delete_success' => 'リビジョンを削除しました', 'revision_delete_success' => 'リビジョンを削除しました',
'revision_cannot_delete_latest' => '最新のリビジョンを削除できません。', 'revision_cannot_delete_latest' => '最新のリビジョンを削除できません。',
// Copy view // Copy view
'copy_consider' => 'Please consider the below when copying content.', 'copy_consider' => 'コンテンツをコピーする場合は以下の点にご注意ください。',
'copy_consider_permissions' => 'Custom permission settings will not be copied.', 'copy_consider_permissions' => 'カスタム権限設定はコピーされません。',
'copy_consider_owner' => 'You will become the owner of all copied content.', 'copy_consider_owner' => 'あなたはコピーされた全てのコンテンツの所有者になります。',
'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', 'copy_consider_images' => 'ページの画像ファイルは複製されず、元の画像は最初にアップロードされたページとの関係を保持します。',
'copy_consider_attachments' => 'Page attachments will not be copied.', 'copy_consider_attachments' => 'ページの添付ファイルはコピーされません。',
'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.', 'copy_consider_access' => '場所、所有者または権限を変更すると、以前アクセスできなかったユーザーがこのコンテンツにアクセスできるようになる可能性があります。',
]; ];

View File

@ -99,7 +99,7 @@ return [
'api_no_authorization_found' => 'リクエストに認証トークンが見つかりません', 'api_no_authorization_found' => 'リクエストに認証トークンが見つかりません',
'api_bad_authorization_format' => 'リクエストに認証トークンが見つかりましたが、形式が正しくないようです', 'api_bad_authorization_format' => 'リクエストに認証トークンが見つかりましたが、形式が正しくないようです',
'api_user_token_not_found' => '提供された認証トークンに一致するAPIトークンが見つかりませんでした', 'api_user_token_not_found' => '提供された認証トークンに一致するAPIトークンが見つかりませんでした',
'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', 'api_incorrect_token_secret' => '利用されたAPIトークンに対して提供されたシークレットが正しくありません',
'api_user_no_api_permission' => '使用されているAPIトークンの所有者には、API呼び出しを行う権限がありません', 'api_user_no_api_permission' => '使用されているAPIトークンの所有者には、API呼び出しを行う権限がありません',
'api_user_token_expired' => '認証トークンが期限切れです。', 'api_user_token_expired' => '認証トークンが期限切れです。',

View File

@ -234,27 +234,27 @@ return [
'user_api_token_delete_success' => 'APIトークンが正常に削除されました', 'user_api_token_delete_success' => 'APIトークンが正常に削除されました',
// Webhooks // Webhooks
'webhooks' => 'Webhooks', 'webhooks' => 'Webhook',
'webhooks_create' => 'Create New Webhook', 'webhooks_create' => 'Webhookを作成',
'webhooks_none_created' => 'No webhooks have yet been created.', 'webhooks_none_created' => 'Webhookはまだ作成されていません。',
'webhooks_edit' => 'Edit Webhook', 'webhooks_edit' => 'Webhookを編集',
'webhooks_save' => 'Save Webhook', 'webhooks_save' => 'Webhookを保存',
'webhooks_details' => 'Webhook Details', 'webhooks_details' => 'Webhookの詳細',
'webhooks_details_desc' => 'Provide a user friendly name and a POST endpoint as a location for the webhook data to be sent to.', 'webhooks_details_desc' => 'ユーザーフレンドリーな名前とWebhookデータの送信先にするPOSTエンドポイントを指定します。',
'webhooks_events' => 'Webhook Events', 'webhooks_events' => 'Webhookのイベント',
'webhooks_events_desc' => 'Select all the events that should trigger this webhook to be called.', 'webhooks_events_desc' => 'このWebhookの呼び出しをトリガーするすべてのイベントを選択します。',
'webhooks_events_warning' => 'Keep in mind that these events will be triggered for all selected events, even if custom permissions are applied. Ensure that use of this webhook won\'t expose confidential content.', 'webhooks_events_warning' => 'これらのイベントはカスタム権限が適用されている場合でも、選択したすべてのイベントに対してトリガーされることに注意してください。このWebhookの利用により機密コンテンツが公開されないことを確認してください。',
'webhooks_events_all' => 'All system events', 'webhooks_events_all' => '全てのシステムイベント',
'webhooks_name' => 'Webhook Name', 'webhooks_name' => 'Webhook',
'webhooks_timeout' => 'Webhook Request Timeout (Seconds)', 'webhooks_timeout' => 'Webhookリクエストタイムアウト (秒)',
'webhooks_endpoint' => 'Webhook Endpoint', 'webhooks_endpoint' => 'Webhookエンドポイント',
'webhooks_active' => 'Webhook Active', 'webhooks_active' => 'Webhook Active',
'webhook_events_table_header' => 'Events', 'webhook_events_table_header' => 'Events',
'webhooks_delete' => 'Delete Webhook', 'webhooks_delete' => 'Delete Webhook',
'webhooks_delete_warning' => 'This will fully delete this webhook, with the name \':webhookName\', from the system.', 'webhooks_delete_warning' => 'This will fully delete this webhook, with the name \':webhookName\', from the system.',
'webhooks_delete_confirm' => 'Are you sure you want to delete this webhook?', 'webhooks_delete_confirm' => 'Are you sure you want to delete this webhook?',
'webhooks_format_example' => 'Webhook Format Example', 'webhooks_format_example' => 'Webhookのフォーマット例',
'webhooks_format_example_desc' => 'Webhook data is sent as a POST request to the configured endpoint as JSON following the format below. The "related_item" and "url" properties are optional and will depend on the type of event triggered.', 'webhooks_format_example_desc' => 'Webhookのデータは、設定されたエンドポイントにPOSTリクエストにより以下のフォーマットのJSONで送信されます。related_item と url プロパティはオプションであり、トリガーされるイベントの種類によって異なります。',
'webhooks_status' => 'Webhook Status', 'webhooks_status' => 'Webhook Status',
'webhooks_last_called' => 'Last Called:', 'webhooks_last_called' => 'Last Called:',
'webhooks_last_errored' => 'Last Errored:', 'webhooks_last_errored' => 'Last Errored:',

View File

@ -7,57 +7,57 @@ return [
// Pages // Pages
'page_create' => 'criou a página', 'page_create' => 'criou a página',
'page_create_notification' => 'Page successfully created', 'page_create_notification' => 'Página criada com sucesso',
'page_update' => 'atualizou a página', 'page_update' => 'atualizou a página',
'page_update_notification' => 'Page successfully updated', 'page_update_notification' => 'Página atualizada com sucesso',
'page_delete' => 'excluiu a página', 'page_delete' => 'excluiu a página',
'page_delete_notification' => 'Page successfully deleted', 'page_delete_notification' => 'Página excluída com sucesso',
'page_restore' => 'restaurou a página', 'page_restore' => 'restaurou a página',
'page_restore_notification' => 'Page successfully restored', 'page_restore_notification' => 'Página restaurada com sucesso',
'page_move' => 'moveu a página', 'page_move' => 'moveu a página',
// Chapters // Chapters
'chapter_create' => 'criou o capítulo', 'chapter_create' => 'criou o capítulo',
'chapter_create_notification' => 'Chapter successfully created', 'chapter_create_notification' => 'Capítulo criado com sucesso',
'chapter_update' => 'atualizou o capítulo', 'chapter_update' => 'atualizou o capítulo',
'chapter_update_notification' => 'Chapter successfully updated', 'chapter_update_notification' => 'Capítulo atualizado com sucesso',
'chapter_delete' => 'excluiu o capítulo', 'chapter_delete' => 'excluiu o capítulo',
'chapter_delete_notification' => 'Chapter successfully deleted', 'chapter_delete_notification' => 'Capítulo excluída com sucesso',
'chapter_move' => 'moveu o capítulo', 'chapter_move' => 'moveu o capítulo',
// Books // Books
'book_create' => 'criou o livro', 'book_create' => 'criou o livro',
'book_create_notification' => 'Book successfully created', 'book_create_notification' => 'Livro criado com sucesso',
'book_update' => 'atualizou o livro', 'book_update' => 'atualizou o livro',
'book_update_notification' => 'Book successfully updated', 'book_update_notification' => 'Livro atualizado com sucesso',
'book_delete' => 'excluiu o livro', 'book_delete' => 'excluiu o livro',
'book_delete_notification' => 'Book successfully deleted', 'book_delete_notification' => 'Livro excluído com sucesso',
'book_sort' => 'ordenou o livro', 'book_sort' => 'ordenou o livro',
'book_sort_notification' => 'Book successfully re-sorted', 'book_sort_notification' => 'Livro reordenado com sucesso',
// Bookshelves // Bookshelves
'bookshelf_create' => 'created bookshelf', 'bookshelf_create' => 'prateleira criada',
'bookshelf_create_notification' => 'Bookshelf successfully created', 'bookshelf_create_notification' => 'Prateleira criada com sucesso',
'bookshelf_update' => 'atualizou a prateleira', 'bookshelf_update' => 'atualizou a prateleira',
'bookshelf_update_notification' => 'Bookshelf successfully updated', 'bookshelf_update_notification' => 'Prateleira atualizada com sucesso',
'bookshelf_delete' => 'excluiu a prateleira', 'bookshelf_delete' => 'excluiu a prateleira',
'bookshelf_delete_notification' => 'Bookshelf successfully deleted', 'bookshelf_delete_notification' => 'Prateleira excluída com sucesso',
// Favourites // Favourites
'favourite_add_notification' => '":name" has been added to your favourites', 'favourite_add_notification' => '":name" foi adicionada aos seus favoritos',
'favourite_remove_notification' => '":name" has been removed from your favourites', 'favourite_remove_notification' => '":name" foi removida dos seus favoritos',
// MFA // MFA
'mfa_setup_method_notification' => 'Multi-factor method successfully configured', 'mfa_setup_method_notification' => 'Método de multi-fatores configurado com sucesso',
'mfa_remove_method_notification' => 'Multi-factor method successfully removed', 'mfa_remove_method_notification' => 'Método de multi-fatores removido com sucesso',
// Webhooks // Webhooks
'webhook_create' => 'created webhook', 'webhook_create' => 'webhook criado',
'webhook_create_notification' => 'Webhook successfully created', 'webhook_create_notification' => 'Webhook criado com sucesso',
'webhook_update' => 'updated webhook', 'webhook_update' => 'webhook atualizado',
'webhook_update_notification' => 'Webhook successfully updated', 'webhook_update_notification' => 'Webhook atualizado com sucesso',
'webhook_delete' => 'deleted webhook', 'webhook_delete' => 'webhook excluído',
'webhook_delete_notification' => 'Webhook successfully deleted', 'webhook_delete_notification' => 'Webhook excluido com sucesso',
// Other // Other
'commented_on' => 'comentou em', 'commented_on' => 'comentou em',

View File

@ -39,14 +39,14 @@ return [
'reset' => 'Redefinir', 'reset' => 'Redefinir',
'remove' => 'Remover', 'remove' => 'Remover',
'add' => 'Adicionar', 'add' => 'Adicionar',
'configure' => 'Configure', 'configure' => 'Configurar',
'fullscreen' => 'Tela cheia', 'fullscreen' => 'Tela cheia',
'favourite' => 'Favoritos', 'favourite' => 'Favoritos',
'unfavourite' => 'Remover dos Favoritos', 'unfavourite' => 'Remover dos Favoritos',
'next' => 'Seguinte', 'next' => 'Seguinte',
'previous' => 'Anterior', 'previous' => 'Anterior',
'filter_active' => 'Active Filter:', 'filter_active' => 'Filtro Ativo:',
'filter_clear' => 'Clear Filter', 'filter_clear' => 'Limpar Filtro',
// Sort Options // Sort Options
'sort_options' => 'Opções de Ordenação', 'sort_options' => 'Opções de Ordenação',
@ -72,12 +72,12 @@ return [
'default' => 'Padrão', 'default' => 'Padrão',
'breadcrumb' => 'Caminho', 'breadcrumb' => 'Caminho',
'status' => 'Status', 'status' => 'Status',
'status_active' => 'Active', 'status_active' => 'Ativo',
'status_inactive' => 'Inactive', 'status_inactive' => 'Inativo',
'never' => 'Never', 'never' => 'Nunca',
// Header // Header
'header_menu_expand' => 'Expand Header Menu', 'header_menu_expand' => 'Expandir Cabeçalho do Menu',
'profile_menu' => 'Menu de Perfil', 'profile_menu' => 'Menu de Perfil',
'view_profile' => 'Visualizar Perfil', 'view_profile' => 'Visualizar Perfil',
'edit_profile' => 'Editar Perfil', 'edit_profile' => 'Editar Perfil',
@ -86,9 +86,9 @@ return [
// Layout tabs // Layout tabs
'tab_info' => 'Informações', 'tab_info' => 'Informações',
'tab_info_label' => 'Tab: Show Secondary Information', 'tab_info_label' => 'Aba: Mostrar Informação Secundária',
'tab_content' => 'Conteúdo', 'tab_content' => 'Conteúdo',
'tab_content_label' => 'Tab: Show Primary Content', 'tab_content_label' => 'Aba: Mostrar Conteúdo Primário',
// Email Content // Email Content
'email_action_help' => 'Se você estiver tendo problemas ao clicar o botão ":actionText", copie e cole a URL abaixo no seu navegador:', 'email_action_help' => 'Se você estiver tendo problemas ao clicar o botão ":actionText", copie e cole a URL abaixo no seu navegador:',

View File

@ -74,7 +74,7 @@ return [
'status' => '状态', 'status' => '状态',
'status_active' => '已激活', 'status_active' => '已激活',
'status_inactive' => '未激活', 'status_inactive' => '未激活',
'never' => '永不', 'never' => '从未',
// Header // Header
'header_menu_expand' => '展开标头菜单', 'header_menu_expand' => '展开标头菜单',

View File

@ -236,7 +236,7 @@ return [
// Webhooks // Webhooks
'webhooks' => 'Webhooks', 'webhooks' => 'Webhooks',
'webhooks_create' => '新建 Webhook', 'webhooks_create' => '新建 Webhook',
'webhooks_none_created' => '不存在已创建的 webhooks', 'webhooks_none_created' => '尚未创建任何 webhook',
'webhooks_edit' => '编辑 Webhook', 'webhooks_edit' => '编辑 Webhook',
'webhooks_save' => '保存 Webhook', 'webhooks_save' => '保存 Webhook',
'webhooks_details' => 'Webhook 详情', 'webhooks_details' => 'Webhook 详情',

View File

@ -8,7 +8,7 @@
<div class="image-manager-viewer"> <div class="image-manager-viewer">
<a href="{{ $image->url }}" target="_blank" rel="noopener" class="block"> <a href="{{ $image->url }}" target="_blank" rel="noopener" class="block">
<img src="{{ $image->thumbs['display'] }}" <img src="{{ $image->thumbs['display'] ?? $image->url }}"
alt="{{ $image->name }}" alt="{{ $image->name }}"
class="anim fadeIn" class="anim fadeIn"
title="{{ $image->name }}"> title="{{ $image->name }}">

View File

@ -79,6 +79,24 @@ class HomepageTest extends TestCase
$pageDeleteReq->assertSessionMissing('error'); $pageDeleteReq->assertSessionMissing('error');
} }
public function test_custom_homepage_cannot_be_deleted_from_parent_deletion()
{
/** @var Page $page */
$page = Page::query()->first();
$this->setSettings([
'app-homepage' => $page->id,
'app-homepage-type' => 'page',
]);
$this->asEditor()->delete($page->book->getUrl());
$this->assertSessionError('Cannot delete a page while it is set as a homepage');
$this->assertDatabaseMissing('deletions', ['deletable_id' => $page->book->id]);
$page->refresh();
$this->assertNull($page->deleted_at);
$this->assertNull($page->book->deleted_at);
}
public function test_custom_homepage_renders_includes() public function test_custom_homepage_renders_includes()
{ {
$this->asEditor(); $this->asEditor();