Skip to content
This repository was archived by the owner on Jul 27, 2024. It is now read-only.

Commit ca7296a

Browse files
committed
Merge branch 'main' of github.com:BookStackApp/api-scripts
2 parents 04b4fca + 2339cf1 commit ca7296a

File tree

3 files changed

+502
-0
lines changed

3 files changed

+502
-0
lines changed

Diff for: php-generate-sitemap/generate-sitemap.php

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
// API Credentials
5+
// You can either provide them as environment variables
6+
// or hard-code them in the empty strings below.
7+
$baseUrl = getenv('BS_URL') ?: '';
8+
$clientId = getenv('BS_TOKEN_ID') ?: '';
9+
$clientSecret = getenv('BS_TOKEN_SECRET') ?: '';
10+
11+
// Output File
12+
// Can be provided as a arguments when calling the script
13+
// or be hard-coded as strings below.
14+
$outputFile = $argv[1] ?? './sitemap.xml';
15+
16+
// Script logic
17+
////////////////
18+
19+
// Check we have required options
20+
if (empty($outputFile)) {
21+
errorOut("An output file needs to be provided");
22+
}
23+
24+
// Create the output folder if it does not exist
25+
$outDir = dirname($outputFile);
26+
if (!is_dir($outDir)) {
27+
mkdir($outDir, 0777, true);
28+
}
29+
30+
// Clean up the base path
31+
$baseUrl = rtrim($baseUrl, '/');
32+
33+
// Additional endpoints not fetched via API entities
34+
$nowDate = date_format(new DateTime(), 'Y-m-d');
35+
$additionalEndpoints = [
36+
['endpoint' => '/', 'updated' => $nowDate],
37+
['endpoint' => '/books', 'updated' => $nowDate],
38+
['endpoint' => '/search', 'updated' => $nowDate],
39+
['endpoint' => '/login', 'updated' => $nowDate],
40+
];
41+
42+
// Get all shelf URLs
43+
$shelves = getAllOfAtListEndpoint("api/shelves", []);
44+
$shelfEndpoints = array_map(function ($shelf) {
45+
return ['endpoint' => '/shelves/' . $shelf['slug'], 'updated' => $shelf['updated_at']];
46+
}, $shelves);
47+
48+
// Get all book URLs and map for chapters & pages
49+
$books = getAllOfAtListEndpoint("api/books", []);
50+
$bookSlugsById = [];
51+
$bookEndpoints = array_map(function ($book) use (&$bookSlugsById) {
52+
$bookSlugsById[$book['id']] = $book['slug'];
53+
return ['endpoint' => '/books/' . $book['slug'], 'updated' => $book['updated_at']];
54+
}, $books);
55+
56+
// Get all chapter URLs and map for pages
57+
$chapters = getAllOfAtListEndpoint("api/chapters", []);
58+
$chapterEndpoints = array_map(function ($chapter) use ($bookSlugsById) {
59+
$bookSlug = $bookSlugsById[$chapter['book_id']];
60+
return ['endpoint' => '/books/' . $bookSlug . '/chapter/' . $chapter['slug'], 'updated' => $chapter['updated_at']];
61+
}, $chapters);
62+
63+
// Get all page URLs
64+
$pages = getAllOfAtListEndpoint("api/pages", []);
65+
$pageEndpoints = array_map(function ($page) use ($bookSlugsById) {
66+
$bookSlug = $bookSlugsById[$page['book_id']];
67+
return ['endpoint' => '/books/' . $bookSlug . '/page/' . $page['slug'], 'updated' => $page['updated_at']];
68+
}, $pages);
69+
70+
// Gather all our endpoints
71+
$allEndpoints = $additionalEndpoints
72+
+ $pageEndpoints
73+
+ $chapterEndpoints
74+
+ $bookEndpoints
75+
+ $shelfEndpoints;
76+
77+
// Fetch our sitemap XML
78+
$xmlSitemap = generateSitemapXml($allEndpoints);
79+
// Write to the output file
80+
file_put_contents($outputFile, $xmlSitemap);
81+
82+
/**
83+
* Generate out the XML content for a sitemap
84+
* for the given URLs.
85+
*/
86+
function generateSitemapXml(array $endpoints): string
87+
{
88+
global $baseUrl;
89+
$doc = new DOMDocument("1.0", "UTF-8");
90+
$urlset = $doc->createElement('urlset');
91+
$urlset->setAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
92+
93+
$doc->appendChild($urlset);
94+
foreach ($endpoints as $endpointInfo) {
95+
$date = (new DateTime($endpointInfo['updated']))->format('Y-m-d');
96+
$url = $doc->createElement('url');
97+
$loc = $url->appendChild($doc->createElement('loc'));
98+
$urlText = $doc->createTextNode($baseUrl . $endpointInfo['endpoint']);
99+
$loc->appendChild($urlText);
100+
$url->appendChild($doc->createElement('lastmod', $date));
101+
$url->appendChild($doc->createElement('changefreq', 'monthly'));
102+
$url->appendChild($doc->createElement('priority', '0.8'));
103+
$urlset->appendChild($url);
104+
}
105+
106+
return $doc->saveXML();
107+
}
108+
109+
/**
110+
* Consume all items from the given API listing endpoint.
111+
*/
112+
function getAllOfAtListEndpoint(string $endpoint, array $params): array
113+
{
114+
$count = 100;
115+
$offset = 0;
116+
$all = [];
117+
118+
do {
119+
$endpoint = $endpoint . '?' . http_build_query(array_merge($params, ['count' => $count, 'offset' => $offset]));
120+
$resp = apiGetJson($endpoint);
121+
122+
$total = $resp['total'] ?? 0;
123+
$new = $resp['data'] ?? [];
124+
array_push($all, ...$new);
125+
$offset += $count;
126+
} while ($offset < $total);
127+
128+
return $all;
129+
}
130+
131+
/**
132+
* Make a simple GET HTTP request to the API.
133+
*/
134+
function apiGet(string $endpoint): string
135+
{
136+
global $baseUrl, $clientId, $clientSecret;
137+
$url = rtrim($baseUrl, '/') . '/' . ltrim($endpoint, '/');
138+
$opts = ['http' => ['header' => "Authorization: Token {$clientId}:{$clientSecret}"]];
139+
$context = stream_context_create($opts);
140+
return @file_get_contents($url, false, $context);
141+
}
142+
143+
/**
144+
* Make a simple GET HTTP request to the API &
145+
* decode the JSON response to an array.
146+
*/
147+
function apiGetJson(string $endpoint): array
148+
{
149+
$data = apiGet($endpoint);
150+
return json_decode($data, true);
151+
}
152+
153+
/**
154+
* DEBUG: Dump out the given variables and exit.
155+
*/
156+
function dd(...$args)
157+
{
158+
foreach ($args as $arg) {
159+
var_dump($arg);
160+
}
161+
exit(1);
162+
}
163+
164+
/**
165+
* Alert of an error then exit the script.
166+
*/
167+
function errorOut(string $text)
168+
{
169+
echo "ERROR: " . $text;
170+
exit(1);
171+
}

Diff for: php-generate-sitemap/readme.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Generate Sitemap
2+
3+
This script will scan through all pages, chapters books and shelves via the API to generate a sitemap XML file.
4+
5+
**This is a very simplistic single-script-file example of using the endpoints API together**
6+
, it is not a fully-featured & validated script.
7+
8+
Keep in mind, The sitemap generated will reflect content visible to the API user used when running the script.
9+
10+
## Requirements
11+
12+
You will need php (~7.2+) installed on the machine you want to run this script on.
13+
You will also need BookStack API credentials (TOKEN_ID & TOKEN_SECRET) at the ready.
14+
15+
## Running
16+
17+
```bash
18+
# Downloading the script
19+
# ALTERNATIVELY: Clone the project from GitHub and run locally.
20+
curl https://raw.githubusercontent.com/BookStackApp/api-scripts/main/php-generate-sitemap/generate-sitemap.php > generate-sitemap.php
21+
22+
# Setup
23+
# ALTERNATIVELY: Open the script and edit the variables at the top.
24+
export BS_URL=https://bookstack.example.com # Set to be your BookStack base URL
25+
export BS_TOKEN_ID=abc123 # Set to be your API token_id
26+
export BS_TOKEN_SECRET=123abc # Set to be your API token_secret
27+
28+
# Running the script
29+
php generate-sitemap.php <output_file_name>
30+
```
31+
32+
## Examples
33+
34+
```bash
35+
# Create a sitemap called "sitemap.xml within the current directory
36+
php generate-sitemap.php ./sitemap.xml
37+
```

0 commit comments

Comments
 (0)