Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore/implementation-testing-and-documentation #6

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion confluence-api-client.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_development_dependency "bundler", "~> 1.8"
spec.add_development_dependency "bundler", "~> 2.1"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec-core"
spec.add_development_dependency "rspec-expectations"
spec.add_development_dependency "rspec-mocks"

spec.add_runtime_dependency "json"
spec.add_runtime_dependency "faraday"
spec.add_runtime_dependency "mime-types"
end
70 changes: 63 additions & 7 deletions lib/confluence/api/client.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
require "confluence/api/client/version"
require 'json'
require 'faraday'
require 'securerandom'
require 'mime/types'

module Confluence
module Api
class Client
attr_accessor :user, :pass, :url, :conn
attr_accessor :user, :pass, :url

def initialize(user, pass, url)
self.user = user
self.pass = pass
self.url = url
self.conn = Faraday.new(url: url) do |faraday|
faraday.request :url_encoded # form-encode POST params
# faraday.response :logger # log requests to STDOUT
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
faraday.basic_auth(self.user, self.pass)
end
end

def get(params)
Expand Down Expand Up @@ -47,6 +43,66 @@ def update(id, params)
JSON.parse(response.body)
end

def create_attachment(page_id, file_info, comment=nil)
sep = SecureRandom.hex(8)
file = resolve_file_info_from(file_info)
boundary = "-----------------------#{ sep }"

file_section = [
"Content-Disposition: form-data; name=\"file\"; filename=\"#{ file[:name] }\"",
"Content-Type: #{ file[:type] }",
"",
file[:content],
""
].join("\r\n")

content = "--#{ boundary }\r\n"
content << file_section
if comment
content << "--#{ boundary }\r\n"
comment_section = [
"Content-Disposition: form-data; name=\"comment\"",
"",
comment,
""
].join("\r\n")
content << comment_section
end
content << "--#{ boundary }--\r\n"

response = conn.post do |request|
request.headers['content-type'] = "multipart/form-data; boundary=#{ boundary }"
request.headers['X-Atlassian-Token'] = 'nocheck'
url = "rest/api/content/#{ page_id }/child/attachment"
request.url url
request.body = content
end

[response.status == 200 ? :ok : :error, JSON.parse(response.body)]
end

private

def resolve_file_info_from file_info
return file_info if file_info.kind_of?(Hash)

file_name = file_info.split('/').last

{
name: file_name,
type: MIME::Types.type_for(file_name).first,
content: File.open(file_info).read
}
end

def conn
@conn ||= Faraday.new(url: url) do |faraday|
faraday.request :url_encoded # form-encode POST params
# faraday.response :logger # log requests to STDOUT
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
faraday.basic_auth(user, pass)
end
end
end
end
end
111 changes: 109 additions & 2 deletions spec/confluence/api/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,114 @@
expect(Confluence::Api::Client::VERSION).not_to be nil
end

it 'does something useful' do
expect(false).to eq(true)
describe 'instance methods' do
subject(:instance) { described_class.new(user, pass, url) }
let(:user) { 'confluence-user-identifier' }
let(:pass) { 'confluence-api-key' }
let(:url) { 'confluence-url' }

let(:dummy_connection) { double(:connection) }
let(:dummy_request) { double(:request, headers: {}) }

describe '#create_attachment' do
let(:page_id) { 1234 }
let(:random_hex) { 'deadbeefdeadbeef' }
let(:comment) { nil }

before :each do
allow(instance).to receive(:conn).and_return(dummy_connection)
allow(dummy_connection).to receive(:post).and_yield(dummy_request)
allow(SecureRandom).to receive(:hex).with(8).and_return(random_hex)
allow(dummy_request).to receive(:url)
allow(dummy_request).to receive(:body=)

if comment.nil?
instance.create_attachment(page_id, file_info)
else
instance.create_attachment(page_id, file_info, comment)
end
end

context 'using a filename to identify the file' do
let(:file_info) { File.expand_path('../../../fixtures/example.txt', __FILE__) }
let(:expected_content) do
<<-TEXT
-------------------------deadbeefdeadbeef\r
Content-Disposition: form-data; name="file"; filename="example.txt"\r
Content-Type: text/plain\r
\r
This is a simple example text file.\r
-------------------------deadbeefdeadbeef--\r
TEXT
end

it 'submits what is expected' do
expect(dummy_connection).to have_received(:post)
expect(dummy_request.headers).to eq({
'content-type' => "multipart/form-data; boundary=-----------------------#{ random_hex }",
'X-Atlassian-Token' => 'nocheck'
})
expect(dummy_request).to have_received(:url).with("rest/api/content/#{ page_id }/child/attachment")
expect(dummy_request).to have_received(:body=).with expected_content
end

context 'and it includes a comment' do
let(:comment) { 'Silly Little Comment' }

let(:expected_content) do
<<-TEXT
-------------------------deadbeefdeadbeef\r
Content-Disposition: form-data; name="file"; filename="example.txt"\r
Content-Type: text/plain\r
\r
This is a simple example text file.\r
-------------------------deadbeefdeadbeef\r
Content-Disposition: form-data; name="comment"\r
\r
Silly Little Comment\r
-------------------------deadbeefdeadbeef--\r
TEXT
end

it 'submits what is expected' do
expect(dummy_request).to have_received(:body=).with expected_content
end
end
end

context 'using a hash to identify the file' do
let(:file_info) do
{
name: 'sample.txt',
type: 'text/plain',
content: <<-CONTENT
This is some lovely LOVELY content.
CONTENT
}
end

let(:expected_content) do
<<-TEXT
-------------------------deadbeefdeadbeef\r
Content-Disposition: form-data; name="file"; filename="sample.txt"\r
Content-Type: text/plain\r
\r
This is some lovely LOVELY content.
\r
-------------------------deadbeefdeadbeef--\r
TEXT
end

it 'submits what is expected' do
expect(dummy_connection).to have_received(:post)
expect(dummy_request.headers).to eq({
'content-type' => "multipart/form-data; boundary=-----------------------#{ random_hex }",
'X-Atlassian-Token' => 'nocheck'
})
expect(dummy_request).to have_received(:url).with("rest/api/content/#{ page_id }/child/attachment")
expect(dummy_request).to have_received(:body=).with expected_content
end
end
end
end
end
4 changes: 4 additions & 0 deletions spec/fixtures/example.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
First,Second,Third
a,b,c
1,2,3
x,y,z
1 change: 1 addition & 0 deletions spec/fixtures/example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is a simple example text file.