mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-02-19 03:09:39 +03:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a22af7b14 | ||
|
|
b54702ab08 | ||
|
|
a7e3c26fe3 | ||
|
|
37de4e2e0a | ||
|
|
61a911dd39 | ||
|
|
cc5d0ef4cf | ||
|
|
7843d8f054 | ||
|
|
c4fdcfc5d1 | ||
|
|
cb8117e8df | ||
|
|
d547ed4a6b | ||
|
|
5a218d5056 | ||
|
|
8dbc5cf9c6 | ||
|
|
d33f136660 | ||
|
|
173dad345e | ||
|
|
47b0eb6324 | ||
|
|
c35c37008d |
1
.github/translators.txt
vendored
1
.github/translators.txt
vendored
@@ -133,3 +133,4 @@ MatthieuParis :: French
|
||||
Douradinho :: Portuguese, Brazilian
|
||||
Gaku Yaguchi (tama11) :: Japanese
|
||||
johnroyer :: Chinese Traditional
|
||||
jackaaa :: Chinese Traditional
|
||||
|
||||
@@ -177,17 +177,13 @@ class PageRepo
|
||||
// Hold the old details to compare later
|
||||
$oldHtml = $page->html;
|
||||
$oldName = $page->name;
|
||||
$oldMarkdown = $page->markdown;
|
||||
|
||||
$this->updateTemplateStatusAndContentFromInput($page, $input);
|
||||
$this->baseRepo->update($page, $input);
|
||||
|
||||
// Update with new details
|
||||
$page->revision_count++;
|
||||
|
||||
if (setting('app-editor') !== 'markdown') {
|
||||
$page->markdown = '';
|
||||
}
|
||||
|
||||
$page->save();
|
||||
|
||||
// Remove all update drafts for this user & page.
|
||||
@@ -195,7 +191,10 @@ class PageRepo
|
||||
|
||||
// Save a revision after updating
|
||||
$summary = $input['summary'] ?? null;
|
||||
if ($oldHtml !== $input['html'] || $oldName !== $input['name'] || $summary !== null) {
|
||||
$htmlChanged = isset($input['html']) && $input['html'] !== $oldHtml;
|
||||
$nameChanged = isset($input['name']) && $input['name'] !== $oldName;
|
||||
$markdownChanged = isset($input['markdown']) && $input['markdown'] !== $oldMarkdown;
|
||||
if ($htmlChanged || $nameChanged || $markdownChanged || $summary !== null) {
|
||||
$this->savePageRevision($page, $summary);
|
||||
}
|
||||
|
||||
@@ -224,10 +223,6 @@ class PageRepo
|
||||
{
|
||||
$revision = new PageRevision($page->getAttributes());
|
||||
|
||||
if (setting('app-editor') !== 'markdown') {
|
||||
$revision->markdown = '';
|
||||
}
|
||||
|
||||
$revision->page_id = $page->id;
|
||||
$revision->slug = $page->slug;
|
||||
$revision->book_slug = $page->book->slug;
|
||||
@@ -290,7 +285,13 @@ class PageRepo
|
||||
|
||||
$page->fill($revision->toArray());
|
||||
$content = new PageContent($page);
|
||||
$content->setNewHTML($revision->html);
|
||||
|
||||
if (!empty($revision->markdown)) {
|
||||
$content->setNewMarkdown($revision->markdown);
|
||||
} else {
|
||||
$content->setNewHTML($revision->html);
|
||||
}
|
||||
|
||||
$page->updated_by = user()->id;
|
||||
$page->refreshSlug();
|
||||
$page->save();
|
||||
|
||||
@@ -273,11 +273,11 @@ class TrashCan
|
||||
$count++;
|
||||
};
|
||||
|
||||
if ($entity->isA('chapter') || $entity->isA('book')) {
|
||||
if ($entity instanceof Chapter || $entity instanceof Book) {
|
||||
$entity->pages()->withTrashed()->withCount('deletions')->get()->each($restoreAction);
|
||||
}
|
||||
|
||||
if ($entity->isA('book')) {
|
||||
if ($entity instanceof Book) {
|
||||
$entity->chapters()->withTrashed()->withCount('deletions')->get()->each($restoreAction);
|
||||
}
|
||||
|
||||
@@ -286,19 +286,20 @@ class TrashCan
|
||||
|
||||
/**
|
||||
* Destroy the given entity.
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function destroyEntity(Entity $entity): int
|
||||
{
|
||||
if ($entity->isA('page')) {
|
||||
if ($entity instanceof Page) {
|
||||
return $this->destroyPage($entity);
|
||||
}
|
||||
if ($entity->isA('chapter')) {
|
||||
if ($entity instanceof Chapter) {
|
||||
return $this->destroyChapter($entity);
|
||||
}
|
||||
if ($entity->isA('book')) {
|
||||
if ($entity instanceof Book) {
|
||||
return $this->destroyBook($entity);
|
||||
}
|
||||
if ($entity->isA('shelf')) {
|
||||
if ($entity instanceof Bookshelf) {
|
||||
return $this->destroyShelf($entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"facade/ignition": "^1.16.4",
|
||||
"fideloper/proxy": "^4.4.1",
|
||||
"intervention/image": "^2.5.1",
|
||||
"laravel/framework": "^6.20",
|
||||
"laravel/framework": "^6.20.16",
|
||||
"laravel/socialite": "^5.1",
|
||||
"league/commonmark": "^1.5",
|
||||
"league/flysystem-aws-s3-v3": "^1.0.29",
|
||||
|
||||
618
composer.lock
generated
618
composer.lock
generated
File diff suppressed because it is too large
Load Diff
2
public/dist/app.js
vendored
2
public/dist/app.js
vendored
File diff suppressed because one or more lines are too long
@@ -422,7 +422,7 @@ class WysiwygEditor {
|
||||
this.imageUploadErrorText = this.$opts.imageUploadErrorText;
|
||||
this.isDarkMode = document.documentElement.classList.contains('dark-mode');
|
||||
|
||||
this.plugins = "image table textcolor paste link autolink fullscreen code customhr autosave lists codeeditor media";
|
||||
this.plugins = "image imagetools table textcolor paste link autolink fullscreen code customhr autosave lists codeeditor media";
|
||||
this.loadPlugins();
|
||||
|
||||
this.tinyMceConfig = this.getTinyMceConfig();
|
||||
|
||||
@@ -45,5 +45,5 @@ return [
|
||||
|
||||
// Other
|
||||
'commented_on' => '評論',
|
||||
'permissions_update' => 'updated permissions',
|
||||
'permissions_update' => '更新權限',
|
||||
];
|
||||
|
||||
@@ -268,7 +268,7 @@ return [
|
||||
'attachments_link_url' => '連結到檔案',
|
||||
'attachments_link_url_hint' => '網站或檔案的網址',
|
||||
'attach' => '附加',
|
||||
'attachments_insert_link' => 'Add Attachment Link to Page',
|
||||
'attachments_insert_link' => '將附件連結增加到頁面',
|
||||
'attachments_edit_file' => '編輯檔案',
|
||||
'attachments_edit_file_name' => '檔案名稱',
|
||||
'attachments_edit_drop_upload' => '刪除檔案或點選這裡上傳並覆蓋',
|
||||
|
||||
@@ -68,7 +68,7 @@ return [
|
||||
'maint' => '維護',
|
||||
'maint_image_cleanup' => '清理圖像',
|
||||
'maint_image_cleanup_desc' => "掃描頁面和修訂內容以檢查哪些圖像是正在使用的以及哪些圖像是多余的。確保在運行前創建完整的數據庫和映像備份。",
|
||||
'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions',
|
||||
'maint_delete_images_only_in_revisions' => '包含刪除僅在舊頁面修訂版中存在的圖像',
|
||||
'maint_image_cleanup_run' => '運行清理',
|
||||
'maint_image_cleanup_warning' => '發現了:count 張可能未使用的圖像。您確定要刪除這些圖像嗎?',
|
||||
'maint_image_cleanup_success' => '找到並刪除了:count 張可能未使用的圖像!',
|
||||
@@ -80,11 +80,11 @@ return [
|
||||
'maint_send_test_email_mail_subject' => '測試郵件',
|
||||
'maint_send_test_email_mail_greeting' => '電子郵件傳遞似乎有效!',
|
||||
'maint_send_test_email_mail_text' => '恭喜你! 收到此電子郵件通知時,您的電子郵件設置已經認證成功。',
|
||||
'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.',
|
||||
'maint_recycle_bin_desc' => '刪除的書架,書籍,章節和頁面將發送到回收站,以便可以還原或永久刪除它們。 回收站中的較舊項目可能會在一段時間後自動刪除,具體取決於系統配置。',
|
||||
'maint_recycle_bin_open' => 'Open Recycle Bin',
|
||||
|
||||
// Recycle Bin
|
||||
'recycle_bin' => 'Recycle Bin',
|
||||
'recycle_bin' => '資源回收筒',
|
||||
'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.',
|
||||
'recycle_bin_deleted_item' => 'Deleted Item',
|
||||
'recycle_bin_deleted_by' => 'Deleted By',
|
||||
@@ -103,16 +103,16 @@ return [
|
||||
'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.',
|
||||
|
||||
// Audit Log
|
||||
'audit' => 'Audit Log',
|
||||
'audit' => '稽核記錄',
|
||||
'audit_desc' => 'This audit log displays a list of activities tracked in the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.',
|
||||
'audit_event_filter' => 'Event Filter',
|
||||
'audit_event_filter_no_filter' => 'No Filter',
|
||||
'audit_deleted_item' => 'Deleted Item',
|
||||
'audit_deleted_item_name' => 'Name: :name',
|
||||
'audit_table_user' => 'User',
|
||||
'audit_table_event' => 'Event',
|
||||
'audit_table_user' => '使用者',
|
||||
'audit_table_event' => '活動',
|
||||
'audit_table_related' => 'Related Item or Detail',
|
||||
'audit_table_date' => 'Activity Date',
|
||||
'audit_table_date' => '最後活動日期',
|
||||
'audit_date_from' => 'Date Range From',
|
||||
'audit_date_to' => 'Date Range To',
|
||||
|
||||
@@ -157,7 +157,7 @@ return [
|
||||
'user_profile' => '使用者資料',
|
||||
'users_add_new' => '加入使用者',
|
||||
'users_search' => '搜尋使用者',
|
||||
'users_latest_activity' => 'Latest Activity',
|
||||
'users_latest_activity' => '最新活動',
|
||||
'users_details' => '用戶詳情',
|
||||
'users_details_desc' => '請設置用戶的顯示名稱和電子郵件地址, 該電子郵件地址將用於登錄該應用。',
|
||||
'users_details_desc_no_email' => '設置一個用戶的顯示名稱,以便其他人可以認出你。',
|
||||
@@ -177,7 +177,7 @@ return [
|
||||
'users_delete_confirm' => '您確定要刪除這個使用者?',
|
||||
'users_migrate_ownership' => 'Migrate Ownership',
|
||||
'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.',
|
||||
'users_none_selected' => 'No user selected',
|
||||
'users_none_selected' => '沒有選定的使用者',
|
||||
'users_delete_success' => 'User successfully removed',
|
||||
'users_edit' => '編輯使用者',
|
||||
'users_edit_profile' => '編輯資料',
|
||||
|
||||
@@ -66,6 +66,36 @@ class PageRevisionTest extends TestCase
|
||||
$pageView->assertSee('def456');
|
||||
}
|
||||
|
||||
public function test_page_revision_restore_with_markdown_retains_markdown_content()
|
||||
{
|
||||
$this->asEditor();
|
||||
|
||||
$pageRepo = app(PageRepo::class);
|
||||
$page = Page::first();
|
||||
$pageRepo->update($page, ['name' => 'updated page abc123', 'markdown' => '## New Content def456', 'summary' => 'initial page revision testing']);
|
||||
$pageRepo->update($page, ['name' => 'updated page again', 'markdown' => '## New Content Updated', 'summary' => 'page revision testing']);
|
||||
$page = Page::find($page->id);
|
||||
|
||||
$pageView = $this->get($page->getUrl());
|
||||
$pageView->assertDontSee('abc123');
|
||||
$pageView->assertDontSee('def456');
|
||||
|
||||
$revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first();
|
||||
$restoreReq = $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore');
|
||||
$page = Page::find($page->id);
|
||||
|
||||
$restoreReq->assertStatus(302);
|
||||
$restoreReq->assertRedirect($page->getUrl());
|
||||
|
||||
$pageView = $this->get($page->getUrl());
|
||||
$this->assertDatabaseHas('pages', [
|
||||
'id' => $page->id,
|
||||
'markdown' => '## New Content def456',
|
||||
]);
|
||||
$pageView->assertSee('abc123');
|
||||
$pageView->assertSee('def456');
|
||||
}
|
||||
|
||||
public function test_page_revision_restore_sets_new_revision_with_summary()
|
||||
{
|
||||
$this->asEditor();
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<?php namespace Tests;
|
||||
|
||||
use BookStack\Entities\Models\Book;
|
||||
use BookStack\Entities\Models\Bookshelf;
|
||||
use BookStack\Entities\Models\Chapter;
|
||||
use BookStack\Entities\Models\Deletion;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Entities\Models\Page;
|
||||
use DB;
|
||||
use Illuminate\Support\Carbon;
|
||||
@@ -129,6 +132,21 @@ class RecycleBinTest extends TestCase
|
||||
$redirectReq->assertNotificationContains('Deleted '.$itemCount.' total items from the recycle bin');
|
||||
}
|
||||
|
||||
public function test_permanent_delete_for_each_type()
|
||||
{
|
||||
/** @var Entity $entity */
|
||||
foreach ([new Bookshelf, new Book, new Chapter, new Page] as $entity) {
|
||||
$entity = $entity->newQuery()->first();
|
||||
$this->asEditor()->delete($entity->getUrl());
|
||||
$deletion = Deletion::query()->orderBy('id', 'desc')->firstOrFail();
|
||||
|
||||
$deleteReq = $this->asAdmin()->delete("/settings/recycle-bin/{$deletion->id}");
|
||||
$deleteReq->assertRedirect('/settings/recycle-bin');
|
||||
$this->assertDatabaseMissing('deletions', ['id' => $deletion->id]);
|
||||
$this->assertDatabaseMissing($entity->getTable(), ['id' => $entity->id]);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_permanent_entity_delete_updates_existing_activity_with_entity_name()
|
||||
{
|
||||
$page = Page::query()->firstOrFail();
|
||||
|
||||
Reference in New Issue
Block a user