mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Added markdown export endpoints to API
- Added tests to cover. - Added slight extra spaces at content joins.
This commit is contained in:
parent
57ea2e92ec
commit
992f03a3c0
@ -248,7 +248,7 @@ class ExportFormatter
|
|||||||
$text = "# " . $chapter->name . "\n\n";
|
$text = "# " . $chapter->name . "\n\n";
|
||||||
$text .= $chapter->description . "\n\n";
|
$text .= $chapter->description . "\n\n";
|
||||||
foreach ($chapter->pages as $page) {
|
foreach ($chapter->pages as $page) {
|
||||||
$text .= $this->pageToMarkdown($page);
|
$text .= $this->pageToMarkdown($page) . "\n\n";
|
||||||
}
|
}
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,21 @@ class HtmlToMarkdown
|
|||||||
*/
|
*/
|
||||||
protected function getConverterEnvironment(): Environment
|
protected function getConverterEnvironment(): Environment
|
||||||
{
|
{
|
||||||
$environment = new Environment(['header_style' => 'atx']);
|
$environment = new Environment([
|
||||||
|
'header_style' => 'atx', // Set to 'atx' to output H1 and H2 headers as # Header1 and ## Header2
|
||||||
|
'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML
|
||||||
|
'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output.
|
||||||
|
'strip_placeholder_links' => false, // Set to true to remove <a> that doesn't have href.
|
||||||
|
'bold_style' => '**', // DEPRECATED: Set to '__' if you prefer the underlined style
|
||||||
|
'italic_style' => '*', // DEPRECATED: Set to '_' if you prefer the underlined style
|
||||||
|
'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: 'meta style script'
|
||||||
|
'hard_break' => false, // Set to true to turn <br> into `\n` instead of ` \n`
|
||||||
|
'list_item_style' => '-', // Set the default character for each <li> in a <ul>. Can be '-', '*', or '+'
|
||||||
|
'preserve_comments' => false, // Set to true to preserve comments, or set to an array of strings to preserve specific comments
|
||||||
|
'use_autolinks' => false, // Set to true to use simple link syntax if possible. Will always use []() if set to false
|
||||||
|
'table_pipe_escape' => '\|', // Replacement string for pipe characters inside markdown table cells
|
||||||
|
'table_caption_side' => 'top', // Set to 'top' or 'bottom' to show <caption> content before or after table, null to suppress
|
||||||
|
]);
|
||||||
|
|
||||||
$environment->addConverter(new BlockquoteConverter());
|
$environment->addConverter(new BlockquoteConverter());
|
||||||
$environment->addConverter(new CodeConverter());
|
$environment->addConverter(new CodeConverter());
|
||||||
|
@ -44,4 +44,14 @@ class BookExportApiController extends ApiController
|
|||||||
$textContent = $this->exportFormatter->bookToPlainText($book);
|
$textContent = $this->exportFormatter->bookToPlainText($book);
|
||||||
return $this->downloadResponse($textContent, $book->slug . '.txt');
|
return $this->downloadResponse($textContent, $book->slug . '.txt');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export a book as a markdown file.
|
||||||
|
*/
|
||||||
|
public function exportMarkdown(int $id)
|
||||||
|
{
|
||||||
|
$book = Book::visible()->findOrFail($id);
|
||||||
|
$markdown = $this->exportFormatter->bookToMarkdown($book);
|
||||||
|
return $this->downloadResponse($markdown, $book->slug . '.md');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use BookStack\Entities\Models\Chapter;
|
use BookStack\Entities\Models\Chapter;
|
||||||
use BookStack\Entities\Tools\ExportFormatter;
|
use BookStack\Entities\Tools\ExportFormatter;
|
||||||
use BookStack\Entities\Repos\BookRepo;
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
class ChapterExportApiController extends ApiController
|
class ChapterExportApiController extends ApiController
|
||||||
@ -48,4 +47,14 @@ class ChapterExportApiController extends ApiController
|
|||||||
$textContent = $this->exportFormatter->chapterToPlainText($chapter);
|
$textContent = $this->exportFormatter->chapterToPlainText($chapter);
|
||||||
return $this->downloadResponse($textContent, $chapter->slug . '.txt');
|
return $this->downloadResponse($textContent, $chapter->slug . '.txt');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export a chapter as a markdown file.
|
||||||
|
*/
|
||||||
|
public function exportMarkdown(int $id)
|
||||||
|
{
|
||||||
|
$chapter = Chapter::visible()->findOrFail($id);
|
||||||
|
$markdown = $this->exportFormatter->chapterToMarkdown($chapter);
|
||||||
|
return $this->downloadResponse($markdown, $chapter->slug . '.md');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,4 +44,14 @@ class PageExportApiController extends ApiController
|
|||||||
$textContent = $this->exportFormatter->pageToPlainText($page);
|
$textContent = $this->exportFormatter->pageToPlainText($page);
|
||||||
return $this->downloadResponse($textContent, $page->slug . '.txt');
|
return $this->downloadResponse($textContent, $page->slug . '.txt');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export a page as a markdown file.
|
||||||
|
*/
|
||||||
|
public function exportMarkdown(int $id)
|
||||||
|
{
|
||||||
|
$page = Page::visible()->findOrFail($id);
|
||||||
|
$markdown = $this->exportFormatter->pageToMarkdown($page);
|
||||||
|
return $this->downloadResponse($markdown, $page->slug . '.md');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ Route::delete('books/{id}', 'BookApiController@delete');
|
|||||||
Route::get('books/{id}/export/html', 'BookExportApiController@exportHtml');
|
Route::get('books/{id}/export/html', 'BookExportApiController@exportHtml');
|
||||||
Route::get('books/{id}/export/pdf', 'BookExportApiController@exportPdf');
|
Route::get('books/{id}/export/pdf', 'BookExportApiController@exportPdf');
|
||||||
Route::get('books/{id}/export/plaintext', 'BookExportApiController@exportPlainText');
|
Route::get('books/{id}/export/plaintext', 'BookExportApiController@exportPlainText');
|
||||||
|
Route::get('books/{id}/export/markdown', 'BookExportApiController@exportMarkdown');
|
||||||
|
|
||||||
Route::get('chapters', 'ChapterApiController@list');
|
Route::get('chapters', 'ChapterApiController@list');
|
||||||
Route::post('chapters', 'ChapterApiController@create');
|
Route::post('chapters', 'ChapterApiController@create');
|
||||||
@ -28,6 +29,7 @@ Route::delete('chapters/{id}', 'ChapterApiController@delete');
|
|||||||
Route::get('chapters/{id}/export/html', 'ChapterExportApiController@exportHtml');
|
Route::get('chapters/{id}/export/html', 'ChapterExportApiController@exportHtml');
|
||||||
Route::get('chapters/{id}/export/pdf', 'ChapterExportApiController@exportPdf');
|
Route::get('chapters/{id}/export/pdf', 'ChapterExportApiController@exportPdf');
|
||||||
Route::get('chapters/{id}/export/plaintext', 'ChapterExportApiController@exportPlainText');
|
Route::get('chapters/{id}/export/plaintext', 'ChapterExportApiController@exportPlainText');
|
||||||
|
Route::get('chapters/{id}/export/markdown', 'ChapterExportApiController@exportMarkdown');
|
||||||
|
|
||||||
Route::get('pages', 'PageApiController@list');
|
Route::get('pages', 'PageApiController@list');
|
||||||
Route::post('pages', 'PageApiController@create');
|
Route::post('pages', 'PageApiController@create');
|
||||||
@ -38,6 +40,7 @@ Route::delete('pages/{id}', 'PageApiController@delete');
|
|||||||
Route::get('pages/{id}/export/html', 'PageExportApiController@exportHtml');
|
Route::get('pages/{id}/export/html', 'PageExportApiController@exportHtml');
|
||||||
Route::get('pages/{id}/export/pdf', 'PageExportApiController@exportPdf');
|
Route::get('pages/{id}/export/pdf', 'PageExportApiController@exportPdf');
|
||||||
Route::get('pages/{id}/export/plaintext', 'PageExportApiController@exportPlainText');
|
Route::get('pages/{id}/export/plaintext', 'PageExportApiController@exportPlainText');
|
||||||
|
Route::get('pages/{id}/export/markdown', 'PageExportApiController@exportMarkDown');
|
||||||
|
|
||||||
Route::get('shelves', 'BookshelfApiController@list');
|
Route::get('shelves', 'BookshelfApiController@list');
|
||||||
Route::post('shelves', 'BookshelfApiController@create');
|
Route::post('shelves', 'BookshelfApiController@create');
|
||||||
|
@ -140,4 +140,17 @@ class BooksApiTest extends TestCase
|
|||||||
$resp->assertStatus(200);
|
$resp->assertStatus(200);
|
||||||
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $book->slug . '.pdf"');
|
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $book->slug . '.pdf"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_export_markdown_endpoint()
|
||||||
|
{
|
||||||
|
$this->actingAsApiEditor();
|
||||||
|
$book = Book::visible()->has('pages')->has('chapters')->first();
|
||||||
|
|
||||||
|
$resp = $this->get($this->baseEndpoint . "/{$book->id}/export/markdown");
|
||||||
|
$resp->assertStatus(200);
|
||||||
|
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $book->slug . '.md"');
|
||||||
|
$resp->assertSee('# ' . $book->name);
|
||||||
|
$resp->assertSee('# ' . $book->pages()->first()->name);
|
||||||
|
$resp->assertSee('# ' . $book->chapters()->first()->name);
|
||||||
|
}
|
||||||
}
|
}
|
@ -186,4 +186,16 @@ class ChaptersApiTest extends TestCase
|
|||||||
$resp->assertStatus(200);
|
$resp->assertStatus(200);
|
||||||
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $chapter->slug . '.pdf"');
|
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $chapter->slug . '.pdf"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_export_markdown_endpoint()
|
||||||
|
{
|
||||||
|
$this->actingAsApiEditor();
|
||||||
|
$chapter = Chapter::visible()->has('pages')->first();
|
||||||
|
|
||||||
|
$resp = $this->get($this->baseEndpoint . "/{$chapter->id}/export/markdown");
|
||||||
|
$resp->assertStatus(200);
|
||||||
|
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $chapter->slug . '.md"');
|
||||||
|
$resp->assertSee('# ' . $chapter->name);
|
||||||
|
$resp->assertSee('# ' . $chapter->pages()->first()->name);
|
||||||
|
}
|
||||||
}
|
}
|
@ -258,4 +258,15 @@ class PagesApiTest extends TestCase
|
|||||||
$resp->assertStatus(200);
|
$resp->assertStatus(200);
|
||||||
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $page->slug . '.pdf"');
|
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $page->slug . '.pdf"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_export_markdown_endpoint()
|
||||||
|
{
|
||||||
|
$this->actingAsApiEditor();
|
||||||
|
$page = Page::visible()->first();
|
||||||
|
|
||||||
|
$resp = $this->get($this->baseEndpoint . "/{$page->id}/export/markdown");
|
||||||
|
$resp->assertStatus(200);
|
||||||
|
$resp->assertSee('# ' . $page->name);
|
||||||
|
$resp->assertHeader('Content-Disposition', 'attachment; filename="' . $page->slug . '.md"');
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user