]> BookStack Code Mirror - api-scripts/commitdiff
Adding a Ruby example, exporting list of all pages for use in CSV/Excel konung/main 20/head konung/main
authorNick Gorbikoff <redacted>
Fri, 26 Apr 2024 22:47:16 +0000 (17:47 -0500)
committerNick Gorbikoff <redacted>
Fri, 26 Apr 2024 22:47:16 +0000 (17:47 -0500)
ruby-generate-csv-list-of-all-pages/.env [new file with mode: 0644]
ruby-generate-csv-list-of-all-pages/Gemfile [new file with mode: 0644]
ruby-generate-csv-list-of-all-pages/README.md [new file with mode: 0644]
ruby-generate-csv-list-of-all-pages/export_pages.rb [new file with mode: 0644]

diff --git a/ruby-generate-csv-list-of-all-pages/.env b/ruby-generate-csv-list-of-all-pages/.env
new file mode 100644 (file)
index 0000000..798716a
--- /dev/null
@@ -0,0 +1,3 @@
+BS_URL=<your_bookstack_url>
+BS_TOKEN_ID=<your_api_token_id>
+BS_TOKEN_SECRET=<your_api_token_secret>
diff --git a/ruby-generate-csv-list-of-all-pages/Gemfile b/ruby-generate-csv-list-of-all-pages/Gemfile
new file mode 100644 (file)
index 0000000..7173b60
--- /dev/null
@@ -0,0 +1,5 @@
+source 'https://rubygems.org'
+
+gem 'httparty'
+gem 'dotenv'
+gem 'logger'
diff --git a/ruby-generate-csv-list-of-all-pages/README.md b/ruby-generate-csv-list-of-all-pages/README.md
new file mode 100644 (file)
index 0000000..ae9d79b
--- /dev/null
@@ -0,0 +1,78 @@
+# BookStack Data Exporter
+
+This Ruby script allows you to export data from a BookStack instance into a CSV file. The exported data includes information about pages, books, and shelves, along with their respective URLs and modification dates.
+
+## Prerequisites
+
+Before running the script, make sure you have the following:
+
+- Ruby installed on your system
+- Access to a BookStack instance with API enabled
+- BookStack API token ID and token secret
+
+## Installation
+
+1. Clone this repository or download the script file.
+2. Install the required dependencies by running the following command:
+
+   ```
+   bundle install
+   ```
+
+3. Create a `.env` file in the same directory as the script and provide the following environment variables:
+
+   ```
+   BS_URL=<your_bookstack_url>
+   BS_TOKEN_ID=<your_api_token_id>
+   BS_TOKEN_SECRET=<your_api_token_secret>
+   ```
+
+   Replace `<your_bookstack_url>`, `<your_api_token_id>`, and `<your_api_token_secret>` with your actual BookStack URL, API token ID, and API token secret, respectively.
+
+## Usage
+
+To run the script and export the data, execute the following command:
+
+```
+ruby export_bookstack_data.rb
+```
+
+The script will retrieve data from your BookStack instance and generate a CSV file named `bookstack_data.csv` in the same directory.
+
+## CSV Output
+
+The generated CSV file will have the following columns:
+
+- Type: Indicates whether the row represents a page or a book.
+- ID: The unique identifier of the page or book.
+- Name: The name of the page or book.
+- URL: The URL of the page or book, formatted as an Excel hyperlink.
+- Book ID: The ID of the book to which the page belongs (applicable only for pages).
+- Book Name: The name of the book to which the page belongs (applicable only for pages).
+- Book URL: The URL of the book, formatted as an Excel hyperlink (applicable only for pages).
+- Shelf Name: The name of the shelf to which the book belongs.
+- Date Modified: The last modification date of the page or book.
+
+The URLs in the 'URL' and 'Book URL' columns are wrapped in the `=HYPERLINK()` function, allowing you to easily access the respective pages and books directly from the CSV file when opened in Excel.
+HYPERLINK() - is an Excel shortcut to make URL clickable, feel free to remove, if you don't use Excel.
+
+## Logging
+
+Logging to STDOUT, but can be adjusted to a file.
+
+## Example
+
+Here's an example of how the generated CSV file might look.
+
+```
+Type,ID,Name,URL,Book ID,Book Name,Book URL,Shelf Name,Date Modified
+Page,1,Introduction,=HYPERLINK("https://example.com/books/1/page/1"),1,User Guide,=HYPERLINK("https://example.com/books/1"),Getting Started,2023-05-01T10:00:00.000000Z
+Page,2,Installation,=HYPERLINK("https://example.com/books/1/page/2"),1,User Guide,=HYPERLINK("https://example.com/books/1"),Getting Started,2023-05-02T11:30:00.000000Z
+Book,1,User Guide,=HYPERLINK("https://example.com/books/1"),,,,Getting Started,2023-05-01T09:00:00.000000Z
+```
+
+## License
+
+This script is released under the [MIT License](LICENSE).
+
+Feel free to customize and adapt the script to suit your specific requirements.
diff --git a/ruby-generate-csv-list-of-all-pages/export_pages.rb b/ruby-generate-csv-list-of-all-pages/export_pages.rb
new file mode 100644 (file)
index 0000000..5b0298f
--- /dev/null
@@ -0,0 +1,103 @@
+require 'csv'
+require 'httparty'
+require 'dotenv/load'
+require 'logger'
+require 'bundler/setup'
+
+Bundler.require(:default)
+
+logger = Logger.new('bookstack.log')
+
+class BookStackAPI
+  include HTTParty
+  base_uri ENV['BS_URL']
+  headers 'Authorization' => "Token #{ENV['BS_TOKEN_ID']}:#{ENV['BS_TOKEN_SECRET']}"
+  format :json
+
+  def self.get(path, options = {})
+    url = "#{base_uri}#{path}"
+    ::Logger.new(STDOUT).info("Making GET request to: #{url}")
+    ::Logger.new(STDOUT).info("Query parameters: #{options[:query]}")
+    response = super(path, options)
+    ::Logger.new(STDOUT).info("Response status: #{response.code}")
+    response
+  end
+end
+
+def get_all_items(path)
+  results = []
+  page_size = 500
+  offset = 0
+  total = 1
+
+  while offset < total
+    sleep(0.5) if offset > 0
+
+    response = BookStackAPI.get(path, query: { count: page_size, offset: offset })
+    total = response['total']
+    offset += page_size
+
+    results.concat(response['data'])
+  end
+
+  ::Logger.new(STDOUT).info("Retrieved #{results.count} items from #{path}")
+  results
+end
+
+def generate_csv(pages, books, shelves)
+  book_map = books.map { |book| [book['id'], book] }.to_h
+  shelf_map = shelves.map { |shelf| [shelf['id'], shelf] }.to_h
+
+  CSV.open('bookstack_data.csv', 'w') do |csv|
+    csv << ['Type', 'ID', 'Name', 'URL', 'Book ID', 'Book Name', 'Book URL', 'Shelf Name', 'Date Modified', 'Date Created']
+
+    pages.each do |page|
+      book = book_map[page['book_id']]
+      shelf_name = shelf_map[book['shelf_id']]['name'] if book && shelf_map[book['shelf_id']]
+      csv << [
+        'Page',
+        page['id'],
+        page['name'],
+        "=HYPERLINK(\"#{ENV['BS_URL']}/books/#{page['book_id']}/page/#{page['id']}\")",
+        page['book_id'],
+        book ? book['name'] : '',
+        "=HYPERLINK(\"#{ENV['BS_URL']}/books/#{page['book_id']}\")",
+        shelf_name || '',
+        page['updated_at'],
+        page['created_at']
+      ]
+    end
+
+    books.each do |book|
+      shelf_name = shelf_map[book['shelf_id']]['name'] if shelf_map[book['shelf_id']]
+      csv << [
+        'Book',
+        book['id'],
+        book['name'],
+        "=HYPERLINK(\"#{ENV['BS_URL']}/books/#{book['id']}\")",
+        '',
+        '',
+        '',
+        shelf_name || '',
+        book['updated_at'],
+        page['created_at']
+      ]
+    end
+  end
+end
+
+begin
+  logger.info('Started generating BookStack data CSV')
+  logger.info("BookStack URL: #{ENV['BS_URL']}")
+
+  pages = get_all_items('/api/pages')
+  books = get_all_items('/api/books')
+  shelves = get_all_items('/api/shelves')
+
+  generate_csv(pages, books, shelves)
+
+  logger.info('CSV file generated: bookstack_data.csv')
+rescue StandardError => e
+  logger.error("Error: #{e.message}")
+  logger.error(e.backtrace.join("\n"))
+end