gliffy 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ Gliffy API wrapper
2
+ ==================
3
+
4
+ Basic usage
5
+ -----------
6
+
7
+ ### Initialization
8
+
9
+ api = Gliffy::API.new(ACCOUNT_ID, API_KEY, API_SECRET)
10
+ api.impersonate('user@domain.com')
11
+ api.account.root.documents
12
+
13
+ ### Working with documents
14
+
15
+ doc = account.document(DOCUMENT_ID)
16
+ doc.name
17
+ doc.editor(RETURN_TO, RETURN_BUTTON_TEXT)
18
+ doc.png.full
19
+
20
+ ### Navigating folders
21
+
22
+ root = account.root
23
+ root.folders[0].documents
24
+ root.folders[1].name
25
+ root.folders[1].path
data/lib/gliffy.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'date'
2
+
3
+ require 'gliffy/api'
4
+ require 'gliffy/api/facade'
5
+ require 'gliffy/api/response'
6
+ require 'gliffy/account'
7
+ require 'gliffy/document'
8
+ require 'gliffy/document_png'
9
+ require 'gliffy/folder'
10
+
11
+ require 'gliffy/oauth/helper'
12
+
13
+ module Gliffy
14
+ class << self
15
+ def default_application_name
16
+ "Gliffy Ruby Gem"
17
+ end
18
+
19
+ # some calls (e.g. OAuth token generation) should be done through
20
+ # secure HTTPS; other calls (e.g. actions performed by
21
+ # non-privileged accounts) should be done though plain HTTP
22
+ #
23
+ # We're using protocol-relative URL here.
24
+ def api_root
25
+ '//www.gliffy.com/api/1.0'
26
+ end
27
+
28
+ # We're using protocol-relative (//hosrname/path/ format) URL here.
29
+ def web_root
30
+ '//www.gliffy.com'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,59 @@
1
+ module Gliffy
2
+ class Account
3
+ TYPE_BUSINESS = "Business"
4
+
5
+ attr_reader :api
6
+ attr_reader :id
7
+ attr_reader :name
8
+ attr_reader :max_users, :type, :terms_accepted
9
+ attr_reader :expiration_date
10
+
11
+ def self.load(api, response)
12
+ Gliffy::Account.new(
13
+ api,
14
+ :id => response.integer('//g:account/@id'),
15
+ :name => response.string('//g:account/g:name'),
16
+ :max_users => response.integer('//g:account/@max-users'),
17
+ :type => response.string('//g:account/@account-type'),
18
+ :terms_accepted => response.string('//g:account/@terms') == "true",
19
+ :expiration_date => response.timestamp('//g:account/g:expiration-date')
20
+ )
21
+ end
22
+
23
+ def root
24
+ @root ||= load_root
25
+ end
26
+
27
+ def document(document_id)
28
+ response = api.get("/accounts/#{id}/documents/#{document_id}/meta-data.xml",
29
+ :action => 'get')
30
+
31
+ Gliffy::Document.load(
32
+ self,
33
+ response.node('//g:document')
34
+ )
35
+ end
36
+
37
+ private
38
+
39
+ def initialize(api, params)
40
+ @api = api
41
+
42
+ @id = params[:id]
43
+ @name = params[:name]
44
+ @max_users = params[:max_users]
45
+ @type = params[:type]
46
+ @terms_accepted = params[:terms_accepted]
47
+ @expiration_date = params[:expiration_date]
48
+ end
49
+
50
+ def load_root
51
+ response = api.get_folders(id)
52
+
53
+ Gliffy::Folder.load(
54
+ self,
55
+ response.node("/g:response/g:folders/g:folder")
56
+ )
57
+ end
58
+ end
59
+ end
data/lib/gliffy/api.rb ADDED
@@ -0,0 +1,89 @@
1
+ require 'uri'
2
+ require 'oauth'
3
+ require 'nokogiri'
4
+ require 'cgi'
5
+
6
+ module Gliffy
7
+ class API
8
+ attr_reader :consumer
9
+ attr_reader :account_id
10
+ attr_accessor :application_name
11
+
12
+ def initialize(account_id, key, secret)
13
+ @consumer = init_consumer(key, secret)
14
+ @account_id = account_id
15
+ @application_name = Gliffy.default_application_name
16
+ end
17
+
18
+ def plain
19
+ Gliffy::API::Facade.http(self)
20
+ end
21
+
22
+ def secure
23
+ Gliffy::API::Facade.https(self)
24
+ end
25
+
26
+ def get(url, params = {})
27
+ Gliffy::API::Response.new(Nokogiri.XML(raw(url, params)))
28
+ end
29
+
30
+ def raw(url, params = {})
31
+ r = token.get(url + '?' + query(params))
32
+ r.body
33
+ end
34
+
35
+ def post(url, params)
36
+ r = token.post(url, params)
37
+ Gliffy::API::Response.new(Nokogiri.XML(r.body))
38
+ end
39
+
40
+ def web(url, params)
41
+ consumer.create_signed_request(
42
+ :get,
43
+ url + '?' + query(params),
44
+ token
45
+ ).path
46
+ end
47
+
48
+ def account
49
+ @account ||= load_account
50
+ end
51
+
52
+ def impersonate(user)
53
+ escaped_id = URI.escape @account_id.to_s
54
+ escaped_user = URI.escape user
55
+
56
+ response = secure.post(
57
+ "/accounts/#{escaped_id}/users/#{escaped_user}/oauth_token.xml",
58
+ :action => 'create',
59
+ :description => application_name
60
+ )
61
+
62
+ token.token = response.string('//g:oauth-token')
63
+ token.secret = response.string('//g:oauth-token-secret')
64
+ end
65
+
66
+ private
67
+
68
+ def query(params)
69
+ params.map {|k, v| "#{CGI.escape k.to_s}=#{CGI.escape v.to_s}" }.join('&')
70
+ end
71
+
72
+ def token
73
+ @token ||= OAuth::AccessToken.new @consumer
74
+ end
75
+
76
+ def load_account
77
+ response = plain.get("/accounts/#{account_id}.xml",
78
+ { :action => 'get' })
79
+ Gliffy::Account.load(plain, response)
80
+ end
81
+
82
+ def init_consumer(key, secret)
83
+ OAuth::Consumer.new(key,
84
+ secret,
85
+ :site => Gliffy.web_root,
86
+ :scheme => :query_string)
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,49 @@
1
+ module Gliffy
2
+ class API
3
+ class Facade
4
+ def self.http(api)
5
+ Facade.new("http", api)
6
+ end
7
+
8
+ def self.https(api)
9
+ Facade.new("https", api)
10
+ end
11
+
12
+ def raw(partial_url, params = {})
13
+ @api.raw(api_root + partial_url, params)
14
+ end
15
+
16
+ def get(partial_url, params)
17
+ @api.get(api_root + partial_url, params)
18
+ end
19
+
20
+ def post(partial_url, params)
21
+ @api.post(api_root + partial_url, params)
22
+ end
23
+
24
+ def web(partial_url, params)
25
+ @api.web(web_root + partial_url, params)
26
+ end
27
+
28
+ def get_folders(account_id)
29
+ get("/accounts/#{account_id}/folders.xml",
30
+ :action => 'get')
31
+ end
32
+
33
+ private
34
+
35
+ def initialize(protocol, api)
36
+ @protocol = protocol
37
+ @api = api
38
+ end
39
+
40
+ def api_root
41
+ @protocol + ":" + Gliffy.api_root
42
+ end
43
+
44
+ def web_root
45
+ @protocol + ":" + Gliffy.web_root
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,49 @@
1
+ module Gliffy
2
+ class API::Response
3
+ def initialize(base)
4
+ @base = base
5
+ end
6
+
7
+ def content
8
+ @base.content
9
+ end
10
+
11
+ def nodes(path)
12
+ @base.xpath(path, namespaces).map { |n| Gliffy::API::Response.new(n) }
13
+ end
14
+
15
+ def node(path)
16
+ Gliffy::API::Response.new(@base.at_xpath(path, namespaces))
17
+ end
18
+
19
+ def string(path)
20
+ node(path).content
21
+ end
22
+
23
+ def integer(path)
24
+ string(path).to_i
25
+ end
26
+
27
+ def timestamp(path)
28
+ parse_timestamp(string(path))
29
+ end
30
+
31
+ def exists(path)
32
+ !@base.at_xpath(path, namespaces).nil?
33
+ end
34
+
35
+ private
36
+
37
+ # Gliffy XML namespace to be used in XPath expressions
38
+ def namespaces
39
+ { "g" => "http://www.gliffy.com" }
40
+ end
41
+
42
+ # As opposed to UNIX timestamp, timestamps returned by Gliffy API
43
+ # are in milliseconds, so we should divide them by 1000 before
44
+ # converting to real datetime objectsq
45
+ def parse_timestamp(value)
46
+ Time.at(value.to_i / 1000).to_datetime
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,69 @@
1
+ module Gliffy
2
+ class Document
3
+ attr_reader :owner
4
+ attr_reader :id
5
+ attr_reader :is_public
6
+ attr_reader :versions
7
+ attr_reader :name
8
+ attr_reader :modified, :created, :published
9
+
10
+ def self.load(owner, node)
11
+ @loaded ||= {}
12
+
13
+ id = node.integer('@id')
14
+ if not @loaded.has_key? id then
15
+ @loaded[id] = Gliffy::Document.new(
16
+ owner,
17
+ id,
18
+ :is_public => node.exists('@is-public'),
19
+ :versions => node.integer('@num-versions'),
20
+ :name => node.string('g:name'),
21
+ :modified => node.timestamp('g:mod-date'),
22
+ :created => node.timestamp('g:create-date'),
23
+ :published => node.timestamp('g:published-date')
24
+ )
25
+ end
26
+
27
+ @loaded[id]
28
+ end
29
+
30
+ def self.clear_cache
31
+ @loaded = {}
32
+ end
33
+
34
+ def editor(return_url, return_text)
35
+ api.web(
36
+ "/gliffy/",
37
+ :launchDiagramId => id,
38
+ :returnURL => return_url,
39
+ :returnButtonText => return_text
40
+ )
41
+ end
42
+
43
+ def png
44
+ Document::PNG.new(self)
45
+ end
46
+
47
+ def public?
48
+ is_public
49
+ end
50
+
51
+ def api
52
+ owner.api
53
+ end
54
+
55
+ private
56
+
57
+ def initialize(owner, id, params)
58
+ @owner = owner
59
+ @id = id
60
+
61
+ @is_public = params[:is_public]
62
+ @versions = params[:versions]
63
+ @name = params[:name]
64
+ @modified = params[:modified]
65
+ @created = params[:created]
66
+ @published = params[:published]
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,56 @@
1
+ module Gliffy
2
+ class Document::PNG
3
+ attr_reader :document
4
+
5
+ SIZE_THUMBNAIL = "T"
6
+ SIZE_SMALL = "S"
7
+ SIZE_MEDIUM = "M"
8
+ SIZE_FULL = "L"
9
+
10
+ def initialize(document)
11
+ @document = document
12
+ end
13
+
14
+ def content(size)
15
+ api.raw(
16
+ "/accounts/#{account_id}/documents/#{document_id}.png",
17
+ :action => 'get',
18
+ :size => size
19
+ )
20
+ end
21
+
22
+ def thumbnail
23
+ content(SIZE_THUMBNAIL)
24
+ end
25
+
26
+ def small
27
+ content(SIZE_SMALL)
28
+ end
29
+
30
+ def medium
31
+ content(SIZE_MEDIUM)
32
+ end
33
+
34
+ def full
35
+ content(SIZE_FULL)
36
+ end
37
+
38
+ private
39
+
40
+ def api
41
+ document.api
42
+ end
43
+
44
+ def account
45
+ document.owner
46
+ end
47
+
48
+ def document_id
49
+ document.id
50
+ end
51
+
52
+ def account_id
53
+ account.id
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,71 @@
1
+ require 'uri'
2
+
3
+ module Gliffy
4
+ class Folder
5
+ attr_reader :name, :path
6
+ attr_reader :owner, :parent
7
+ attr_reader :folders
8
+
9
+ def self.load(owner, node)
10
+ Gliffy::Folder.new(
11
+ owner,
12
+ node.string('g:name'),
13
+ node.string('g:path'),
14
+ node.nodes('g:folder').map {|n| Gliffy::Folder.load(owner, n)}
15
+ )
16
+ end
17
+
18
+ def initialize(owner, name, path, folders)
19
+ @owner = owner
20
+ @name = name
21
+ @path = path
22
+
23
+ @folders = folders
24
+ @folders.each do |f|
25
+ f.parent = self
26
+ end
27
+ end
28
+
29
+ def parent=(parent)
30
+ if path != parent.path + "/" + name then
31
+ raise "Invalid parent"
32
+ end
33
+
34
+ @parent = parent
35
+ end
36
+
37
+ def documents
38
+ @documents ||= load_documents
39
+ end
40
+
41
+ def root?
42
+ path == "ROOT"
43
+ end
44
+
45
+ private
46
+
47
+ def api
48
+ owner.api
49
+ end
50
+
51
+ def account_id
52
+ owner.id
53
+ end
54
+
55
+ def escaped_path
56
+ path.gsub(' ', '+')
57
+ end
58
+
59
+ def load_documents
60
+ # Path is alphanumeric + spaces and '/'. Spaces should be
61
+ # escaped; slashes should NOT be escaped.
62
+ url = "/accounts/#{account_id}/folders/#{escaped_path}/documents.xml"
63
+ response = api.get(url,
64
+ :action => "get")
65
+
66
+ response
67
+ .nodes('//g:document')
68
+ .map { |n| Gliffy::Document.load(owner, n) }
69
+ end
70
+ end
71
+ end