Skip to content
GitLab
Menu
Why GitLab
Pricing
Contact Sales
Explore
Why GitLab
Pricing
Contact Sales
Explore
Sign in
Get free trial
Primary navigation
Search or go to…
Project
B
BookStack HTML Importer
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Model registry
Monitor
Service Desk
Analyze
Contributor analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Privacy statement
Keyboard shortcuts
?
What's new
6
Snippets
Groups
Projects
Show more breadcrumbs
Oddineers Public Projects
BookStack HTML Importer
Commits
08c91e08
Commit
08c91e08
authored
8 months ago
by
Steven Brown
Browse files
Options
Downloads
Patches
Plain Diff
feat: Implements support to retrieve pages/books and export as files.
Abstracts requests for books/pages as `things`.
parent
c7d6d129
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
bookstack_client.php
+277
-63
277 additions, 63 deletions
bookstack_client.php
with
277 additions
and
63 deletions
bookstack_client.php
+
277
−
63
View file @
08c91e08
...
@@ -14,9 +14,9 @@ class BookStack_Client {
...
@@ -14,9 +14,9 @@ class BookStack_Client {
private
$headers
=
array
();
private
$headers
=
array
();
private
$debug
=
false
;
private
$debug
=
false
;
private
$cookie
=
false
;
private
$cookie
=
false
;
pr
ivate
$data_string
=
false
;
pr
otected
$data_string
=
false
;
private
$file_as_json
=
false
;
private
$file_as_json
=
false
;
protec
te
d
$c_types
=
array
(
priva
te
$c_types
=
array
(
"gif"
=>
"image/gif"
,
"gif"
=>
"image/gif"
,
"jpg"
=>
"image/jpeg"
,
"jpg"
=>
"image/jpeg"
,
"png"
=>
"image/png"
,
"png"
=>
"image/png"
,
...
@@ -24,7 +24,19 @@ class BookStack_Client {
...
@@ -24,7 +24,19 @@ class BookStack_Client {
"txt"
=>
"text/plain"
,
"txt"
=>
"text/plain"
,
);
);
function
__construct
(
$domain_url
,
$id
,
$secret
,
$debug
=
false
)
{
private
$extension_format
=
[
'pdf'
=>
'pdf'
,
'html'
=>
'html'
,
'plaintext'
=>
'txt'
,
'markdown'
=>
'md'
,
];
private
$output_dir
=
null
;
// Cache book ID's: "id" => "name"
private
$cached_book_ids
=
array
();
function
__construct
(
$domain_url
,
$id
,
$secret
,
$debug
=
false
)
{
if
(
empty
(
$domain_url
)
)
{
if
(
empty
(
$domain_url
)
)
{
$this
->
last_status_message
=
'The hostname/url cannot be empty.'
;
$this
->
last_status_message
=
'The hostname/url cannot be empty.'
;
...
@@ -60,13 +72,28 @@ class BookStack_Client {
...
@@ -60,13 +72,28 @@ class BookStack_Client {
}
}
$this
->
data_string
=
"
{
$id
}
:
{
$secret
}
"
;
$this
->
data_string
=
"
{
$id
}
:
{
$secret
}
"
;
$this
->
output_dir
=
realpath
(
'./docs/'
);
}
}
/**
* Assign a custom output path.
* @param $output_dir
* @return bool
*/
function
update_output_path
(
$output_dir
)
{
// Assign custom directory if overridden and exists
if
(
is_dir
(
$output_dir
))
{
$this
->
output_dir
=
$output_dir
;
return
true
;
}
return
false
;
}
/**
/**
* Basic authentication
* Basic authentication
* @return void
* @return void
*/
*/
function
basic_auth
()
{
protected
function
basic_auth
()
{
//$encoded_token = base64_encode( $this->data_string );
//$encoded_token = base64_encode( $this->data_string );
$encoded_token
=
$this
->
data_string
;
$encoded_token
=
$this
->
data_string
;
$this
->
headers
=
array_merge
(
array
(
$this
->
headers
=
array_merge
(
array
(
...
@@ -81,15 +108,15 @@ class BookStack_Client {
...
@@ -81,15 +108,15 @@ class BookStack_Client {
*
*
* @return void
* @return void
*/
*/
function
user_auth
(
$ch
)
{
protected
function
user_auth
(
$ch
)
{
//$encoded_token = base64_encode( $this->data_string );
//$encoded_token = base64_encode( $this->data_string );
$encoded_token
=
$this
->
data_string
;
$encoded_token
=
$this
->
data_string
;
curl_setopt
(
$ch
,
CURLOPT_USERPWD
,
$encoded_token
);
curl_setopt
(
$ch
,
CURLOPT_USERPWD
,
$encoded_token
);
curl_setopt
(
$ch
,
CURLOPT_HTTPAUTH
,
CURLAUTH_BASIC
);
curl_setopt
(
$ch
,
CURLOPT_HTTPAUTH
,
CURLAUTH_BASIC
);
//curl_setopt($ch, CURLOPT_COOKIESESSION, true);
//curl_setopt($ch, CURLOPT_COOKIESESSION, true);
curl_setopt
(
$ch
,
CURLOPT_COOKIEJAR
,
$this
->
cookie
);
curl_setopt
(
$ch
,
CURLOPT_COOKIEJAR
,
$this
->
cookie
);
curl_setopt
(
$ch
,
CURLOPT_COOKIEFILE
,
$this
->
cookie
);
curl_setopt
(
$ch
,
CURLOPT_COOKIEFILE
,
$this
->
cookie
);
}
}
/**
/**
* Dumps values if debugging is enabled.
* Dumps values if debugging is enabled.
...
@@ -112,25 +139,24 @@ class BookStack_Client {
...
@@ -112,25 +139,24 @@ class BookStack_Client {
* Create a POST request; supports a variety of scenarios.
* Create a POST request; supports a variety of scenarios.
*
*
* @param $url
* @param $url
* @param $payload
* @param
array
$payload
* @param $type
* @param $type
* @param $filename
* @param $filename
*
*
* @return bool|string
* @return bool|string
*/
*/
function
post
(
$url
,
$payload
,
$type
=
"POST"
,
$filename
=
false
)
{
function
post
(
$url
,
$payload
=
array
()
,
$type
=
"POST"
,
$filename
=
false
)
{
// Reset header
// Reset header
$this
->
headers
=
array
();
$this
->
headers
=
array
();
// Set the last url attribute to match this request
// Set the last url attribute to match this request
$this
->
last_url
=
$url
;
$this
->
last_url
=
$url
;
// Get cURL resource
// Get cURL resource
$curl
=
curl_init
();
$curl
=
curl_init
();
// Merge the payload with channel_payload
// $payload = json_encode($payload);
// Custom POST/GET requests
// Custom POST/GET requests
if
(
$type
===
"POST"
)
{
if
(
$type
===
"POST"
)
{
curl_setopt
(
$curl
,
CURLOPT_CUSTOMREQUEST
,
'POST'
);
curl_setopt
(
$curl
,
CURLOPT_CUSTOMREQUEST
,
'POST'
);
curl_setopt
(
$curl
,
CURLOPT_POSTFIELDS
,
$payload
);
}
}
if
(
$type
===
"GET"
)
{
if
(
$type
===
"GET"
)
{
...
@@ -142,7 +168,7 @@ class BookStack_Client {
...
@@ -142,7 +168,7 @@ class BookStack_Client {
}
}
// If file is empty set default header to JSON
// If file is empty set default header to JSON
if
(
$filename
===
false
)
{
if
(
$type
===
"POST"
&&
$filename
===
false
)
{
$payload
=
json_encode
(
$payload
);
$payload
=
json_encode
(
$payload
);
$this
->
headers
=
array_merge
(
$this
->
headers
,
array
(
$this
->
headers
=
array_merge
(
$this
->
headers
,
array
(
'Content-Type: application/json'
,
'Content-Type: application/json'
,
...
@@ -194,47 +220,36 @@ class BookStack_Client {
...
@@ -194,47 +220,36 @@ class BookStack_Client {
curl_setopt
(
$curl
,
CURLOPT_RETURNTRANSFER
,
true
);
curl_setopt
(
$curl
,
CURLOPT_RETURNTRANSFER
,
true
);
curl_setopt
(
$curl
,
CURLOPT_FOLLOWLOCATION
,
true
);
curl_setopt
(
$curl
,
CURLOPT_FOLLOWLOCATION
,
true
);
curl_setopt
(
$curl
,
CURLOPT_USERAGENT
,
'europa_bookstack'
);
curl_setopt
(
$curl
,
CURLOPT_USERAGENT
,
'europa_bookstack'
);
curl_setopt
(
$curl
,
CURLOPT_POSTFIELDS
,
$payload
);
curl_setopt
(
$curl
,
CURLOPT_SSL_VERIFYPEER
,
false
);
curl_setopt
(
$curl
,
CURLOPT_SSL_VERIFYPEER
,
false
);
curl_setopt
(
$curl
,
CURLOPT_HTTP_VERSION
,
CURL_HTTP_VERSION_1_1
);
// Send the request & save response to $resp
// Send the request & save response to $resp
$resp
=
curl_exec
(
$curl
);
$resp
=
curl_exec
(
$curl
);
$http_code
=
curl_getinfo
(
$curl
,
CURLINFO_HTTP_CODE
);
$http_code
=
curl_getinfo
(
$curl
,
CURLINFO_HTTP_CODE
);
$errors
=
curl_error
(
$curl
);
$errors
=
curl_error
(
$curl
);
curl_close
(
$curl
);
curl_close
(
$curl
);
// Check for response errors
$friendly_errors
=
$resp
;
if
(
!
isset
(
$resp
)
)
{
if
(
isset
(
$errors
)
)
{
$friendly_errors
=
$errors
;
}
else
{
$friendly_errors
=
$resp
;
}
}
//$this->log($payload);
$this
->
log
(
$friendly_errors
);
$this
->
last_status_message
=
$errors
;
$this
->
last_status_message
=
$errors
;
$this
->
last_status_code
=
$http_code
;
$this
->
last_status_code
=
$http_code
;
return
(
$http_code
>=
200
&&
$http_code
<
300
)
?
$resp
:
$
friendly_
errors
;
return
(
$http_code
>=
200
&&
$http_code
<
300
)
?
$resp
:
$errors
;
}
}
/**
/**
* Utilises `post` to make a GET request using similar options.
* Utilises `post` to make a GET request using similar options.
*
* @param $url
* @param $url
* @param $payload
* @param
array
$payload
*
*
* @return bool|string
* @return bool|string
*/
*/
function
get
(
$url
,
$payload
)
{
function
get
(
$url
,
$payload
=
array
()
)
{
return
$this
->
post
(
$url
,
$payload
,
"GET"
);
return
$this
->
post
(
$url
,
$payload
,
"GET"
);
}
}
/**
/**
* Utilises `post` to make a PUT request using similar options.
* Utilises `post` to make a PUT request using similar options.
*
* @param $url
* @param $url
* @param $payload
* @param $payload
*
*
...
@@ -246,7 +261,6 @@ class BookStack_Client {
...
@@ -246,7 +261,6 @@ class BookStack_Client {
/**
/**
* Retrieves a list of shelves.
* Retrieves a list of shelves.
*
* @param $payload
* @param $payload
*
*
* @return false
* @return false
...
@@ -268,31 +282,194 @@ class BookStack_Client {
...
@@ -268,31 +282,194 @@ class BookStack_Client {
return
false
;
return
false
;
}
}
/**
/**
* Retrieves a list of books.
* GET Helper function to list from selected types: books, pages
*
*
* @param $payload array
* @param $type book or page
*
* @param $payload
* @return false
* @return false|mixed
*/
*/
function
get_books
(
$payload
)
{
protected
function
get_thing_helper
(
$type
,
$payload
=
array
()
)
{
if
(
is_array
(
$payload
)
)
{
$url
=
"
{
$this
->
url
}{
$type
}
"
;
$books
=
$this
->
get
(
"
{
$this
->
url
}
books"
,
$payload
);
if
(
!
empty
(
$payload
)
)
{
if
(
isset
(
$books
)
)
{
$url
=
"
{
$this
->
url
}{
$type
}
?"
.
http_build_query
(
$payload
);
$books
=
json_decode
(
$books
);
if
(
isset
(
$books
->
data
)
)
{
if
(
isset
(
$payload
[
"id"
]))
{
$books
=
$books
->
data
;
$url
=
"
{
$this
->
url
}{
$type
}
/
{
$payload
[
"id"
]
}
"
;
$this
->
log
(
$books
);
}
}
return
$books
;
}
$books
=
$this
->
get
(
$url
);
}
//$this->log( $books );
}
if
(
isset
(
$books
)
)
{
return
false
;
$books
=
json_decode
(
$books
);
if
(
!
empty
(
$books
))
{
return
$books
;
}
}
return
false
;
}
/**
* Creates a files from data; helper functions to be used by _export_thing_paginated_ with items such as books, pages.
*
* @param $type book or page
* @param $data data from a
* @param $ext
* @return void
*/
protected
function
create_file
(
$type
,
$data
,
$ext
=
'markdown'
)
{
if
(
$data
)
{
// iterate over books and save each entry
foreach
(
$data
as
$entry
)
{
if
(
!
isset
(
$entry
->
slug
))
{
continue
;
}
$id
=
$entry
->
id
;
$extension
=
$this
->
extension_format
[
$ext
];
$content
=
$this
->
get
(
"
{
$this
->
url
}{
$type
}
/
{
$id
}
/export/
{
$ext
}
"
);
//$this->log(array($type, $entry));
$slug
=
"
{
$entry
->
slug
}
"
;
$outpath
=
$this
->
output_dir
;
// Change pages to use the book slug as a sub-directory
if
(
$type
===
"pages"
)
{
if
(
isset
(
$entry
->
book_id
))
{
$book_name
=
$this
->
get_book_name
(
$entry
->
book_id
);
if
(
empty
(
$book_name
))
{
$book_name
=
"unknown"
;
}
$outpath
=
"
{
$this
->
output_dir
}
/
{
$book_name
}
"
;
// Dir doesn't exist make it
if
(
!
is_dir
(
$outpath
))
{
mkdir
(
$outpath
);
}
}
}
$out
=
"
{
$outpath
}
/
{
$slug
}
.
{
$extension
}
"
;
$this
->
log
(
$out
);
file_put_contents
(
$out
,
$content
);
}
}
}
/**
* Used with pagination functionality; changes the type (book or page) and sets the count and offset
* @param $type
* @param $count
* @param $offset
* @return false|mixed
*/
protected
function
set_type
(
$type
,
$count
,
$offset
)
{
switch
(
$type
)
{
case
"pages"
:
$data
=
$this
->
get_pages
(
$count
,
$offset
);
break
;
default
:
$data
=
$this
->
get_books
(
$count
,
$offset
);
break
;
}
return
$data
;
}
/**
* Export *things*; helper functions to be used by types such as books, pages.
*
* @param $type
* @return void
*/
protected
function
export_thing_paginated
(
$type
)
{
$count
=
100
;
$processed
=
0
;
// Set the data type (books or pages)
$data
=
$this
->
set_type
(
$type
,
$count
,
$processed
);
if
(
isset
(
$data
->
total
)
)
{
$total
=
$data
->
total
;
while
(
$processed
<
$total
)
{
// Get next set when processed > 0
if
(
$processed
>
0
)
{
//$this->log( array("new {$type} query", $count, $processed, $this->last_status_message) );
$data
=
$this
->
set_type
(
$type
,
$count
,
$processed
);
}
if
(
isset
(
$data
->
data
)
)
{
$data
=
$data
->
data
;
$this
->
create_file
(
$type
,
$data
,
'markdown'
);
}
$processed
+=
$count
;
}
}
}
/**
* Retrieve a list of *things*; helper functions to be used by types such as books, pages.
*
* @param $payload
* @return false|mixed
*/
protected
function
get_thing
(
$type
,
$payload
=
array
()
)
{
return
$this
->
get_thing_helper
(
$type
,
$payload
);
}
}
/**
* Get information about a book by book ID.
*
* @param $id
* @return false|mixed
*/
function
get_book
(
$id
)
{
$book
=
$this
->
get_thing
(
"books"
,
[
'id'
=>
$id
]);
return
$book
;
}
/**
* Retrieve a list of books based on a count + offset.
* Defaults to 100, 0.
*
* @param $count
* @param $offset
* @return false|mixed
*/
function
get_books
(
$count
=
100
,
$offset
=
0
)
{
$books
=
$this
->
get_thing
(
"books"
,
[
'count'
=>
$count
,
'offset'
=>
$offset
]);
return
$books
;
}
/**
* Get the book (slug) name by book id.
*
* @param $id
* @return false
*/
function
get_book_name
(
$id
)
{
// Test cache first - less likely to hit rate limits
if
(
isset
(
$this
->
cached_book_ids
[
$id
]))
{
return
$this
->
cached_book_ids
[
$id
];
}
// Query the book name (we use slug) from the ID
$book
=
$this
->
get_book
(
$id
);
if
(
isset
(
$book
->
slug
))
{
$this
->
cached_book_ids
[
$id
]
=
$book
->
slug
;
return
$book
->
slug
;
}
return
false
;
}
/**
/**
* Creates a new book if it does not exists.
* Creates a new book if it does not exists.
* $check_existing Default: true. When true checks if there is an existing book with the same name and returns
* $check_existing Default: true. When true checks if there is an existing book with the same name and returns
...
@@ -344,6 +521,44 @@ class BookStack_Client {
...
@@ -344,6 +521,44 @@ class BookStack_Client {
return
$book_id
;
return
$book_id
;
}
}
/**
* Export all books to a file.
* @return void
*/
function
export_all_books
()
{
$this
->
export_thing_paginated
(
"books"
);
}
/**
* Retrieve a page by ID.
* @param $id
* @return false|mixed
*/
function
get_page
(
$id
)
{
$page
=
$this
->
get_thing
(
"pages"
,
[
'id'
=>
$id
]);
return
$page
;
}
/**
* Retrieve a list of pages based on a count + offset.
* Defaults to 100, 0.
* @param $count
* @param $offset
* @return false|mixed
*/
function
get_pages
(
$count
=
100
,
$offset
=
0
)
{
$pages
=
$this
->
get_thing
(
"pages"
,
[
'count'
=>
$count
,
'offset'
=>
$offset
]);
return
$pages
;
}
/**
* Export all pages to files; uses the book slug name as sub-directory to store each page.
* @return void
*/
function
export_all_pages
()
{
$this
->
export_thing_paginated
(
"pages"
);
}
/**
/**
* Creates a page within a book.
* Creates a page within a book.
*
*
...
@@ -375,13 +590,12 @@ class BookStack_Client {
...
@@ -375,13 +590,12 @@ class BookStack_Client {
return
false
;
return
false
;
}
}
function
starts_with
(
$haystack
,
$needle
)
{
public
function
starts_with
(
$haystack
,
$needle
)
{
$length
=
strlen
(
$needle
);
$length
=
strlen
(
$needle
);
return
substr
(
$haystack
,
0
,
$length
)
===
$needle
;
return
substr
(
$haystack
,
0
,
$length
)
===
$needle
;
}
}
function
ends_with
(
$haystack
,
$needle
)
{
public
function
ends_with
(
$haystack
,
$needle
)
{
$length
=
strlen
(
$needle
);
$length
=
strlen
(
$needle
);
if
(
!
$length
)
{
if
(
!
$length
)
{
return
true
;
return
true
;
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment