diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..38b48d3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://EditorConfig.org + +root = true +; Use 2 spaces for indentation in all files +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 +insert_final_newline = true \ No newline at end of file diff --git a/README.md b/README.md index 19312fd..883c30d 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,24 @@ pp client.auth_info pp client.collections_list(offset: 0, limit: 10) ``` +### Import + +`outliner` can be used to import an existing collection of documents into Outline. To do this run: + +```bash +export OUTLINE_BASE_URI="https://kb.example.com" +export OUTLINE_TOKEN="PUT YOUR TOKEN HERE" +export SOURCE_DIRECTORY="/home/user/wiki" +export DESTINATION_COLLECTION_NAME="Archive" +bundle install outliner +bundle exec bin/import "$SOURCE_DIRECTORY" "$DESTINATION_COLLECTION_NAME" +``` + +#### Limitations + +- Images are currently not imported +- Only `.md` files are currently supported + ## Development After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment. diff --git a/bin/import b/bin/import new file mode 100755 index 0000000..601a2f7 --- /dev/null +++ b/bin/import @@ -0,0 +1,78 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require "outliner" + +def validate + unless (ARGV.size == 2) and Dir.exists?(ARGV[0]) and ARGV[1].match(/\w+/) and ENV.key?('OUTLINE_BASE_URI') + puts "[E] Please call as import local_directory remote_collection_name" + puts "[E] Please export OUTLINE_BASE_URI and OUTLINE_TOKEN environment variables" + puts "[E] OUTLINE_BASE_URI should not include /api" + end +end + +def find_or_create_collection(name) + collections = CLIENT.collections_list(limit: 100)['data'] + collections.filter!{|c|c['name'] == name} + if collections.size >= 1 + collections[0]['id'] + else + CLIENT.collections_create(name: name, description: 'Imported Collection')['data']['id'] + end +end + +def create_documents_recursively(directory, collection_id, parent_document_id=nil) + cwd = Dir.pwd + Dir.chdir directory + # Create all documents for this directory + Dir["*.md"].each do |file| + params = { + title: file[0...-3], + text: file[0...-3] + "\n" + File.read(file) + "\n\n---\nImported at #{Time.now}", + collectionId: collection_id, + publish: true + } + + params[:parentDocumentId] = parent_document_id if parent_document_id + CLIENT.documents_create(params) + puts "[-] #{file}" + end + + # Create child documents for each sub-directory + Dir.glob('*').select {|f| File.directory? f}.each do |dir| + puts "[-] #{dir}" + params = { + title: dir, + text: dir +"\nImported at #{Time.now}", + collectionId: collection_id, + publish: true, + parentDocumentId: parent_document_id + } + response = CLIENT.documents_create(params) + create_documents_recursively(dir, collection_id, response['data']['id']) + end + Dir.chdir cwd +end + +# Run validations +validate + +# Setup variables +local_directory = ARGV[0] +remote_collection_name = ARGV[1] + +# Create a root collection +CLIENT = Outliner::Client.new ENV['OUTLINE_BASE_URI'] +root_collection_id = find_or_create_collection(remote_collection_name) + +begin + create_documents_recursively(local_directory, root_collection_id) + puts "[S] Import successful" +rescue Exception => e + # If we fail, print an error, and delete the collection + puts "[E] Import failed with error: #{e.message}" + CLIENT.collections_delete(id: root_collection_id) + puts "[E] Deleted collection, please report the issue or retry" + exit 1 +end +