mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-02-07 11:19:38 +03:00
Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92d15d9cf2 | ||
|
|
b06147fef7 | ||
|
|
776ec7b9e7 | ||
|
|
8aa6bdc8ab | ||
|
|
4ab17157b1 | ||
|
|
6d7ffab115 | ||
|
|
c8cfec96dc | ||
|
|
d145efb6f6 | ||
|
|
c54101c603 | ||
|
|
865e5aecc9 | ||
|
|
ae4d1d804a | ||
|
|
5fc19b0edf | ||
|
|
0a73b70b64 | ||
|
|
2668aae09b | ||
|
|
3b9c0b34ae | ||
|
|
53f32849a9 | ||
|
|
7ca8bdc231 | ||
|
|
6621d55f3d | ||
|
|
d55db06c01 | ||
|
|
6b4b500a33 | ||
|
|
5ffec2c52d | ||
|
|
ec07793cda | ||
|
|
61adc735c8 | ||
|
|
7bbf591a7f | ||
|
|
61f8d18af5 | ||
|
|
f786d25f2e | ||
|
|
e62f4426ea | ||
|
|
32ba3a591f | ||
|
|
73025719a4 | ||
|
|
d55684531f | ||
|
|
d15eb129b0 | ||
|
|
3626a2265b | ||
|
|
d13abc7e1d | ||
|
|
2442829ef2 | ||
|
|
795b28162a | ||
|
|
31706ea06b | ||
|
|
4b9e6042d5 | ||
|
|
d279b0830b | ||
|
|
181ab91b1d | ||
|
|
841350a937 | ||
|
|
12183bac07 | ||
|
|
306f41b6f0 | ||
|
|
c1d76d2571 | ||
|
|
f83074d50e | ||
|
|
2be892be70 | ||
|
|
c934b9319f | ||
|
|
35a51197ce | ||
|
|
47fd578edb | ||
|
|
add091305c | ||
|
|
3d017594a8 | ||
|
|
0dcb2ec78c | ||
|
|
9186e77d27 | ||
|
|
6045aff33a | ||
|
|
dca9765d5d | ||
|
|
a37d0c57dc | ||
|
|
054475135a | ||
|
|
02a35b6db4 | ||
|
|
b80992ca59 | ||
|
|
c606970e38 | ||
|
|
dfeca246a0 | ||
|
|
3476d83ecc | ||
|
|
3617ab1540 | ||
|
|
e65b4b63a2 | ||
|
|
7cac3f4780 | ||
|
|
c4839c783a | ||
|
|
a5751a584c | ||
|
|
f518a3be37 | ||
|
|
0208f066c5 | ||
|
|
2d0461b63a | ||
|
|
b913ae703d | ||
|
|
1611b0399f | ||
|
|
8d4b8ff4f3 | ||
|
|
77a88618c2 | ||
|
|
8b062d4795 | ||
|
|
717b516341 | ||
|
|
fda242d3da | ||
|
|
aac547934c | ||
|
|
64da80cbf4 | ||
|
|
5fa728f28a | ||
|
|
c61ce8dee4 |
13
.github/translators.txt
vendored
13
.github/translators.txt
vendored
@@ -487,3 +487,16 @@ jellium :: French
|
||||
Qxlkdr :: Swedish
|
||||
Hari (muhhari) :: Indonesian
|
||||
仙君御 (xjy) :: Chinese Simplified
|
||||
TapioM :: Finnish
|
||||
lingb58 :: Chinese Traditional
|
||||
Angel Pandey (angel-pandey) :: Nepali
|
||||
Supriya Shrestha (supriyashrestha) :: Nepali
|
||||
gprabhat :: Nepali
|
||||
CellCat :: Chinese Simplified
|
||||
Al Desrahim (aldesrahim) :: Indonesian
|
||||
ahmad abbaspour (deshneh.dar.diss) :: Persian
|
||||
Erjon K. (ekr) :: Albanian
|
||||
LiZerui (iamzrli) :: Chinese Traditional
|
||||
Ticker (ticker.com) :: Hebrew
|
||||
CrazyComputer :: Chinese Simplified
|
||||
Firr (FirrV) :: Russian
|
||||
|
||||
@@ -12,6 +12,8 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $value
|
||||
* @property int $entity_id
|
||||
* @property string $entity_type
|
||||
* @property int $order
|
||||
*/
|
||||
class Tag extends Model
|
||||
|
||||
@@ -3,17 +3,15 @@
|
||||
namespace BookStack\Activity\Tools;
|
||||
|
||||
use BookStack\Activity\Models\Tag;
|
||||
use BookStack\Entities\Models\BookChild;
|
||||
use BookStack\Entities\Models\Entity;
|
||||
use BookStack\Entities\Models\Page;
|
||||
|
||||
class TagClassGenerator
|
||||
{
|
||||
protected array $tags;
|
||||
|
||||
/**
|
||||
* @param Tag[] $tags
|
||||
*/
|
||||
public function __construct(array $tags)
|
||||
{
|
||||
$this->tags = $tags;
|
||||
public function __construct(
|
||||
protected Entity $entity
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,14 +20,23 @@ class TagClassGenerator
|
||||
public function generate(): array
|
||||
{
|
||||
$classes = [];
|
||||
$tags = $this->entity->tags->all();
|
||||
|
||||
foreach ($this->tags as $tag) {
|
||||
$name = $this->normalizeTagClassString($tag->name);
|
||||
$value = $this->normalizeTagClassString($tag->value);
|
||||
$classes[] = 'tag-name-' . $name;
|
||||
if ($value) {
|
||||
$classes[] = 'tag-value-' . $value;
|
||||
$classes[] = 'tag-pair-' . $name . '-' . $value;
|
||||
foreach ($tags as $tag) {
|
||||
array_push($classes, ...$this->generateClassesForTag($tag));
|
||||
}
|
||||
|
||||
if ($this->entity instanceof BookChild && userCan('view', $this->entity->book)) {
|
||||
$bookTags = $this->entity->book->tags;
|
||||
foreach ($bookTags as $bookTag) {
|
||||
array_push($classes, ...$this->generateClassesForTag($bookTag, 'book-'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->entity instanceof Page && $this->entity->chapter && userCan('view', $this->entity->chapter)) {
|
||||
$chapterTags = $this->entity->chapter->tags;
|
||||
foreach ($chapterTags as $chapterTag) {
|
||||
array_push($classes, ...$this->generateClassesForTag($chapterTag, 'chapter-'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +48,22 @@ class TagClassGenerator
|
||||
return implode(' ', $this->generate());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function generateClassesForTag(Tag $tag, string $prefix = ''): array
|
||||
{
|
||||
$classes = [];
|
||||
$name = $this->normalizeTagClassString($tag->name);
|
||||
$value = $this->normalizeTagClassString($tag->value);
|
||||
$classes[] = "{$prefix}tag-name-{$name}";
|
||||
if ($value) {
|
||||
$classes[] = "{$prefix}tag-value-{$value}";
|
||||
$classes[] = "{$prefix}tag-pair-{$name}-{$value}";
|
||||
}
|
||||
return $classes;
|
||||
}
|
||||
|
||||
protected function normalizeTagClassString(string $value): string
|
||||
{
|
||||
$value = str_replace(' ', '', strtolower($value));
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// Configured mail encryption method.
|
||||
// STARTTLS should still be attempted, but tls/ssl forces TLS usage.
|
||||
$mailEncryption = env('MAIL_ENCRYPTION', null);
|
||||
$mailPort = intval(env('MAIL_PORT', 587));
|
||||
|
||||
return [
|
||||
|
||||
@@ -33,13 +34,13 @@ return [
|
||||
'transport' => 'smtp',
|
||||
'scheme' => null,
|
||||
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
|
||||
'port' => env('MAIL_PORT', 587),
|
||||
'port' => $mailPort,
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'verify_peer' => env('MAIL_VERIFY_SSL', true),
|
||||
'timeout' => null,
|
||||
'local_domain' => null,
|
||||
'tls_required' => ($mailEncryption === 'tls' || $mailEncryption === 'ssl'),
|
||||
'require_tls' => ($mailEncryption === 'tls' || $mailEncryption === 'ssl' || $mailPort === 465),
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
|
||||
@@ -18,6 +18,7 @@ use BookStack\Exceptions\NotFoundException;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Http\Controller;
|
||||
use BookStack\References\ReferenceFetcher;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use BookStack\Util\SimpleListOptions;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
@@ -263,7 +264,9 @@ class BookController extends Controller
|
||||
$this->checkPermission('bookshelf-create-all');
|
||||
$this->checkPermission('book-create-all');
|
||||
|
||||
$shelf = $transformer->transformBookToShelf($book);
|
||||
$shelf = (new DatabaseTransaction(function () use ($book, $transformer) {
|
||||
return $transformer->transformBookToShelf($book);
|
||||
}))->run();
|
||||
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
|
||||
@@ -9,12 +9,11 @@ use BookStack\Entities\Repos\ChapterRepo;
|
||||
use BookStack\Exceptions\PermissionsException;
|
||||
use BookStack\Http\ApiController;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ChapterApiController extends ApiController
|
||||
{
|
||||
protected $rules = [
|
||||
protected array $rules = [
|
||||
'create' => [
|
||||
'book_id' => ['required', 'integer'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
|
||||
@@ -18,6 +18,7 @@ use BookStack\Exceptions\NotifyException;
|
||||
use BookStack\Exceptions\PermissionsException;
|
||||
use BookStack\Http\Controller;
|
||||
use BookStack\References\ReferenceFetcher;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Throwable;
|
||||
@@ -269,7 +270,9 @@ class ChapterController extends Controller
|
||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||
$this->checkPermission('book-create-all');
|
||||
|
||||
$book = $transformer->transformChapterToBook($chapter);
|
||||
$book = (new DatabaseTransaction(function () use ($chapter, $transformer) {
|
||||
return $transformer->transformChapterToBook($chapter);
|
||||
}))->run();
|
||||
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class PageApiController extends ApiController
|
||||
{
|
||||
protected $rules = [
|
||||
protected array $rules = [
|
||||
'create' => [
|
||||
'book_id' => ['required_without:chapter_id', 'integer'],
|
||||
'chapter_id' => ['required_without:book_id', 'integer'],
|
||||
|
||||
@@ -77,7 +77,6 @@ class BaseRepo
|
||||
$entity->touch();
|
||||
}
|
||||
|
||||
$entity->rebuildPermissions();
|
||||
$entity->indexForSearch();
|
||||
$this->referenceStore->updateForEntity($entity);
|
||||
|
||||
@@ -139,7 +138,7 @@ class BaseRepo
|
||||
|
||||
/**
|
||||
* Sort the parent of the given entity, if any auto sort actions are set for it.
|
||||
* Typical ran during create/update/insert events.
|
||||
* Typically ran during create/update/insert events.
|
||||
*/
|
||||
public function sortParent(Entity $entity): void
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ use BookStack\Exceptions\ImageUploadException;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Sorting\SortRule;
|
||||
use BookStack\Uploads\ImageRepo;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Exception;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
@@ -28,19 +29,22 @@ class BookRepo
|
||||
*/
|
||||
public function create(array $input): Book
|
||||
{
|
||||
$book = new Book();
|
||||
$this->baseRepo->create($book, $input);
|
||||
$this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
|
||||
$this->baseRepo->updateDefaultTemplate($book, intval($input['default_template_id'] ?? null));
|
||||
Activity::add(ActivityType::BOOK_CREATE, $book);
|
||||
return (new DatabaseTransaction(function () use ($input) {
|
||||
$book = new Book();
|
||||
|
||||
$defaultBookSortSetting = intval(setting('sorting-book-default', '0'));
|
||||
if ($defaultBookSortSetting && SortRule::query()->find($defaultBookSortSetting)) {
|
||||
$book->sort_rule_id = $defaultBookSortSetting;
|
||||
$book->save();
|
||||
}
|
||||
$this->baseRepo->create($book, $input);
|
||||
$this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
|
||||
$this->baseRepo->updateDefaultTemplate($book, intval($input['default_template_id'] ?? null));
|
||||
Activity::add(ActivityType::BOOK_CREATE, $book);
|
||||
|
||||
return $book;
|
||||
$defaultBookSortSetting = intval(setting('sorting-book-default', '0'));
|
||||
if ($defaultBookSortSetting && SortRule::query()->find($defaultBookSortSetting)) {
|
||||
$book->sort_rule_id = $defaultBookSortSetting;
|
||||
$book->save();
|
||||
}
|
||||
|
||||
return $book;
|
||||
}))->run();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ use BookStack\Entities\Models\Bookshelf;
|
||||
use BookStack\Entities\Queries\BookQueries;
|
||||
use BookStack\Entities\Tools\TrashCan;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Exception;
|
||||
|
||||
class BookshelfRepo
|
||||
@@ -23,13 +24,14 @@ class BookshelfRepo
|
||||
*/
|
||||
public function create(array $input, array $bookIds): Bookshelf
|
||||
{
|
||||
$shelf = new Bookshelf();
|
||||
$this->baseRepo->create($shelf, $input);
|
||||
$this->baseRepo->updateCoverImage($shelf, $input['image'] ?? null);
|
||||
$this->updateBooks($shelf, $bookIds);
|
||||
Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
|
||||
|
||||
return $shelf;
|
||||
return (new DatabaseTransaction(function () use ($input, $bookIds) {
|
||||
$shelf = new Bookshelf();
|
||||
$this->baseRepo->create($shelf, $input);
|
||||
$this->baseRepo->updateCoverImage($shelf, $input['image'] ?? null);
|
||||
$this->updateBooks($shelf, $bookIds);
|
||||
Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
|
||||
return $shelf;
|
||||
}))->run();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ use BookStack\Entities\Tools\TrashCan;
|
||||
use BookStack\Exceptions\MoveOperationException;
|
||||
use BookStack\Exceptions\PermissionsException;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Exception;
|
||||
|
||||
class ChapterRepo
|
||||
@@ -27,16 +28,18 @@ class ChapterRepo
|
||||
*/
|
||||
public function create(array $input, Book $parentBook): Chapter
|
||||
{
|
||||
$chapter = new Chapter();
|
||||
$chapter->book_id = $parentBook->id;
|
||||
$chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
|
||||
$this->baseRepo->create($chapter, $input);
|
||||
$this->baseRepo->updateDefaultTemplate($chapter, intval($input['default_template_id'] ?? null));
|
||||
Activity::add(ActivityType::CHAPTER_CREATE, $chapter);
|
||||
return (new DatabaseTransaction(function () use ($input, $parentBook) {
|
||||
$chapter = new Chapter();
|
||||
$chapter->book_id = $parentBook->id;
|
||||
$chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
|
||||
$this->baseRepo->create($chapter, $input);
|
||||
$this->baseRepo->updateDefaultTemplate($chapter, intval($input['default_template_id'] ?? null));
|
||||
Activity::add(ActivityType::CHAPTER_CREATE, $chapter);
|
||||
|
||||
$this->baseRepo->sortParent($chapter);
|
||||
$this->baseRepo->sortParent($chapter);
|
||||
|
||||
return $chapter;
|
||||
return $chapter;
|
||||
}))->run();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,12 +91,14 @@ class ChapterRepo
|
||||
throw new PermissionsException('User does not have permission to create a chapter within the chosen book');
|
||||
}
|
||||
|
||||
$chapter->changeBook($parent->id);
|
||||
$chapter->rebuildPermissions();
|
||||
Activity::add(ActivityType::CHAPTER_MOVE, $chapter);
|
||||
return (new DatabaseTransaction(function () use ($chapter, $parent) {
|
||||
$chapter->changeBook($parent->id);
|
||||
$chapter->rebuildPermissions();
|
||||
Activity::add(ActivityType::CHAPTER_MOVE, $chapter);
|
||||
|
||||
$this->baseRepo->sortParent($chapter);
|
||||
$this->baseRepo->sortParent($chapter);
|
||||
|
||||
return $parent;
|
||||
return $parent;
|
||||
}))->run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use BookStack\Exceptions\PermissionsException;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\References\ReferenceStore;
|
||||
use BookStack\References\ReferenceUpdater;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Exception;
|
||||
|
||||
class PageRepo
|
||||
@@ -61,8 +62,10 @@ class PageRepo
|
||||
]);
|
||||
}
|
||||
|
||||
$page->save();
|
||||
$page->refresh()->rebuildPermissions();
|
||||
(new DatabaseTransaction(function () use ($page) {
|
||||
$page->save();
|
||||
$page->refresh()->rebuildPermissions();
|
||||
}))->run();
|
||||
|
||||
return $page;
|
||||
}
|
||||
@@ -72,26 +75,29 @@ class PageRepo
|
||||
*/
|
||||
public function publishDraft(Page $draft, array $input): Page
|
||||
{
|
||||
$draft->draft = false;
|
||||
$draft->revision_count = 1;
|
||||
$draft->priority = $this->getNewPriority($draft);
|
||||
$this->updateTemplateStatusAndContentFromInput($draft, $input);
|
||||
$this->baseRepo->update($draft, $input);
|
||||
return (new DatabaseTransaction(function () use ($draft, $input) {
|
||||
$draft->draft = false;
|
||||
$draft->revision_count = 1;
|
||||
$draft->priority = $this->getNewPriority($draft);
|
||||
$this->updateTemplateStatusAndContentFromInput($draft, $input);
|
||||
$this->baseRepo->update($draft, $input);
|
||||
$draft->rebuildPermissions();
|
||||
|
||||
$summary = trim($input['summary'] ?? '') ?: trans('entities.pages_initial_revision');
|
||||
$this->revisionRepo->storeNewForPage($draft, $summary);
|
||||
$draft->refresh();
|
||||
$summary = trim($input['summary'] ?? '') ?: trans('entities.pages_initial_revision');
|
||||
$this->revisionRepo->storeNewForPage($draft, $summary);
|
||||
$draft->refresh();
|
||||
|
||||
Activity::add(ActivityType::PAGE_CREATE, $draft);
|
||||
$this->baseRepo->sortParent($draft);
|
||||
Activity::add(ActivityType::PAGE_CREATE, $draft);
|
||||
$this->baseRepo->sortParent($draft);
|
||||
|
||||
return $draft;
|
||||
return $draft;
|
||||
}))->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly update the content for the given page from the provided input.
|
||||
* Used for direct content access in a way that performs required changes
|
||||
* (Search index & reference regen) without performing an official update.
|
||||
* (Search index and reference regen) without performing an official update.
|
||||
*/
|
||||
public function setContentFromInput(Page $page, array $input): void
|
||||
{
|
||||
@@ -116,7 +122,7 @@ class PageRepo
|
||||
$page->revision_count++;
|
||||
$page->save();
|
||||
|
||||
// Remove all update drafts for this user & page.
|
||||
// Remove all update drafts for this user and page.
|
||||
$this->revisionRepo->deleteDraftsForCurrentUser($page);
|
||||
|
||||
// Save a revision after updating
|
||||
@@ -269,16 +275,18 @@ class PageRepo
|
||||
throw new PermissionsException('User does not have permission to create a page within the new parent');
|
||||
}
|
||||
|
||||
$page->chapter_id = ($parent instanceof Chapter) ? $parent->id : null;
|
||||
$newBookId = ($parent instanceof Chapter) ? $parent->book->id : $parent->id;
|
||||
$page->changeBook($newBookId);
|
||||
$page->rebuildPermissions();
|
||||
return (new DatabaseTransaction(function () use ($page, $parent) {
|
||||
$page->chapter_id = ($parent instanceof Chapter) ? $parent->id : null;
|
||||
$newBookId = ($parent instanceof Chapter) ? $parent->book->id : $parent->id;
|
||||
$page->changeBook($newBookId);
|
||||
$page->rebuildPermissions();
|
||||
|
||||
Activity::add(ActivityType::PAGE_MOVE, $page);
|
||||
Activity::add(ActivityType::PAGE_MOVE, $page);
|
||||
|
||||
$this->baseRepo->sortParent($page);
|
||||
$this->baseRepo->sortParent($page);
|
||||
|
||||
return $parent;
|
||||
return $parent;
|
||||
}))->run();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,17 +13,12 @@ use BookStack\Facades\Activity;
|
||||
|
||||
class HierarchyTransformer
|
||||
{
|
||||
protected BookRepo $bookRepo;
|
||||
protected BookshelfRepo $shelfRepo;
|
||||
protected Cloner $cloner;
|
||||
protected TrashCan $trashCan;
|
||||
|
||||
public function __construct(BookRepo $bookRepo, BookshelfRepo $shelfRepo, Cloner $cloner, TrashCan $trashCan)
|
||||
{
|
||||
$this->bookRepo = $bookRepo;
|
||||
$this->shelfRepo = $shelfRepo;
|
||||
$this->cloner = $cloner;
|
||||
$this->trashCan = $trashCan;
|
||||
public function __construct(
|
||||
protected BookRepo $bookRepo,
|
||||
protected BookshelfRepo $shelfRepo,
|
||||
protected Cloner $cloner,
|
||||
protected TrashCan $trashCan
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@ use BookStack\Exceptions\NotifyException;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Uploads\AttachmentService;
|
||||
use BookStack\Uploads\ImageService;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Carbon;
|
||||
@@ -357,25 +358,26 @@ class TrashCan
|
||||
|
||||
/**
|
||||
* Destroy the given entity.
|
||||
* Returns the number of total entities destroyed in the operation.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function destroyEntity(Entity $entity): int
|
||||
{
|
||||
if ($entity instanceof Page) {
|
||||
return $this->destroyPage($entity);
|
||||
}
|
||||
if ($entity instanceof Chapter) {
|
||||
return $this->destroyChapter($entity);
|
||||
}
|
||||
if ($entity instanceof Book) {
|
||||
return $this->destroyBook($entity);
|
||||
}
|
||||
if ($entity instanceof Bookshelf) {
|
||||
return $this->destroyShelf($entity);
|
||||
}
|
||||
$result = (new DatabaseTransaction(function () use ($entity) {
|
||||
if ($entity instanceof Page) {
|
||||
return $this->destroyPage($entity);
|
||||
} else if ($entity instanceof Chapter) {
|
||||
return $this->destroyChapter($entity);
|
||||
} else if ($entity instanceof Book) {
|
||||
return $this->destroyBook($entity);
|
||||
} else if ($entity instanceof Bookshelf) {
|
||||
return $this->destroyShelf($entity);
|
||||
}
|
||||
return null;
|
||||
}))->run();
|
||||
|
||||
return 0;
|
||||
return $result ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace BookStack\Exports\Controllers;
|
||||
|
||||
use BookStack\Entities\Queries\BookQueries;
|
||||
use BookStack\Exports\ExportFormatter;
|
||||
use BookStack\Exports\ZipExports\ZipExportBuilder;
|
||||
use BookStack\Http\ApiController;
|
||||
use Throwable;
|
||||
|
||||
@@ -63,4 +64,15 @@ class BookExportApiController extends ApiController
|
||||
|
||||
return $this->download()->directly($markdown, $book->slug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a book as a contained ZIP export file.
|
||||
*/
|
||||
public function exportZip(int $id, ZipExportBuilder $builder)
|
||||
{
|
||||
$book = $this->queries->findVisibleByIdOrFail($id);
|
||||
$zip = $builder->buildForBook($book);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $book->slug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace BookStack\Exports\Controllers;
|
||||
|
||||
use BookStack\Entities\Queries\ChapterQueries;
|
||||
use BookStack\Exports\ExportFormatter;
|
||||
use BookStack\Exports\ZipExports\ZipExportBuilder;
|
||||
use BookStack\Http\ApiController;
|
||||
use Throwable;
|
||||
|
||||
@@ -63,4 +64,15 @@ class ChapterExportApiController extends ApiController
|
||||
|
||||
return $this->download()->directly($markdown, $chapter->slug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a chapter as a contained ZIP file.
|
||||
*/
|
||||
public function exportZip(int $id, ZipExportBuilder $builder)
|
||||
{
|
||||
$chapter = $this->queries->findVisibleByIdOrFail($id);
|
||||
$zip = $builder->buildForChapter($chapter);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $chapter->slug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
144
app/Exports/Controllers/ImportApiController.php
Normal file
144
app/Exports/Controllers/ImportApiController.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BookStack\Exports\Controllers;
|
||||
|
||||
use BookStack\Exceptions\ZipImportException;
|
||||
use BookStack\Exceptions\ZipValidationException;
|
||||
use BookStack\Exports\ImportRepo;
|
||||
use BookStack\Http\ApiController;
|
||||
use BookStack\Uploads\AttachmentService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class ImportApiController extends ApiController
|
||||
{
|
||||
public function __construct(
|
||||
protected ImportRepo $imports,
|
||||
) {
|
||||
$this->middleware('can:content-import');
|
||||
}
|
||||
|
||||
/**
|
||||
* List existing ZIP imports visible to the user.
|
||||
* Requires permission to import content.
|
||||
*/
|
||||
public function list(): JsonResponse
|
||||
{
|
||||
$query = $this->imports->queryVisible();
|
||||
|
||||
return $this->apiListingResponse($query, [
|
||||
'id', 'name', 'size', 'type', 'created_by', 'created_at', 'updated_at'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new import from a ZIP file.
|
||||
* This does not actually run the import since that is performed via the "run" endpoint.
|
||||
* This uploads, validates and stores the ZIP file so it's ready to be imported.
|
||||
*
|
||||
* This "file" parameter must be a BookStack-compatible ZIP file, and this must be
|
||||
* sent via a 'multipart/form-data' type request.
|
||||
*
|
||||
* Requires permission to import content.
|
||||
*/
|
||||
public function create(Request $request): JsonResponse
|
||||
{
|
||||
$this->validate($request, $this->rules()['create']);
|
||||
|
||||
$file = $request->file('file');
|
||||
|
||||
try {
|
||||
$import = $this->imports->storeFromUpload($file);
|
||||
} catch (ZipValidationException $exception) {
|
||||
$message = "ZIP upload failed with the following validation errors: \n" . $this->formatErrors($exception->errors);
|
||||
return $this->jsonError($message, 422);
|
||||
}
|
||||
|
||||
return response()->json($import);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read details of a pending ZIP import.
|
||||
* The "details" property contains high-level metadata regarding the ZIP import content,
|
||||
* and the structure of this will change depending on import "type".
|
||||
* Requires permission to import content.
|
||||
*/
|
||||
public function read(int $id): JsonResponse
|
||||
{
|
||||
$import = $this->imports->findVisible($id);
|
||||
|
||||
$import->setAttribute('details', $import->decodeMetadata());
|
||||
|
||||
return response()->json($import);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the import process for an uploaded ZIP import.
|
||||
* The "parent_id" and "parent_type" parameters are required when the import type is "chapter" or "page".
|
||||
* On success, this endpoint returns the imported item.
|
||||
* Requires permission to import content.
|
||||
*/
|
||||
public function run(int $id, Request $request): JsonResponse
|
||||
{
|
||||
$import = $this->imports->findVisible($id);
|
||||
$parent = null;
|
||||
$rules = $this->rules()['run'];
|
||||
|
||||
if ($import->type === 'page' || $import->type === 'chapter') {
|
||||
$rules['parent_type'][] = 'required';
|
||||
$rules['parent_id'][] = 'required';
|
||||
$data = $this->validate($request, $rules);
|
||||
$parent = "{$data['parent_type']}:{$data['parent_id']}";
|
||||
}
|
||||
|
||||
try {
|
||||
$entity = $this->imports->runImport($import, $parent);
|
||||
} catch (ZipImportException $exception) {
|
||||
$message = "ZIP import failed with the following errors: \n" . $this->formatErrors($exception->errors);
|
||||
return $this->jsonError($message);
|
||||
}
|
||||
|
||||
return response()->json($entity->withoutRelations());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a pending ZIP import from the system.
|
||||
* Requires permission to import content.
|
||||
*/
|
||||
public function delete(int $id): Response
|
||||
{
|
||||
$import = $this->imports->findVisible($id);
|
||||
$this->imports->deleteImport($import);
|
||||
|
||||
return response('', 204);
|
||||
}
|
||||
|
||||
protected function rules(): array
|
||||
{
|
||||
return [
|
||||
'create' => [
|
||||
'file' => ['required', ...AttachmentService::getFileValidationRules()],
|
||||
],
|
||||
'run' => [
|
||||
'parent_type' => ['string', 'in:book,chapter'],
|
||||
'parent_id' => ['int'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
protected function formatErrors(array $errors): string
|
||||
{
|
||||
$parts = [];
|
||||
foreach ($errors as $key => $error) {
|
||||
if (is_string($key)) {
|
||||
$parts[] = "[{$key}] {$error}";
|
||||
} else {
|
||||
$parts[] = $error;
|
||||
}
|
||||
}
|
||||
return implode("\n", $parts);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace BookStack\Exports\Controllers;
|
||||
|
||||
use BookStack\Entities\Queries\PageQueries;
|
||||
use BookStack\Exports\ExportFormatter;
|
||||
use BookStack\Exports\ZipExports\ZipExportBuilder;
|
||||
use BookStack\Http\ApiController;
|
||||
use Throwable;
|
||||
|
||||
@@ -63,4 +64,15 @@ class PageExportApiController extends ApiController
|
||||
|
||||
return $this->download()->directly($markdown, $page->slug . '.md');
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a page as a contained ZIP file.
|
||||
*/
|
||||
public function exportZip(int $id, ZipExportBuilder $builder)
|
||||
{
|
||||
$page = $this->queries->findVisibleByIdOrFail($id);
|
||||
$zip = $builder->buildForPage($page);
|
||||
|
||||
return $this->download()->streamedFileDirectly($zip, $page->slug . '.zip', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ class Import extends Model implements Loggable
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $hidden = ['metadata'];
|
||||
|
||||
public function getSizeString(): string
|
||||
{
|
||||
$mb = round($this->size / 1000000, 2);
|
||||
|
||||
@@ -17,6 +17,7 @@ use BookStack\Exports\ZipExports\ZipExportValidator;
|
||||
use BookStack\Exports\ZipExports\ZipImportRunner;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Uploads\FileStorage;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
@@ -34,6 +35,11 @@ class ImportRepo
|
||||
* @return Collection<Import>
|
||||
*/
|
||||
public function getVisibleImports(): Collection
|
||||
{
|
||||
return $this->queryVisible()->get();
|
||||
}
|
||||
|
||||
public function queryVisible(): Builder
|
||||
{
|
||||
$query = Import::query();
|
||||
|
||||
@@ -41,7 +47,7 @@ class ImportRepo
|
||||
$query->where('created_by', user()->id);
|
||||
}
|
||||
|
||||
return $query->get();
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function findVisible(int $id): Import
|
||||
|
||||
@@ -8,7 +8,7 @@ use Illuminate\Http\JsonResponse;
|
||||
|
||||
abstract class ApiController extends Controller
|
||||
{
|
||||
protected $rules = [];
|
||||
protected array $rules = [];
|
||||
|
||||
/**
|
||||
* Provide a paginated listing JSON response in a standard format
|
||||
|
||||
@@ -16,7 +16,7 @@ class ContentPermissionApiController extends ApiController
|
||||
) {
|
||||
}
|
||||
|
||||
protected $rules = [
|
||||
protected array $rules = [
|
||||
'update' => [
|
||||
'owner_id' => ['int'],
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class JointPermissionBuilder
|
||||
/**
|
||||
* Re-generate all entity permission from scratch.
|
||||
*/
|
||||
public function rebuildForAll()
|
||||
public function rebuildForAll(): void
|
||||
{
|
||||
JointPermission::query()->truncate();
|
||||
|
||||
@@ -51,7 +51,7 @@ class JointPermissionBuilder
|
||||
/**
|
||||
* Rebuild the entity jointPermissions for a particular entity.
|
||||
*/
|
||||
public function rebuildForEntity(Entity $entity)
|
||||
public function rebuildForEntity(Entity $entity): void
|
||||
{
|
||||
$entities = [$entity];
|
||||
if ($entity instanceof Book) {
|
||||
@@ -119,7 +119,7 @@ class JointPermissionBuilder
|
||||
/**
|
||||
* Build joint permissions for the given book and role combinations.
|
||||
*/
|
||||
protected function buildJointPermissionsForBooks(EloquentCollection $books, array $roles, bool $deleteOld = false)
|
||||
protected function buildJointPermissionsForBooks(EloquentCollection $books, array $roles, bool $deleteOld = false): void
|
||||
{
|
||||
$entities = clone $books;
|
||||
|
||||
@@ -143,7 +143,7 @@ class JointPermissionBuilder
|
||||
/**
|
||||
* Rebuild the entity jointPermissions for a collection of entities.
|
||||
*/
|
||||
protected function buildJointPermissionsForEntities(array $entities)
|
||||
protected function buildJointPermissionsForEntities(array $entities): void
|
||||
{
|
||||
$roles = Role::query()->get()->values()->all();
|
||||
$this->deleteManyJointPermissionsForEntities($entities);
|
||||
@@ -155,21 +155,19 @@ class JointPermissionBuilder
|
||||
*
|
||||
* @param Entity[] $entities
|
||||
*/
|
||||
protected function deleteManyJointPermissionsForEntities(array $entities)
|
||||
protected function deleteManyJointPermissionsForEntities(array $entities): void
|
||||
{
|
||||
$simpleEntities = $this->entitiesToSimpleEntities($entities);
|
||||
$idsByType = $this->entitiesToTypeIdMap($simpleEntities);
|
||||
|
||||
DB::transaction(function () use ($idsByType) {
|
||||
foreach ($idsByType as $type => $ids) {
|
||||
foreach (array_chunk($ids, 1000) as $idChunk) {
|
||||
DB::table('joint_permissions')
|
||||
->where('entity_type', '=', $type)
|
||||
->whereIn('entity_id', $idChunk)
|
||||
->delete();
|
||||
}
|
||||
foreach ($idsByType as $type => $ids) {
|
||||
foreach (array_chunk($ids, 1000) as $idChunk) {
|
||||
DB::table('joint_permissions')
|
||||
->where('entity_type', '=', $type)
|
||||
->whereIn('entity_id', $idChunk)
|
||||
->delete();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,7 +193,7 @@ class JointPermissionBuilder
|
||||
* @param Entity[] $originalEntities
|
||||
* @param Role[] $roles
|
||||
*/
|
||||
protected function createManyJointPermissions(array $originalEntities, array $roles)
|
||||
protected function createManyJointPermissions(array $originalEntities, array $roles): void
|
||||
{
|
||||
$entities = $this->entitiesToSimpleEntities($originalEntities);
|
||||
$jointPermissions = [];
|
||||
@@ -225,11 +223,9 @@ class JointPermissionBuilder
|
||||
}
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($jointPermissions) {
|
||||
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
|
||||
DB::table('joint_permissions')->insert($jointPermissionChunk);
|
||||
}
|
||||
});
|
||||
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
|
||||
DB::table('joint_permissions')->insert($jointPermissionChunk);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ use BookStack\Entities\Tools\PermissionsUpdater;
|
||||
use BookStack\Http\Controller;
|
||||
use BookStack\Permissions\Models\EntityPermission;
|
||||
use BookStack\Users\Models\Role;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PermissionsController extends Controller
|
||||
@@ -40,7 +41,9 @@ class PermissionsController extends Controller
|
||||
$page = $this->queries->pages->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($page, $request);
|
||||
(new DatabaseTransaction(function () use ($page, $request) {
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($page, $request);
|
||||
}))->run();
|
||||
|
||||
$this->showSuccessNotification(trans('entities.pages_permissions_success'));
|
||||
|
||||
@@ -70,7 +73,9 @@ class PermissionsController extends Controller
|
||||
$chapter = $this->queries->chapters->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($chapter, $request);
|
||||
(new DatabaseTransaction(function () use ($chapter, $request) {
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($chapter, $request);
|
||||
}))->run();
|
||||
|
||||
$this->showSuccessNotification(trans('entities.chapters_permissions_success'));
|
||||
|
||||
@@ -100,7 +105,9 @@ class PermissionsController extends Controller
|
||||
$book = $this->queries->books->findVisibleBySlugOrFail($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($book, $request);
|
||||
(new DatabaseTransaction(function () use ($book, $request) {
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($book, $request);
|
||||
}))->run();
|
||||
|
||||
$this->showSuccessNotification(trans('entities.books_permissions_updated'));
|
||||
|
||||
@@ -130,7 +137,9 @@ class PermissionsController extends Controller
|
||||
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($shelf, $request);
|
||||
(new DatabaseTransaction(function () use ($shelf, $request) {
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($shelf, $request);
|
||||
}))->run();
|
||||
|
||||
$this->showSuccessNotification(trans('entities.shelves_permissions_updated'));
|
||||
|
||||
@@ -145,7 +154,10 @@ class PermissionsController extends Controller
|
||||
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||
|
||||
$updateCount = $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf);
|
||||
$updateCount = (new DatabaseTransaction(function () use ($shelf) {
|
||||
return $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf);
|
||||
}))->run();
|
||||
|
||||
$this->showSuccessNotification(trans('entities.shelves_copy_permission_success', ['count' => $updateCount]));
|
||||
|
||||
return redirect($shelf->getUrl());
|
||||
|
||||
@@ -7,6 +7,7 @@ use BookStack\Exceptions\PermissionsException;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Permissions\Models\RolePermission;
|
||||
use BookStack\Users\Models\Role;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
@@ -48,38 +49,42 @@ class PermissionsRepo
|
||||
*/
|
||||
public function saveNewRole(array $roleData): Role
|
||||
{
|
||||
$role = new Role($roleData);
|
||||
$role->mfa_enforced = boolval($roleData['mfa_enforced'] ?? false);
|
||||
$role->save();
|
||||
return (new DatabaseTransaction(function () use ($roleData) {
|
||||
$role = new Role($roleData);
|
||||
$role->mfa_enforced = boolval($roleData['mfa_enforced'] ?? false);
|
||||
$role->save();
|
||||
|
||||
$permissions = $roleData['permissions'] ?? [];
|
||||
$this->assignRolePermissions($role, $permissions);
|
||||
$this->permissionBuilder->rebuildForRole($role);
|
||||
$permissions = $roleData['permissions'] ?? [];
|
||||
$this->assignRolePermissions($role, $permissions);
|
||||
$this->permissionBuilder->rebuildForRole($role);
|
||||
|
||||
Activity::add(ActivityType::ROLE_CREATE, $role);
|
||||
Activity::add(ActivityType::ROLE_CREATE, $role);
|
||||
|
||||
return $role;
|
||||
return $role;
|
||||
}))->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing role.
|
||||
* Ensures Admin system role always have core permissions.
|
||||
* Ensures the Admin system role always has core permissions.
|
||||
*/
|
||||
public function updateRole($roleId, array $roleData): Role
|
||||
{
|
||||
$role = $this->getRoleById($roleId);
|
||||
|
||||
if (isset($roleData['permissions'])) {
|
||||
$this->assignRolePermissions($role, $roleData['permissions']);
|
||||
}
|
||||
return (new DatabaseTransaction(function () use ($role, $roleData) {
|
||||
if (isset($roleData['permissions'])) {
|
||||
$this->assignRolePermissions($role, $roleData['permissions']);
|
||||
}
|
||||
|
||||
$role->fill($roleData);
|
||||
$role->save();
|
||||
$this->permissionBuilder->rebuildForRole($role);
|
||||
$role->fill($roleData);
|
||||
$role->save();
|
||||
$this->permissionBuilder->rebuildForRole($role);
|
||||
|
||||
Activity::add(ActivityType::ROLE_UPDATE, $role);
|
||||
Activity::add(ActivityType::ROLE_UPDATE, $role);
|
||||
|
||||
return $role;
|
||||
return $role;
|
||||
}))->run();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +119,7 @@ class PermissionsRepo
|
||||
/**
|
||||
* Delete a role from the system.
|
||||
* Check it's not an admin role or set as default before deleting.
|
||||
* If a migration Role ID is specified the users assign to the current role
|
||||
* If a migration Role ID is specified, the users assigned to the current role
|
||||
* will be added to the role of the specified id.
|
||||
*
|
||||
* @throws PermissionsException
|
||||
@@ -131,17 +136,19 @@ class PermissionsRepo
|
||||
throw new PermissionsException(trans('errors.role_registration_default_cannot_delete'));
|
||||
}
|
||||
|
||||
if ($migrateRoleId !== 0) {
|
||||
$newRole = Role::query()->find($migrateRoleId);
|
||||
if ($newRole) {
|
||||
$users = $role->users()->pluck('id')->toArray();
|
||||
$newRole->users()->sync($users);
|
||||
(new DatabaseTransaction(function () use ($migrateRoleId, $role) {
|
||||
if ($migrateRoleId !== 0) {
|
||||
$newRole = Role::query()->find($migrateRoleId);
|
||||
if ($newRole) {
|
||||
$users = $role->users()->pluck('id')->toArray();
|
||||
$newRole->users()->sync($users);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$role->entityPermissions()->delete();
|
||||
$role->jointPermissions()->delete();
|
||||
Activity::add(ActivityType::ROLE_DELETE, $role);
|
||||
$role->delete();
|
||||
$role->entityPermissions()->delete();
|
||||
$role->jointPermissions()->delete();
|
||||
Activity::add(ActivityType::ROLE_DELETE, $role);
|
||||
$role->delete();
|
||||
}))->run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class SearchApiController extends ApiController
|
||||
{
|
||||
protected $rules = [
|
||||
protected array $rules = [
|
||||
'all' => [
|
||||
'query' => ['required'],
|
||||
'page' => ['integer', 'min:1'],
|
||||
|
||||
@@ -160,7 +160,9 @@ class SearchIndex
|
||||
/** @var DOMNode $child */
|
||||
foreach ($doc->getBodyChildren() as $child) {
|
||||
$nodeName = $child->nodeName;
|
||||
$termCounts = $this->textToTermCountMap(trim($child->textContent));
|
||||
$text = trim($child->textContent);
|
||||
$text = str_replace("\u{00A0}", ' ', $text);
|
||||
$termCounts = $this->textToTermCountMap($text);
|
||||
foreach ($termCounts as $term => $count) {
|
||||
$scoreChange = $count * ($elementScoreAdjustmentMap[$nodeName] ?? 1);
|
||||
$scoresByTerm[$term] = ($scoresByTerm[$term] ?? 0) + $scoreChange;
|
||||
|
||||
@@ -7,6 +7,7 @@ use BookStack\Entities\Queries\BookQueries;
|
||||
use BookStack\Entities\Tools\BookContents;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\Http\Controller;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BookSortController extends Controller
|
||||
@@ -55,16 +56,18 @@ class BookSortController extends Controller
|
||||
|
||||
// Sort via map
|
||||
if ($request->filled('sort-tree')) {
|
||||
$sortMap = BookSortMap::fromJson($request->get('sort-tree'));
|
||||
$booksInvolved = $sorter->sortUsingMap($sortMap);
|
||||
(new DatabaseTransaction(function () use ($book, $request, $sorter, &$loggedActivityForBook) {
|
||||
$sortMap = BookSortMap::fromJson($request->get('sort-tree'));
|
||||
$booksInvolved = $sorter->sortUsingMap($sortMap);
|
||||
|
||||
// Rebuild permissions and add activity for involved books.
|
||||
foreach ($booksInvolved as $bookInvolved) {
|
||||
Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
|
||||
if ($bookInvolved->id === $book->id) {
|
||||
$loggedActivityForBook = true;
|
||||
// Add activity for involved books.
|
||||
foreach ($booksInvolved as $bookInvolved) {
|
||||
Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
|
||||
if ($bookInvolved->id === $book->id) {
|
||||
$loggedActivityForBook = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}))->run();
|
||||
}
|
||||
|
||||
if ($request->filled('auto-sort')) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace BookStack\Sorting;
|
||||
|
||||
use BookStack\App\Model;
|
||||
use BookStack\Entities\Models\Book;
|
||||
use BookStack\Entities\Models\BookChild;
|
||||
use BookStack\Entities\Models\Chapter;
|
||||
|
||||
@@ -50,6 +50,7 @@ class LocaleManager
|
||||
'ku' => 'ku_TR',
|
||||
'lt' => 'lt_LT',
|
||||
'lv' => 'lv_LV',
|
||||
'ne' => 'ne_NP',
|
||||
'nb' => 'nb_NO',
|
||||
'nl' => 'nl_NL',
|
||||
'nn' => 'nn_NO',
|
||||
|
||||
@@ -16,7 +16,7 @@ class RoleApiController extends ApiController
|
||||
'display_name', 'description', 'mfa_enforced', 'external_auth_id', 'created_at', 'updated_at',
|
||||
];
|
||||
|
||||
protected $rules = [
|
||||
protected array $rules = [
|
||||
'create' => [
|
||||
'display_name' => ['required', 'string', 'min:3', 'max:180'],
|
||||
'description' => ['string', 'max:180'],
|
||||
|
||||
42
app/Util/DatabaseTransaction.php
Normal file
42
app/Util/DatabaseTransaction.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Util;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Run the given code within a database transactions.
|
||||
* Wraps Laravel's own transaction method, but sets a specific runtime isolation method.
|
||||
* This sets a session level since this won't cause issues if already within a transaction,
|
||||
* and this should apply to the next transactions anyway.
|
||||
*
|
||||
* "READ COMMITTED" ensures that changes from other transactions can be read within
|
||||
* a transaction, even if started afterward (and for example, it was blocked by the initial
|
||||
* transaction). This is quite important for things like permission generation, where we would
|
||||
* want to consider the changes made by other committed transactions by the time we come to
|
||||
* regenerate permission access.
|
||||
*
|
||||
* @throws Throwable
|
||||
* @template TReturn of mixed
|
||||
*/
|
||||
class DatabaseTransaction
|
||||
{
|
||||
/**
|
||||
* @param (Closure(static): TReturn) $callback
|
||||
*/
|
||||
public function __construct(
|
||||
protected Closure $callback
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TReturn
|
||||
*/
|
||||
public function run(): mixed
|
||||
{
|
||||
DB::statement('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED');
|
||||
return DB::transaction($this->callback);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ namespace BookStack\Util;
|
||||
|
||||
use DOMAttr;
|
||||
use DOMElement;
|
||||
use DOMNamedNodeMap;
|
||||
use DOMNode;
|
||||
|
||||
/**
|
||||
@@ -25,6 +24,7 @@ class HtmlDescriptionFilter
|
||||
'ul' => [],
|
||||
'li' => [],
|
||||
'strong' => [],
|
||||
'span' => [],
|
||||
'em' => [],
|
||||
'br' => [],
|
||||
];
|
||||
@@ -59,7 +59,6 @@ class HtmlDescriptionFilter
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var DOMNamedNodeMap $attrs */
|
||||
$attrs = $element->attributes;
|
||||
for ($i = $attrs->length - 1; $i >= 0; $i--) {
|
||||
/** @var DOMAttr $attr */
|
||||
@@ -70,7 +69,8 @@ class HtmlDescriptionFilter
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($element->childNodes as $child) {
|
||||
$childNodes = [...$element->childNodes];
|
||||
foreach ($childNodes as $child) {
|
||||
if ($child instanceof DOMElement) {
|
||||
static::filterElement($child);
|
||||
}
|
||||
|
||||
@@ -38,8 +38,7 @@
|
||||
"socialiteproviders/microsoft-azure": "^5.1",
|
||||
"socialiteproviders/okta": "^4.2",
|
||||
"socialiteproviders/twitch": "^5.3",
|
||||
"ssddanbrown/htmldiff": "^1.0.2",
|
||||
"ssddanbrown/symfony-mailer": "7.2.x-dev"
|
||||
"ssddanbrown/htmldiff": "^2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.21",
|
||||
|
||||
627
composer.lock
generated
627
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@ class ImportFactory extends Factory
|
||||
'path' => 'uploads/files/imports/' . Str::random(10) . '.zip',
|
||||
'name' => $this->faker->words(3, true),
|
||||
'type' => 'book',
|
||||
'size' => rand(1, 1001),
|
||||
'metadata' => '{"name": "My book"}',
|
||||
'created_at' => User::factory(),
|
||||
];
|
||||
|
||||
4
dev/api/requests/imports-run.json
Normal file
4
dev/api/requests/imports-run.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"parent_type": "book",
|
||||
"parent_id": 28
|
||||
}
|
||||
10
dev/api/responses/imports-create.json
Normal file
10
dev/api/responses/imports-create.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"type": "chapter",
|
||||
"name": "Pension Providers",
|
||||
"created_by": 1,
|
||||
"size": 2757,
|
||||
"path": "uploads\/files\/imports\/ghnxmS3u9QxLWu82.zip",
|
||||
"updated_at": "2025-07-18T14:50:27.000000Z",
|
||||
"created_at": "2025-07-18T14:50:27.000000Z",
|
||||
"id": 31
|
||||
}
|
||||
23
dev/api/responses/imports-list.json
Normal file
23
dev/api/responses/imports-list.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": 25,
|
||||
"name": "IT Department",
|
||||
"size": 618462,
|
||||
"type": "book",
|
||||
"created_by": 1,
|
||||
"created_at": "2024-12-20T18:40:38.000000Z",
|
||||
"updated_at": "2024-12-20T18:40:38.000000Z"
|
||||
},
|
||||
{
|
||||
"id": 27,
|
||||
"name": "Clients",
|
||||
"size": 15364,
|
||||
"type": "chapter",
|
||||
"created_by": 1,
|
||||
"created_at": "2025-03-20T12:41:44.000000Z",
|
||||
"updated_at": "2025-03-20T12:41:44.000000Z"
|
||||
}
|
||||
],
|
||||
"total": 2
|
||||
}
|
||||
51
dev/api/responses/imports-read.json
Normal file
51
dev/api/responses/imports-read.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"id": 25,
|
||||
"name": "IT Department",
|
||||
"path": "uploads\/files\/imports\/7YOpZ6sGIEbYdRFL.zip",
|
||||
"size": 618462,
|
||||
"type": "book",
|
||||
"created_by": 1,
|
||||
"created_at": "2024-12-20T18:40:38.000000Z",
|
||||
"updated_at": "2024-12-20T18:40:38.000000Z",
|
||||
"details": {
|
||||
"id": 4,
|
||||
"name": "IT Department",
|
||||
"chapters": [
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Server Systems",
|
||||
"priority": 1,
|
||||
"pages": [
|
||||
{
|
||||
"id": 22,
|
||||
"name": "prod-aws-stonehawk",
|
||||
"priority": 0,
|
||||
"attachments": [],
|
||||
"images": [],
|
||||
"tags": []
|
||||
}
|
||||
],
|
||||
"tags": []
|
||||
}
|
||||
],
|
||||
"pages": [
|
||||
{
|
||||
"id": 23,
|
||||
"name": "Member Onboarding Guide",
|
||||
"priority": 0,
|
||||
"attachments": [],
|
||||
"images": [],
|
||||
"tags": []
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"name": "IT Holiday Party Event",
|
||||
"priority": 2,
|
||||
"attachments": [],
|
||||
"images": [],
|
||||
"tags": []
|
||||
}
|
||||
],
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
14
dev/api/responses/imports-run.json
Normal file
14
dev/api/responses/imports-run.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"id": 1067,
|
||||
"book_id": 28,
|
||||
"slug": "pension-providers",
|
||||
"name": "Pension Providers",
|
||||
"description": "Details on the various pension providers that are available",
|
||||
"priority": 7,
|
||||
"created_at": "2025-07-18T14:53:35.000000Z",
|
||||
"updated_at": "2025-07-18T14:53:36.000000Z",
|
||||
"created_by": 1,
|
||||
"updated_by": 1,
|
||||
"owned_by": 1,
|
||||
"default_template_id": null
|
||||
}
|
||||
@@ -13,7 +13,7 @@ const entryPoints = {
|
||||
app: path.join(__dirname, '../../resources/js/app.ts'),
|
||||
code: path.join(__dirname, '../../resources/js/code/index.mjs'),
|
||||
'legacy-modes': path.join(__dirname, '../../resources/js/code/legacy-modes.mjs'),
|
||||
markdown: path.join(__dirname, '../../resources/js/markdown/index.mjs'),
|
||||
markdown: path.join(__dirname, '../../resources/js/markdown/index.mts'),
|
||||
wysiwyg: path.join(__dirname, '../../resources/js/wysiwyg/index.ts'),
|
||||
};
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
1bfc7abbc1d913f6e98b40258cb0b440157e28e381505d10c25132c969b9eb5a
|
||||
ecb1c038267dde9336e703e14a89d43848880ebb630465e313b4726570f2db04
|
||||
@@ -345,7 +345,7 @@ Link: tj/co
|
||||
codemirror
|
||||
License: MIT
|
||||
License File: node_modules/codemirror/LICENSE
|
||||
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <*******@*****.***> and others
|
||||
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <******@*********.******> and others
|
||||
Source: https://github.com/codemirror/basic-setup.git
|
||||
Link: https://github.com/codemirror/basic-setup.git
|
||||
-----------
|
||||
@@ -711,13 +711,13 @@ eslint-scope
|
||||
License: BSD-2-Clause
|
||||
License File: node_modules/eslint-scope/LICENSE
|
||||
Copyright: Copyright (C) 2012-2013 Yusuke Suzuki (twitter: @Constellation) and other contributors.
|
||||
Source: eslint/js
|
||||
Source: https://github.com/eslint/js.git
|
||||
Link: https://github.com/eslint/js/blob/main/packages/eslint-scope/README.md
|
||||
-----------
|
||||
eslint-visitor-keys
|
||||
License: Apache-2.0
|
||||
License File: node_modules/eslint-visitor-keys/LICENSE
|
||||
Source: eslint/js
|
||||
Source: https://github.com/eslint/js.git
|
||||
Link: https://github.com/eslint/js/blob/main/packages/eslint-visitor-keys/README.md
|
||||
-----------
|
||||
eslint
|
||||
@@ -731,7 +731,7 @@ License: BSD-2-Clause
|
||||
License File: node_modules/espree/LICENSE
|
||||
Copyright: Copyright (c) Open JS Foundation
|
||||
All rights reserved.
|
||||
Source: eslint/js
|
||||
Source: https://github.com/eslint/js.git
|
||||
Link: https://github.com/eslint/js/blob/main/packages/espree/README.md
|
||||
-----------
|
||||
esprima
|
||||
@@ -1252,6 +1252,13 @@ Copyright: Copyright (c) 2019 Inspect JS
|
||||
Source: git+https://github.com/inspect-js/is-map.git
|
||||
Link: https://github.com/inspect-js/is-map#readme
|
||||
-----------
|
||||
is-negative-zero
|
||||
License: MIT
|
||||
License File: node_modules/is-negative-zero/LICENSE
|
||||
Copyright: Copyright (c) 2014 Jordan Harband
|
||||
Source: git://github.com/inspect-js/is-negative-zero.git
|
||||
Link: https://github.com/inspect-js/is-negative-zero
|
||||
-----------
|
||||
is-number-object
|
||||
License: MIT
|
||||
License File: node_modules/is-number-object/LICENSE
|
||||
@@ -2493,6 +2500,13 @@ Copyright: Copyright (c) 2016-2022 Isaac Z. Schlueter <*@***.**>, James Talmage
|
||||
Source: tapjs/stack-utils
|
||||
Link: tapjs/stack-utils
|
||||
-----------
|
||||
stop-iteration-iterator
|
||||
License: MIT
|
||||
License File: node_modules/stop-iteration-iterator/LICENSE
|
||||
Copyright: Copyright (c) 2023 Jordan Harband
|
||||
Source: git+https://github.com/ljharb/stop-iteration-iterator.git
|
||||
Link: https://github.com/ljharb/stop-iteration-iterator#readme
|
||||
-----------
|
||||
string-length
|
||||
License: MIT
|
||||
License File: node_modules/string-length/license
|
||||
@@ -2992,6 +3006,13 @@ Copyright: Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||
Source: https://github.com/babel/babel.git
|
||||
Link: https://github.com/babel/babel.git
|
||||
-----------
|
||||
@babel/helper-globals
|
||||
License: MIT
|
||||
License File: node_modules/@babel/helper-globals/LICENSE
|
||||
Copyright: Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||
Source: https://github.com/babel/babel.git
|
||||
Link: https://github.com/babel/babel.git
|
||||
-----------
|
||||
@babel/helper-module-imports
|
||||
License: MIT
|
||||
License File: node_modules/@babel/helper-module-imports/LICENSE
|
||||
@@ -3038,7 +3059,7 @@ Link: https://github.com/babel/babel.git
|
||||
License: MIT
|
||||
License File: node_modules/@babel/helpers/LICENSE
|
||||
Copyright: Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||
Copyright (c) 2014-present, Facebook, Inc. (ONLY ./src/helpers/regeneratorRuntime.js)
|
||||
Copyright (c) 2014-present, Facebook, Inc. (ONLY ./src/helpers/regenerator* files)
|
||||
Source: https://github.com/babel/babel.git
|
||||
Link: https://babel.dev/docs/en/next/babel-helpers
|
||||
-----------
|
||||
@@ -3233,7 +3254,7 @@ Link: https://github.com/codemirror/lang-javascript.git
|
||||
@codemirror/lang-json
|
||||
License: MIT
|
||||
License File: node_modules/@codemirror/lang-json/LICENSE
|
||||
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <*******@*****.***> and others
|
||||
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <******@*********.******> and others
|
||||
Source: https://github.com/codemirror/lang-json.git
|
||||
Link: https://github.com/codemirror/lang-json.git
|
||||
-----------
|
||||
@@ -3247,7 +3268,7 @@ Link: https://github.com/codemirror/lang-markdown.git
|
||||
@codemirror/lang-php
|
||||
License: MIT
|
||||
License File: node_modules/@codemirror/lang-php/LICENSE
|
||||
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <*******@*****.***> and others
|
||||
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <******@*********.******> and others
|
||||
Source: https://github.com/codemirror/lang-php.git
|
||||
Link: https://github.com/codemirror/lang-php.git
|
||||
-----------
|
||||
@@ -3337,7 +3358,7 @@ Link: https://github.com/eslint-community/regexpp#readme
|
||||
License: Apache-2.0
|
||||
License File: node_modules/@eslint/config-array/LICENSE
|
||||
Source: git+https://github.com/eslint/rewrite.git
|
||||
Link: https://github.com/eslint/rewrite#readme
|
||||
Link: https://github.com/eslint/rewrite/tree/main/packages/config-array#readme
|
||||
-----------
|
||||
@eslint/config-helpers
|
||||
License: Apache-2.0
|
||||
@@ -3349,7 +3370,7 @@ Link: https://github.com/eslint/rewrite/tree/main/packages/config-helpers#readme
|
||||
License: Apache-2.0
|
||||
License File: node_modules/@eslint/core/LICENSE
|
||||
Source: git+https://github.com/eslint/rewrite.git
|
||||
Link: https://github.com/eslint/rewrite#readme
|
||||
Link: https://github.com/eslint/rewrite/tree/main/packages/core#readme
|
||||
-----------
|
||||
@eslint/eslintrc
|
||||
License: MIT
|
||||
@@ -3373,7 +3394,7 @@ Link: https://github.com/eslint/rewrite#readme
|
||||
License: Apache-2.0
|
||||
License File: node_modules/@eslint/plugin-kit/LICENSE
|
||||
Source: git+https://github.com/eslint/rewrite.git
|
||||
Link: https://github.com/eslint/rewrite#readme
|
||||
Link: https://github.com/eslint/rewrite/tree/main/packages/plugin-kit#readme
|
||||
-----------
|
||||
@humanfs/core
|
||||
License: Apache-2.0
|
||||
@@ -3514,9 +3535,9 @@ Link: https://github.com/jestjs/jest.git
|
||||
@jridgewell/gen-mapping
|
||||
License: MIT
|
||||
License File: node_modules/@jridgewell/gen-mapping/LICENSE
|
||||
Copyright: Copyright 2022 Justin Ridgewell <**********@******.***>
|
||||
Source: https://github.com/jridgewell/gen-mapping
|
||||
Link: https://github.com/jridgewell/gen-mapping
|
||||
Copyright: Copyright 2024 Justin Ridgewell <******@*********.****>
|
||||
Source: git+https://github.com/jridgewell/sourcemaps.git
|
||||
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/gen-mapping
|
||||
-----------
|
||||
@jridgewell/resolve-uri
|
||||
License: MIT
|
||||
@@ -3525,26 +3546,19 @@ Copyright: Copyright 2019 Justin Ridgewell <**********@******.***>
|
||||
Source: https://github.com/jridgewell/resolve-uri
|
||||
Link: https://github.com/jridgewell/resolve-uri
|
||||
-----------
|
||||
@jridgewell/set-array
|
||||
License: MIT
|
||||
License File: node_modules/@jridgewell/set-array/LICENSE
|
||||
Copyright: Copyright 2022 Justin Ridgewell <**********@******.***>
|
||||
Source: https://github.com/jridgewell/set-array
|
||||
Link: https://github.com/jridgewell/set-array
|
||||
-----------
|
||||
@jridgewell/sourcemap-codec
|
||||
License: MIT
|
||||
License File: node_modules/@jridgewell/sourcemap-codec/LICENSE
|
||||
Copyright: Copyright (c) 2015 Rich Harris
|
||||
Source: git+https://github.com/jridgewell/sourcemap-codec.git
|
||||
Link: git+https://github.com/jridgewell/sourcemap-codec.git
|
||||
Copyright: Copyright 2024 Justin Ridgewell <******@*********.****>
|
||||
Source: git+https://github.com/jridgewell/sourcemaps.git
|
||||
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/sourcemap-codec
|
||||
-----------
|
||||
@jridgewell/trace-mapping
|
||||
License: MIT
|
||||
License File: node_modules/@jridgewell/trace-mapping/LICENSE
|
||||
Copyright: Copyright 2022 Justin Ridgewell <******@*********.****>
|
||||
Source: git+https://github.com/jridgewell/trace-mapping.git
|
||||
Link: git+https://github.com/jridgewell/trace-mapping.git
|
||||
Copyright: Copyright 2024 Justin Ridgewell <******@*********.****>
|
||||
Source: git+https://github.com/jridgewell/sourcemaps.git
|
||||
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/trace-mapping
|
||||
-----------
|
||||
@lezer/common
|
||||
License: MIT
|
||||
@@ -3813,6 +3827,27 @@ License: MIT
|
||||
Source: https://www.github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
Link: https://www.github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
-----------
|
||||
@types/linkify-it
|
||||
License: MIT
|
||||
License File: node_modules/@types/linkify-it/LICENSE
|
||||
Copyright: Copyright (c) Microsoft Corporation.
|
||||
Source: https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
Link: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/linkify-it
|
||||
-----------
|
||||
@types/markdown-it
|
||||
License: MIT
|
||||
License File: node_modules/@types/markdown-it/LICENSE
|
||||
Copyright: Copyright (c) Microsoft Corporation.
|
||||
Source: https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
Link: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/markdown-it
|
||||
-----------
|
||||
@types/mdurl
|
||||
License: MIT
|
||||
License File: node_modules/@types/mdurl/LICENSE
|
||||
Copyright: Copyright (c) Microsoft Corporation.
|
||||
Source: https://github.com/DefinitelyTyped/DefinitelyTyped.git
|
||||
Link: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mdurl
|
||||
-----------
|
||||
@types/node
|
||||
License: MIT
|
||||
License File: node_modules/@types/node/LICENSE
|
||||
|
||||
@@ -486,7 +486,7 @@ Link: https://github.com/ramsey/collection.git
|
||||
ramsey/uuid
|
||||
License: MIT
|
||||
License File: vendor/ramsey/uuid/LICENSE
|
||||
Copyright: Copyright (c) 2012-2023 Ben Ramsey <***@*********.***>
|
||||
Copyright: Copyright (c) 2012-2025 Ben Ramsey <***@*********.***>
|
||||
Source: https://github.com/ramsey/uuid.git
|
||||
Link: https://github.com/ramsey/uuid.git
|
||||
-----------
|
||||
@@ -543,13 +543,6 @@ Copyright: Copyright (c) 2024 Nathan Herald, Rohland de Charmoy, Dan Brown
|
||||
Source: https://codeberg.org/danb/HtmlDiff
|
||||
Link: https://codeberg.org/danb/HtmlDiff
|
||||
-----------
|
||||
ssddanbrown/symfony-mailer
|
||||
License: MIT
|
||||
License File: vendor/ssddanbrown/symfony-mailer/LICENSE
|
||||
Copyright: Copyright (c) 2019-present Fabien Potencier
|
||||
Source: https://github.com/ssddanbrown/symfony-mailer.git
|
||||
Link: https://symfony.com
|
||||
-----------
|
||||
symfony/clock
|
||||
License: MIT
|
||||
License File: vendor/symfony/clock/LICENSE
|
||||
@@ -620,6 +613,13 @@ Copyright: Copyright (c) 2004-present Fabien Potencier
|
||||
Source: https://github.com/symfony/http-kernel.git
|
||||
Link: https://symfony.com
|
||||
-----------
|
||||
symfony/mailer
|
||||
License: MIT
|
||||
License File: vendor/symfony/mailer/LICENSE
|
||||
Copyright: Copyright (c) 2019-present Fabien Potencier
|
||||
Source: https://github.com/symfony/mailer.git
|
||||
Link: https://symfony.com
|
||||
-----------
|
||||
symfony/mime
|
||||
License: MIT
|
||||
License File: vendor/symfony/mime/LICENSE
|
||||
|
||||
@@ -30,8 +30,8 @@ return [
|
||||
'create' => 'إنشاء',
|
||||
'update' => 'تحديث',
|
||||
'edit' => 'تعديل',
|
||||
'archive' => 'Archive',
|
||||
'unarchive' => 'Un-Archive',
|
||||
'archive' => 'أرشف',
|
||||
'unarchive' => 'إلغاء الأرشفة',
|
||||
'sort' => 'سرد',
|
||||
'move' => 'نقل',
|
||||
'copy' => 'نسخ',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'نص مرتفع',
|
||||
'subscript' => 'نص منخفض',
|
||||
'text_color' => 'لون النص',
|
||||
'highlight_color' => 'لون التمييز',
|
||||
'custom_color' => 'لون مخصص',
|
||||
'remove_color' => 'إزالة اللون',
|
||||
'background_color' => 'لون الخلفية',
|
||||
|
||||
@@ -248,7 +248,7 @@ return [
|
||||
'pages_edit_switch_to_markdown_stable' => '(محتوى مستقر)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'التبديل إلى محرر ما تراه هو ما تحصل عليه -WYSIWYG-',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'التبديل إلى محرر ما تراه هو ما تحصل عليه الجديد -new WYSIWYG-',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(في الاختبار التجريبي)',
|
||||
'pages_edit_set_changelog' => 'تثبيت سجل التعديل',
|
||||
'pages_edit_enter_changelog_desc' => 'ضع وصف مختصر للتعديلات التي تمت',
|
||||
'pages_edit_enter_changelog' => 'أدخل سجل التعديل',
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'إدخال رسمة',
|
||||
'pages_md_show_preview' => 'عرض المعاينة',
|
||||
'pages_md_sync_scroll' => 'مزامنة معاينة التمرير',
|
||||
'pages_md_plain_editor' => 'محرر النصوص العادي',
|
||||
'pages_drawing_unsaved' => 'تم العثور على رسم غير محفوظ',
|
||||
'pages_drawing_unsaved_confirm' => 'تم العثور على بيانات رسم غير محفوظة من محاولة حفظ رسم سابقة فاشلة. هل ترغب في استعادة هذا الرسم غير المحفوظ ومواصلة تحريره؟',
|
||||
'pages_not_in_chapter' => 'صفحة ليست في فصل',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Горен индекс',
|
||||
'subscript' => 'Долен индекс',
|
||||
'text_color' => 'Цвят на текста',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Цвят по избор',
|
||||
'remove_color' => 'Премахване на цвят',
|
||||
'background_color' => 'Фонов цвят',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Вмъкни рисунка',
|
||||
'pages_md_show_preview' => 'Show preview',
|
||||
'pages_md_sync_scroll' => 'Sync preview scroll',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
|
||||
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
|
||||
'pages_not_in_chapter' => 'Страницата не принадлежи в никоя глава',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Superscript',
|
||||
'subscript' => 'Subscript',
|
||||
'text_color' => 'Text color',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Custom color',
|
||||
'remove_color' => 'Remove color',
|
||||
'background_color' => 'Background color',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Insert Drawing',
|
||||
'pages_md_show_preview' => 'Show preview',
|
||||
'pages_md_sync_scroll' => 'Sync preview scroll',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
|
||||
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
|
||||
'pages_not_in_chapter' => 'Page is not in a chapter',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Superscript',
|
||||
'subscript' => 'Subscript',
|
||||
'text_color' => 'Text color',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Custom color',
|
||||
'remove_color' => 'Remove color',
|
||||
'background_color' => 'Background color',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Insert Drawing',
|
||||
'pages_md_show_preview' => 'Show preview',
|
||||
'pages_md_sync_scroll' => 'Sync preview scroll',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
|
||||
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
|
||||
'pages_not_in_chapter' => 'Page is not in a chapter',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Superíndex',
|
||||
'subscript' => 'Subíndex',
|
||||
'text_color' => 'Color del text',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Color personalitzat',
|
||||
'remove_color' => 'Elimina el color',
|
||||
'background_color' => 'Color de fons',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Insereix un dibuix',
|
||||
'pages_md_show_preview' => 'Mostra la visualització prèvia',
|
||||
'pages_md_sync_scroll' => 'Sincronitza el desplaçament de la visualització prèvia',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'S’ha trobat un dibuix sense desar',
|
||||
'pages_drawing_unsaved_confirm' => 'S’han trobat dades d’un dibuix d’un intent anterior de desar un dibuix. Voleu restaurar aquest dibuix no desat per a reprendre’n l’edició?',
|
||||
'pages_not_in_chapter' => 'La pàgina no és un capítol',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -30,8 +30,8 @@ return [
|
||||
'create' => 'Vytvořit',
|
||||
'update' => 'Aktualizovat',
|
||||
'edit' => 'Upravit',
|
||||
'archive' => 'Archive',
|
||||
'unarchive' => 'Un-Archive',
|
||||
'archive' => 'Archivovat',
|
||||
'unarchive' => 'Od-Archivovat',
|
||||
'sort' => 'Seřadit',
|
||||
'move' => 'Přesunout',
|
||||
'copy' => 'Kopírovat',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'horní index',
|
||||
'subscript' => 'Dolní index',
|
||||
'text_color' => 'Barva textu:',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Vlastní barva',
|
||||
'remove_color' => 'Odstranit barvu',
|
||||
'background_color' => 'Barva pozadí',
|
||||
|
||||
@@ -134,7 +134,7 @@ return [
|
||||
'shelves_copy_permissions_to_books' => 'Kopírovat oprávnění na knihy',
|
||||
'shelves_copy_permissions' => 'Kopírovat oprávnění',
|
||||
'shelves_copy_permissions_explain' => 'Tímto se použije aktuální nastavení oprávnění police na všechny knihy v ní obsažené. Před aktivací se ujistěte, že byly uloženy všechny změny oprávnění této police.',
|
||||
'shelves_copy_permission_success' => 'Oprávnění police byla zkopírována na :count knih',
|
||||
'shelves_copy_permission_success' => '{1}Oprávnění police byla zkopírována na :count knihu|[2,4]Oprávnění police byla zkopírována na :count knihy|[5,*]Oprávnění police byla zkopírována na :count knih',
|
||||
|
||||
// Books
|
||||
'book' => 'Kniha',
|
||||
@@ -194,7 +194,7 @@ return [
|
||||
// Chapters
|
||||
'chapter' => 'Kapitola',
|
||||
'chapters' => 'Kapitoly',
|
||||
'x_chapters' => '{0}:count Kapitol|{1}:count Kapitola|[2,4]:count Kapitoly|[5,*]:count Kapitol',
|
||||
'x_chapters' => '{0}:count kapitol|{1}:count kapitola|[2,4]:count kapitoly|[5,*]:count kapitol',
|
||||
'chapters_popular' => 'Populární kapitoly',
|
||||
'chapters_new' => 'Nová kapitola',
|
||||
'chapters_create' => 'Vytvořit novou kapitolu',
|
||||
@@ -219,7 +219,7 @@ return [
|
||||
// Pages
|
||||
'page' => 'Stránka',
|
||||
'pages' => 'Stránky',
|
||||
'x_pages' => '{0}:count Stran|{1}:count Strana|[2,4]:count Strany|[5,*]:count Stran',
|
||||
'x_pages' => '{0}:count stran|{1}:count strana|[2,4]:count strany|[5,*]:count stran',
|
||||
'pages_popular' => 'Populární stránky',
|
||||
'pages_new' => 'Nová stránka',
|
||||
'pages_attachments' => 'Přílohy',
|
||||
@@ -248,7 +248,7 @@ return [
|
||||
'pages_edit_switch_to_markdown_stable' => '(Stabilní obsah)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Přepnout na WYSIWYG Editor',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Přepnout na nový WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(V beta testování)',
|
||||
'pages_edit_set_changelog' => 'Nastavit protokol změn',
|
||||
'pages_edit_enter_changelog_desc' => 'Zadejte stručný popis změn, které jste provedli',
|
||||
'pages_edit_enter_changelog' => 'Zadejte protokol změn',
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Vložit kresbu',
|
||||
'pages_md_show_preview' => 'Zobrazit náhled',
|
||||
'pages_md_sync_scroll' => 'Synchronizovat náhled',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Nalezen neuložený výkres',
|
||||
'pages_drawing_unsaved_confirm' => 'Byly nalezeny neuložené kresby z předchozí neúspěšné pokusu o uložení kresby. Chcete je obnovit a pokračovat v úpravě této neuložené kresby?',
|
||||
'pages_not_in_chapter' => 'Stránka není v kapitole',
|
||||
@@ -312,7 +313,7 @@ return [
|
||||
'pages_draft_edited_notification' => 'Tato stránka se od té doby změnila. Je doporučeno aktuální koncept zahodit.',
|
||||
'pages_draft_page_changed_since_creation' => 'Tato stránka byla aktualizována od vytvoření tohoto konceptu. Doporučuje se zrušit tento koncept nebo se postarat o to, abyste si nepřepsali žádné již zadané změny.',
|
||||
'pages_draft_edit_active' => [
|
||||
'start_a' => 'Uživatelé začali upravovat tuto stránku (celkem :count)',
|
||||
'start_a' => '{1}:count uživatel začal upravovat tuto stránku|[2,4]:count uživatelé začali upravovat tuto stránku|[5,*]:count uživatelů začalo upravovat tuto stránku',
|
||||
'start_b' => ':userName začal/a upravovat tuto stránku',
|
||||
'time_a' => 'od doby, kdy byla tato stránky naposledy aktualizována',
|
||||
'time_b' => 'v posledních minutách (:minCount min.)',
|
||||
@@ -342,7 +343,7 @@ return [
|
||||
'tags_assigned_chapters' => 'Přiřazeno ke kapitolám',
|
||||
'tags_assigned_books' => 'Přiřazeno ke knihám',
|
||||
'tags_assigned_shelves' => 'Přiřazeno k policím',
|
||||
'tags_x_unique_values' => ':count jedinečných hodnot',
|
||||
'tags_x_unique_values' => '{1}:count jedinečná hodnota|[2,4]:count jedinečné hodnoty|[5,*]:count jedinečných hodnot',
|
||||
'tags_all_values' => 'Všechny hodnoty',
|
||||
'tags_view_tags' => 'Zobrazit štítky',
|
||||
'tags_view_existing_tags' => 'Zobrazit existující štítky',
|
||||
@@ -392,11 +393,11 @@ return [
|
||||
'comment' => 'Komentář',
|
||||
'comments' => 'Komentáře',
|
||||
'comment_add' => 'Přidat komentář',
|
||||
'comment_none' => 'No comments to display',
|
||||
'comment_none' => 'Žádné komentáře k zobrazení',
|
||||
'comment_placeholder' => 'Zde zadejte komentář',
|
||||
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
|
||||
'comment_archived_count' => ':count Archived',
|
||||
'comment_archived_threads' => 'Archived Threads',
|
||||
'comment_thread_count' => '{0}:count vláken komentářů|{1}:count vlákno komentářů|[2,4]:count vlákna komentářů|[5,*]:count vláken komentářů',
|
||||
'comment_archived_count' => '[0,1]:count archivováno|[2,4]:count archivována|[5,*]:count archivováno',
|
||||
'comment_archived_threads' => 'Archivovaná vlákna',
|
||||
'comment_save' => 'Uložit komentář',
|
||||
'comment_new' => 'Nový komentář',
|
||||
'comment_created' => 'komentováno :createDiff',
|
||||
@@ -405,14 +406,14 @@ return [
|
||||
'comment_deleted_success' => 'Komentář odstraněn',
|
||||
'comment_created_success' => 'Komentář přidán',
|
||||
'comment_updated_success' => 'Komentář aktualizován',
|
||||
'comment_archive_success' => 'Comment archived',
|
||||
'comment_unarchive_success' => 'Comment un-archived',
|
||||
'comment_view' => 'View comment',
|
||||
'comment_jump_to_thread' => 'Jump to thread',
|
||||
'comment_archive_success' => 'Komentář archivován',
|
||||
'comment_unarchive_success' => 'Komentář od-archivován',
|
||||
'comment_view' => 'Zobrazit komentář',
|
||||
'comment_jump_to_thread' => 'Přejít na vlákno',
|
||||
'comment_delete_confirm' => 'Opravdu chcete odstranit tento komentář?',
|
||||
'comment_in_reply_to' => 'Odpověď na :commentId',
|
||||
'comment_reference' => 'Reference',
|
||||
'comment_reference_outdated' => '(Outdated)',
|
||||
'comment_reference' => 'Odkaz',
|
||||
'comment_reference_outdated' => '(Zastaralý)',
|
||||
'comment_editor_explain' => 'Zde jsou komentáře, které zůstaly na této stránce. Komentáře lze přidat a spravovat při prohlížení uložené stránky.',
|
||||
|
||||
// Revision
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Uwchysgrif',
|
||||
'subscript' => 'Isysgrif',
|
||||
'text_color' => 'Lliw testun',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Lliw addasu',
|
||||
'remove_color' => 'Dileu lliw',
|
||||
'background_color' => 'Lliw cefnder',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Mewnosod Llun',
|
||||
'pages_md_show_preview' => 'Dangos rhagolwg',
|
||||
'pages_md_sync_scroll' => 'Cydamseru sgrôl ragolwg',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Canfuwyd Llun heb ei Gadw',
|
||||
'pages_drawing_unsaved_confirm' => 'Canfuwyd data llun heb ei gadw o ymgais aflwyddiannus blaenorol i gadw llun. Hoffech chi adfer a pharhau i olygu\'r llun heb ei gadw?',
|
||||
'pages_not_in_chapter' => 'Nid yw\'r dudalen mewn pennod',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Hævet',
|
||||
'subscript' => 'Sænket',
|
||||
'text_color' => 'Tekstfarve',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Tilpasset farve',
|
||||
'remove_color' => 'Fjern farve',
|
||||
'background_color' => 'Baggrundsfarve',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Indsæt tegning',
|
||||
'pages_md_show_preview' => 'Vis forhåndsvisning',
|
||||
'pages_md_sync_scroll' => 'Rulning af forhåndsvisning af synkronisering',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Ikke gemt tegning fundet',
|
||||
'pages_drawing_unsaved_confirm' => 'Der blev fundet ikke-gemte tegningsdata fra et tidligere mislykket forsøg på at gemme en tegning. Vil du gendanne og fortsætte med at redigere denne ikke-gemte tegning?',
|
||||
'pages_not_in_chapter' => 'Side er ikke i et kapitel',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -30,8 +30,8 @@ return [
|
||||
'create' => 'Erstellen',
|
||||
'update' => 'Aktualisieren',
|
||||
'edit' => 'Bearbeiten',
|
||||
'archive' => 'Archive',
|
||||
'unarchive' => 'Un-Archive',
|
||||
'archive' => 'Archivieren',
|
||||
'unarchive' => 'Nicht mehr archivieren',
|
||||
'sort' => 'Sortieren',
|
||||
'move' => 'Verschieben',
|
||||
'copy' => 'Kopieren',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Hochgestellt',
|
||||
'subscript' => 'Tiefgestellt',
|
||||
'text_color' => 'Schriftfarbe',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Benutzerdefinierte Farbe',
|
||||
'remove_color' => 'Farbe entfernen',
|
||||
'background_color' => 'Hintergrundfarbe',
|
||||
|
||||
@@ -248,7 +248,7 @@ return [
|
||||
'pages_edit_switch_to_markdown_stable' => '(Stabiler Inhalt)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Zum WYSIWYG-Editor wechseln',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Zum neuen WYSIWYG wechseln',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(Im Beta-Test)',
|
||||
'pages_edit_set_changelog' => 'Änderungsprotokoll hinzufügen',
|
||||
'pages_edit_enter_changelog_desc' => 'Bitte geben Sie eine kurze Zusammenfassung Ihrer Änderungen ein',
|
||||
'pages_edit_enter_changelog' => 'Änderungsprotokoll eingeben',
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Zeichnung einfügen',
|
||||
'pages_md_show_preview' => 'Vorschau anzeigen',
|
||||
'pages_md_sync_scroll' => 'Vorschau synchronisieren',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Ungespeicherte Zeichnung gefunden',
|
||||
'pages_drawing_unsaved_confirm' => 'Es wurden ungespeicherte Zeichnungsdaten von einem früheren, fehlgeschlagenen Versuch, die Zeichnung zu speichern, gefunden. Möchten Sie diese ungespeicherte Zeichnung wiederherstellen und weiter bearbeiten?',
|
||||
'pages_not_in_chapter' => 'Seite ist in keinem Kapitel',
|
||||
@@ -392,11 +393,11 @@ return [
|
||||
'comment' => 'Kommentar',
|
||||
'comments' => 'Kommentare',
|
||||
'comment_add' => 'Kommentieren',
|
||||
'comment_none' => 'No comments to display',
|
||||
'comment_none' => 'Keine Kommentare vorhanden',
|
||||
'comment_placeholder' => 'Geben Sie hier Ihre Kommentare ein',
|
||||
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
|
||||
'comment_archived_count' => ':count Archived',
|
||||
'comment_archived_threads' => 'Archived Threads',
|
||||
'comment_thread_count' => ':count Thema|:count Themen',
|
||||
'comment_archived_count' => ':count archiviert',
|
||||
'comment_archived_threads' => 'Archivierte Themen',
|
||||
'comment_save' => 'Kommentar speichern',
|
||||
'comment_new' => 'Neuer Kommentar',
|
||||
'comment_created' => ':createDiff kommentiert',
|
||||
@@ -405,14 +406,14 @@ return [
|
||||
'comment_deleted_success' => 'Kommentar gelöscht',
|
||||
'comment_created_success' => 'Kommentar hinzugefügt',
|
||||
'comment_updated_success' => 'Kommentar aktualisiert',
|
||||
'comment_archive_success' => 'Comment archived',
|
||||
'comment_unarchive_success' => 'Comment un-archived',
|
||||
'comment_view' => 'View comment',
|
||||
'comment_jump_to_thread' => 'Jump to thread',
|
||||
'comment_archive_success' => 'Kommentar archiviert',
|
||||
'comment_unarchive_success' => 'Kommentar nicht mehr archiviert',
|
||||
'comment_view' => 'Kommentar ansehen',
|
||||
'comment_jump_to_thread' => 'Zum Thema springen',
|
||||
'comment_delete_confirm' => 'Möchten Sie diesen Kommentar wirklich löschen?',
|
||||
'comment_in_reply_to' => 'Antwort auf :commentId',
|
||||
'comment_reference' => 'Reference',
|
||||
'comment_reference_outdated' => '(Outdated)',
|
||||
'comment_reference' => 'Referenz',
|
||||
'comment_reference_outdated' => '(Veraltet)',
|
||||
'comment_editor_explain' => 'Hier sind die Kommentare, die auf dieser Seite hinterlassen wurden. Kommentare können hinzugefügt und verwaltet werden, wenn die gespeicherte Seite angezeigt wird.',
|
||||
|
||||
// Revision
|
||||
|
||||
@@ -349,6 +349,7 @@ Hinweis: Benutzer können ihre E-Mail-Adresse nach erfolgreicher Registrierung
|
||||
'lt' => 'Litauisch',
|
||||
'lv' => 'Lettisch',
|
||||
'nb' => 'Norwegisch (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Niederländisch',
|
||||
'pl' => 'Polnisch',
|
||||
|
||||
@@ -30,8 +30,8 @@ return [
|
||||
'create' => 'Anlegen',
|
||||
'update' => 'Aktualisieren',
|
||||
'edit' => 'Bearbeiten',
|
||||
'archive' => 'Archive',
|
||||
'unarchive' => 'Un-Archive',
|
||||
'archive' => 'Archivieren',
|
||||
'unarchive' => 'Nicht mehr archivieren',
|
||||
'sort' => 'Sortieren',
|
||||
'move' => 'Verschieben',
|
||||
'copy' => 'Kopieren',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Hochgestellt',
|
||||
'subscript' => 'Tiefgestellt',
|
||||
'text_color' => 'Textfarbe',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Benutzerdefinierte Farbe',
|
||||
'remove_color' => 'Farbe entfernen',
|
||||
'background_color' => 'Hintergrundfarbe',
|
||||
|
||||
@@ -248,7 +248,7 @@ return [
|
||||
'pages_edit_switch_to_markdown_stable' => '(Stabiler Inhalt)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Zum WYSIWYG-Editor wechseln',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Zum neuen WYSIWYG wechseln',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(Im Beta-Test)',
|
||||
'pages_edit_set_changelog' => 'Änderungsprotokoll hinzufügen',
|
||||
'pages_edit_enter_changelog_desc' => 'Bitte gib eine kurze Zusammenfassung deiner Änderungen ein',
|
||||
'pages_edit_enter_changelog' => 'Änderungsprotokoll eingeben',
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Zeichnung einfügen',
|
||||
'pages_md_show_preview' => 'Vorschau anzeigen',
|
||||
'pages_md_sync_scroll' => 'Vorschau synchronisieren',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Ungespeicherte Zeichnung gefunden',
|
||||
'pages_drawing_unsaved_confirm' => 'Es wurden ungespeicherte Zeichnungsdaten von einem früheren, fehlgeschlagenen Versuch, die Zeichnung zu speichern, gefunden. Möchtest du diese ungespeicherte Zeichnung wiederherstellen und weiter bearbeiten?',
|
||||
'pages_not_in_chapter' => 'Seite ist in keinem Kapitel',
|
||||
@@ -392,11 +393,11 @@ return [
|
||||
'comment' => 'Kommentar',
|
||||
'comments' => 'Kommentare',
|
||||
'comment_add' => 'Kommentieren',
|
||||
'comment_none' => 'No comments to display',
|
||||
'comment_none' => 'Keine Kommentare vorhanden',
|
||||
'comment_placeholder' => 'Gib hier deine Kommentare ein',
|
||||
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
|
||||
'comment_archived_count' => ':count Archived',
|
||||
'comment_archived_threads' => 'Archived Threads',
|
||||
'comment_thread_count' => ':count Thema|:count Themen',
|
||||
'comment_archived_count' => ':count archiviert',
|
||||
'comment_archived_threads' => 'Archivierte Themen',
|
||||
'comment_save' => 'Kommentar speichern',
|
||||
'comment_new' => 'Neuer Kommentar',
|
||||
'comment_created' => ':createDiff kommentiert',
|
||||
@@ -405,14 +406,14 @@ return [
|
||||
'comment_deleted_success' => 'Kommentar gelöscht',
|
||||
'comment_created_success' => 'Kommentar hinzugefügt',
|
||||
'comment_updated_success' => 'Kommentar aktualisiert',
|
||||
'comment_archive_success' => 'Comment archived',
|
||||
'comment_unarchive_success' => 'Comment un-archived',
|
||||
'comment_view' => 'View comment',
|
||||
'comment_jump_to_thread' => 'Jump to thread',
|
||||
'comment_archive_success' => 'Kommentar archiviert',
|
||||
'comment_unarchive_success' => 'Kommentar nicht mehr archiviert',
|
||||
'comment_view' => 'Kommentar ansehen',
|
||||
'comment_jump_to_thread' => 'Zum Thema springen',
|
||||
'comment_delete_confirm' => 'Möchtst du diesen Kommentar wirklich löschen?',
|
||||
'comment_in_reply_to' => 'Antwort auf :commentId',
|
||||
'comment_reference' => 'Reference',
|
||||
'comment_reference_outdated' => '(Outdated)',
|
||||
'comment_reference' => 'Referenz',
|
||||
'comment_reference_outdated' => '(Veraltet)',
|
||||
'comment_editor_explain' => 'Hier sind die Kommentare, die auf dieser Seite hinterlassen wurden. Kommentare können hinzugefügt und verwaltet werden, wenn die gespeicherte Seite angezeigt wird.',
|
||||
|
||||
// Revision
|
||||
|
||||
@@ -349,6 +349,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
|
||||
'lt' => 'Litauisch',
|
||||
'lv' => 'Lettisch',
|
||||
'nb' => 'Norwegisch (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Niederländisch',
|
||||
'pl' => 'Polnisch',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Εκθέτης',
|
||||
'subscript' => 'Δείκτης',
|
||||
'text_color' => 'Χρώμα κειμένου',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Προσαρμογή χρώματος',
|
||||
'remove_color' => 'Αφαίρεση χρώματος',
|
||||
'background_color' => 'Χρώμα φόντου',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Εισαγωγή Σχεδίου',
|
||||
'pages_md_show_preview' => 'Εμφάνιση προεπισκόπησης',
|
||||
'pages_md_sync_scroll' => 'Συγχρονισμός προεπισκόπησης',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
|
||||
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
|
||||
'pages_not_in_chapter' => 'Η σελίδα δεν είναι σε κεφάλαιο',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Superscript',
|
||||
'subscript' => 'Subscript',
|
||||
'text_color' => 'Text color',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Custom color',
|
||||
'remove_color' => 'Remove color',
|
||||
'background_color' => 'Background color',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Insert Drawing',
|
||||
'pages_md_show_preview' => 'Show preview',
|
||||
'pages_md_sync_scroll' => 'Sync preview scroll',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
|
||||
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
|
||||
'pages_not_in_chapter' => 'Page is not in a chapter',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -30,8 +30,8 @@ return [
|
||||
'create' => 'Crear',
|
||||
'update' => 'Actualizar',
|
||||
'edit' => 'Editar',
|
||||
'archive' => 'Archive',
|
||||
'unarchive' => 'Un-Archive',
|
||||
'archive' => 'Archivar',
|
||||
'unarchive' => 'Desarchivar',
|
||||
'sort' => 'Ordenar',
|
||||
'move' => 'Mover',
|
||||
'copy' => 'Copiar',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Superíndice',
|
||||
'subscript' => 'Subíndice',
|
||||
'text_color' => 'Color de texto',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Color personalizado',
|
||||
'remove_color' => 'Eliminar color',
|
||||
'background_color' => 'Color de fondo',
|
||||
|
||||
@@ -248,7 +248,7 @@ return [
|
||||
'pages_edit_switch_to_markdown_stable' => '(Contenido Estable)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Cambiar a Editor WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Cambiar a nuevo editor WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(En prueba beta)',
|
||||
'pages_edit_set_changelog' => 'Ajustar Log de cambios',
|
||||
'pages_edit_enter_changelog_desc' => 'Introduzca una breve descripción de los cambios que ha realizado',
|
||||
'pages_edit_enter_changelog' => 'Entrar al Log de cambios',
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Insertar Dibujo',
|
||||
'pages_md_show_preview' => 'Mostrar vista previa',
|
||||
'pages_md_sync_scroll' => 'Sincronizar desplazamiento de vista previa',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Encontrado dibujo sin guardar',
|
||||
'pages_drawing_unsaved_confirm' => 'Se encontraron datos no guardados del dibujo de un intento de guardado fallido. ¿Desea restaurar y continuar editando el dibujo no guardado?',
|
||||
'pages_not_in_chapter' => 'La página no está en un capítulo',
|
||||
@@ -392,11 +393,11 @@ return [
|
||||
'comment' => 'Comentario',
|
||||
'comments' => 'Comentarios',
|
||||
'comment_add' => 'Añadir Comentario',
|
||||
'comment_none' => 'No comments to display',
|
||||
'comment_none' => 'No hay comentarios para mostrar',
|
||||
'comment_placeholder' => 'Introduzca su comentario aquí',
|
||||
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
|
||||
'comment_archived_count' => ':count Archived',
|
||||
'comment_archived_threads' => 'Archived Threads',
|
||||
'comment_thread_count' => ':count hilo de comentarios|:count hilos de comentarios',
|
||||
'comment_archived_count' => ':count Archivados',
|
||||
'comment_archived_threads' => 'Hilos archivados',
|
||||
'comment_save' => 'Guardar comentario',
|
||||
'comment_new' => 'Nuevo Comentario',
|
||||
'comment_created' => 'comentado :createDiff',
|
||||
@@ -405,14 +406,14 @@ return [
|
||||
'comment_deleted_success' => 'Comentario borrado',
|
||||
'comment_created_success' => 'Comentario añadido',
|
||||
'comment_updated_success' => 'Comentario actualizado',
|
||||
'comment_archive_success' => 'Comment archived',
|
||||
'comment_unarchive_success' => 'Comment un-archived',
|
||||
'comment_view' => 'View comment',
|
||||
'comment_jump_to_thread' => 'Jump to thread',
|
||||
'comment_archive_success' => 'Comentario archivado',
|
||||
'comment_unarchive_success' => 'Comentario desarchivado',
|
||||
'comment_view' => 'Ver comentario',
|
||||
'comment_jump_to_thread' => 'Ir al hilo',
|
||||
'comment_delete_confirm' => '¿Está seguro de que quiere borrar este comentario?',
|
||||
'comment_in_reply_to' => 'En respuesta a :commentId',
|
||||
'comment_reference' => 'Reference',
|
||||
'comment_reference_outdated' => '(Outdated)',
|
||||
'comment_reference' => 'Referencia',
|
||||
'comment_reference_outdated' => '(obsoleto)',
|
||||
'comment_editor_explain' => 'Estos son los comentarios que se han escrito en esta página. Los comentarios se pueden añadir y administrar cuando se ve la página guardada.',
|
||||
|
||||
// Revision
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lituano',
|
||||
'lv' => 'Letón',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Holanda',
|
||||
'pl' => 'Polaco',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Superíndice',
|
||||
'subscript' => 'Subíndice',
|
||||
'text_color' => 'Color del texto',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Color personalizado',
|
||||
'remove_color' => 'Eliminar color',
|
||||
'background_color' => 'Color de fondo',
|
||||
|
||||
@@ -248,7 +248,7 @@ return [
|
||||
'pages_edit_switch_to_markdown_stable' => '(Contenido Estable)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Cambiar a Editor WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Cambiar a nuevo editor WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(En prueba beta)',
|
||||
'pages_edit_set_changelog' => 'Establecer cambios de registro',
|
||||
'pages_edit_enter_changelog_desc' => 'Introduzca una breve descripción de los cambios que ha realizado',
|
||||
'pages_edit_enter_changelog' => 'Entrar en cambio de registro',
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Insertar Dibujo',
|
||||
'pages_md_show_preview' => 'Mostrar vista previa',
|
||||
'pages_md_sync_scroll' => 'Sincronizar desplazamiento de vista previa',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Encontrado dibujo sin guardar',
|
||||
'pages_drawing_unsaved_confirm' => 'Se encontraron datos del dibujo no guardados durante un intento de guardado fallido anterior. ¿Desea restaurar y continuar editando el dibujo no guardado?',
|
||||
'pages_not_in_chapter' => 'La página no esá en el capítulo',
|
||||
|
||||
@@ -349,6 +349,7 @@ return [
|
||||
'lt' => 'Lituano',
|
||||
'lv' => 'Letón',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Holanda',
|
||||
'pl' => 'Polaco',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Ülaindeks',
|
||||
'subscript' => 'Alaindeks',
|
||||
'text_color' => 'Teksti värv',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Kohandatud värv',
|
||||
'remove_color' => 'Eemalda värv',
|
||||
'background_color' => 'Taustavärv',
|
||||
|
||||
@@ -248,7 +248,7 @@ return [
|
||||
'pages_edit_switch_to_markdown_stable' => '(Stabiilne sisu)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Kasuta WYSIWYG redaktorit',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Kasuta uut tekstiredaktorit',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(beetatestimisel)',
|
||||
'pages_edit_set_changelog' => 'Muudatuste logi',
|
||||
'pages_edit_enter_changelog_desc' => 'Sisesta tehtud muudatuste lühikirjeldus',
|
||||
'pages_edit_enter_changelog' => 'Salvesta muudatuste logi',
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Lisa joonis',
|
||||
'pages_md_show_preview' => 'Näita eelvaadet',
|
||||
'pages_md_sync_scroll' => 'Sünkrooni eelvaate kerimine',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Leiti salvestamata joonis',
|
||||
'pages_drawing_unsaved_confirm' => 'Varasemast ebaõnnestunud salvestuskatsest leiti salvestamata joonis. Kas soovid salvestamata joonise taastada ja selle muutmist jätkata?',
|
||||
'pages_not_in_chapter' => 'Leht ei kuulu peatüki alla',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba (leedu keel)',
|
||||
'lv' => 'Latviešu Valoda (läti keel)',
|
||||
'nb' => 'Norsk (Bokmål) (norra keel)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands (hollandi keel)',
|
||||
'pl' => 'Polski (poola keel)',
|
||||
|
||||
@@ -48,6 +48,7 @@ return [
|
||||
'superscript' => 'Gain-eskripta',
|
||||
'subscript' => 'Azpi-script',
|
||||
'text_color' => 'Testuaren kolorea',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Kolore pertsonalizatua',
|
||||
'remove_color' => 'Kolorea ezabatu',
|
||||
'background_color' => 'Atzeko planoaren kolorea',
|
||||
|
||||
@@ -268,6 +268,7 @@ return [
|
||||
'pages_md_insert_drawing' => 'Txertatu marrazki berria',
|
||||
'pages_md_show_preview' => 'Show preview',
|
||||
'pages_md_sync_scroll' => 'Sync preview scroll',
|
||||
'pages_md_plain_editor' => 'Plaintext editor',
|
||||
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
|
||||
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
|
||||
'pages_not_in_chapter' => 'Page is not in a chapter',
|
||||
|
||||
@@ -348,6 +348,7 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
return [
|
||||
|
||||
// Pages
|
||||
'page_create' => 'تاریخ ایجاد',
|
||||
'page_create' => 'صفحه ایجاد شد',
|
||||
'page_create_notification' => 'صفحه با موفقیت ایجاد شد',
|
||||
'page_update' => 'به روزرسانی صفحه',
|
||||
'page_update_notification' => 'صفحه با موفقیت به روزرسانی شد',
|
||||
@@ -85,12 +85,12 @@ return [
|
||||
'webhook_delete_notification' => 'وب هوک با موفقیت حذف شد',
|
||||
|
||||
// Imports
|
||||
'import_create' => 'created import',
|
||||
'import_create_notification' => 'Import successfully uploaded',
|
||||
'import_run' => 'updated import',
|
||||
'import_run_notification' => 'Content successfully imported',
|
||||
'import_delete' => 'deleted import',
|
||||
'import_delete_notification' => 'Import successfully deleted',
|
||||
'import_create' => 'ورودی ایجاد شد',
|
||||
'import_create_notification' => 'فایل با موفقیت آپلود شد',
|
||||
'import_run' => 'آیتم واردشده بروزرسانی شد',
|
||||
'import_run_notification' => 'محتوا با موفقیت انتقال یافت',
|
||||
'import_delete' => 'آیتم ورودی حدف شده',
|
||||
'import_delete_notification' => 'آیتم واردشده با موفقیت حذف شد',
|
||||
|
||||
// Users
|
||||
'user_create' => 'کاربر ایجاد شده',
|
||||
@@ -128,12 +128,12 @@ return [
|
||||
'comment_delete' => 'نظر حذف شده',
|
||||
|
||||
// Sort Rules
|
||||
'sort_rule_create' => 'created sort rule',
|
||||
'sort_rule_create_notification' => 'Sort rule successfully created',
|
||||
'sort_rule_update' => 'updated sort rule',
|
||||
'sort_rule_update_notification' => 'Sort rule successfully updated',
|
||||
'sort_rule_delete' => 'deleted sort rule',
|
||||
'sort_rule_delete_notification' => 'Sort rule successfully deleted',
|
||||
'sort_rule_create' => 'قانون مرتبسازی ایجاد شد',
|
||||
'sort_rule_create_notification' => 'قانون مرتبسازی با موفقیت ایجاد شد',
|
||||
'sort_rule_update' => 'قانون مرتبسازی بهروزرسانی شد',
|
||||
'sort_rule_update_notification' => 'قانون مرتبسازی با موفقیت بهروزرسانی شد',
|
||||
'sort_rule_delete' => 'قانون مرتبسازی حذف شد',
|
||||
'sort_rule_delete_notification' => 'قانون مرتبسازی با موفقیت حذف شد',
|
||||
|
||||
// Other
|
||||
'permissions_update' => 'به روزرسانی مجوزها',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user