davetron5000-gliffy 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1,5 @@
1
1
  require 'gliffy/handle'
2
+
3
+ # :include: ../README.rdoc
4
+ module Gliffy
5
+ end
@@ -0,0 +1,78 @@
1
+ require 'base64'
2
+ require 'openssl'
3
+ module Gliffy
4
+
5
+ # Encapsulates a request token, which is what Gliffy returns when
6
+ # you request a user's OAuth Token
7
+ class AccessToken
8
+ attr_reader :token
9
+ attr_reader :secret
10
+
11
+ # Create a new token
12
+ # [+token+] the token itself
13
+ # [+secret+] the token secret, used for signing requests
14
+ def initialize(token,secret)
15
+ raise ArgumentError.new('token is required') if token.nil?
16
+ raise ArgumentError.new('secret is required') if secret.nil?
17
+ @token = token
18
+ @secret = secret
19
+ end
20
+ end
21
+
22
+ # Encapsulates all the information needed to make a request of Gliffy
23
+ # outside of request-specific information.
24
+ class Credentials
25
+ attr_reader :consumer_key
26
+ attr_reader :consumer_secret
27
+ attr_reader :access_token
28
+ attr_reader :username
29
+ attr_reader :account_id
30
+ attr_reader :description
31
+ attr_reader :default_protocol
32
+
33
+ # Create a new Credentials object.
34
+ #
35
+ # [+consumer_key+] The OAuth consumer key given to you when you signed up
36
+ # [+consumer_secret+] The OAuth consumer secret given to you when you signed up
37
+ # [+description+] Description of the application you are writing
38
+ # [+account_id+] Your account id
39
+ # [+username+] the Gliffy user name/identifier
40
+ # [+access_token+] The access token you were given as a AccessToken, or nil if you don't have one yet.
41
+ def initialize(consumer_key, consumer_secret, description, account_id, username, default_protocol=:http, access_token = nil)
42
+ raise ArgumentError.new("consumer_key required") if consumer_key.nil?
43
+ raise ArgumentError.new("consumer_secret required") if consumer_secret.nil?
44
+ raise ArgumentError.new("description required") if description.nil? || description.strip == ''
45
+ raise ArgumentError.new("account_id required") if account_id.nil?
46
+ raise ArgumentError.new("username required") if username.nil?
47
+
48
+ @consumer_key = consumer_key
49
+ @consumer_secret = consumer_secret
50
+ @username = username
51
+ @access_token = access_token
52
+ @description = description
53
+ @account_id = account_id
54
+ @default_protocol = default_protocol
55
+ end
56
+
57
+ def has_access_token?
58
+ !@access_token.nil?
59
+ end
60
+
61
+ # Update the access token
62
+ def update_access_token(token)
63
+ @access_token = token
64
+ @access_token
65
+ end
66
+
67
+ # Clear the access token if, for some reason, you know the one
68
+ # you have is bad.
69
+ def clear_access_token
70
+ update_access_token(nil)
71
+ end
72
+
73
+ # Return a nonce that hasn't been used before (at least not in this space/time continuum)
74
+ def nonce
75
+ Time.now.to_f.to_s
76
+ end
77
+ end
78
+ end
@@ -1,368 +1,347 @@
1
- require 'gliffy/rest'
1
+ require 'gliffy/request'
2
2
  require 'gliffy/response'
3
- require 'gliffy/user'
4
- require 'gliffy/diagram'
5
- require 'gliffy/folder'
6
- require 'gliffy/account'
7
- require 'gliffy/config'
3
+ require 'gliffy/credentials'
8
4
 
9
5
  module Gliffy
10
6
  VERSION = '0.1.7'
11
7
 
12
-
13
8
  # A "handle" to access Gliffy on a per-user-session basis
14
9
  # Since most calls to gliffy require a user-token, this class
15
10
  # encapsulates that token and the calls made under it.
16
11
  #
17
- # The methods here are designed to raise exceptions if there are problems from Gliffy.
18
- # These problems usually indicate a programming error or a server-side problem with Gliffy and
19
- # are generally unhandleable. However, if you wish to do something better than simply raise an exception
20
- # you may override handle_error to do something else
21
- #
22
12
  class Handle
23
13
 
24
- # Create a new handle to gliffy for the given user. Tokens will be requested as needed
25
- def initialize(username,token=nil)
26
- @username = username
27
- @rest = Rest.new
28
- @logger = Logger.new(Config.config.log_device)
29
- @logger.level = Config.config.log_level
30
- if token
31
- @rest.current_token = token
32
- else
33
- update_token(username)
14
+ # Get access to the logger (useful for controlling log messages)
15
+ attr_reader :logger
16
+ # Get access to the Request (useful for hacking or testing)
17
+ attr_reader :request
18
+ # Get access to the current token (useful for caching to disk)
19
+ attr_reader :token
20
+
21
+ # Use this to override what happens when an error from Gliffy is received.
22
+ # The default (or nil) is to raise the exception that was generated.
23
+ # If you want to override this provide a block that takes the response that was
24
+ # received (which will be a hash-like object from HTTParty, possibly nil) and
25
+ # the exception that was generated (the message of which will have been parsed
26
+ # from Gliffy's XML if that was possible):
27
+ #
28
+ # # If we got an HTTParty response, try to print out the body and the Gliffy message
29
+ # # Otherwise, barf
30
+ # handle.response = Proc.new do |response,exception|
31
+ # if response && response.respond_to? :body
32
+ # puts exception.to_str
33
+ # puts response.body
34
+ # else
35
+ # raise exception
36
+ # end
37
+ # end
38
+ attr_writer :error_callback
39
+
40
+ # Create a new handle to Gliffy
41
+ # [+api_root+] root URL (without the protocol) of where to connect to Gliffy
42
+ # [+edit_api_root+] root URL (without the protocol) of where to connect to Gliffy for the edit link only
43
+ # [+credentials+] a Credentials object to use for access
44
+ # [+http+] override of http access class (use at your own risk; must be substituable for HTTPart)
45
+ # [+logger+] logger instance, if you don't want the default
46
+ def initialize(api_root,edit_api_root,credentials,http=nil,logger=nil)
47
+ @credentials = credentials
48
+ @request = Request.new(api_root,credentials)
49
+ @edit_link_request = Request.new(edit_api_root,credentials)
50
+ @request.http = http if !http.nil?
51
+ @logger = logger || Logger.new(STDOUT)
52
+ @logger.level = Logger::INFO
53
+ @request.logger = @logger
54
+ if !@credentials.has_access_token?
55
+ update_token
34
56
  end
57
+ @error_callback = nil
35
58
  end
36
59
 
37
- # Run an arbitrary rest call against gliffy, parsing the result. This allows you
38
- # essentially direct access to the underlying Gliffy::Rest, without having to worry about
39
- # setting it up.
40
- #
41
- # [+method+] a rest method, :get, :put, :post, :delete
42
- # [+url+] url to request, relative to Gliffy::Config#gliffy_root
43
- # [+params+] hash of parameters
44
- # [+headers+] hash of HTTP headers
45
- #
46
- # This will return a Gliffy::Response *if* the method you called returned XML.
47
- # If that is not what you want, you should use Gliffy::Rest.
48
- def rest_free(method,url,params={},headers={})
49
- Response.from_xml(do_simple_rest(method,url,"rest_free",params,headers))
50
- end
51
-
52
- # Adds a new user explicitly.
53
- def add_user(username)
54
- do_user(:put,username)
55
- end
56
-
57
- # Deletes the user from this account. May not be the user who owns the token for this
58
- # session (i.e. was passed to the constructor). <b>This cannot be undone</b>.
59
- def delete_user(username)
60
- do_user(:delete,username)
60
+ # Updates the token being used if there isn't one in the
61
+ # credentials, or by forcing
62
+ # [+force+] always attempt to update the token
63
+ def update_token(force=false)
64
+ if !@credentials.has_access_token? || force
65
+ @logger.debug("Requesting new token " + (force ? " by force " : " since we have none "))
66
+ response = @request.create(token_url,
67
+ :description => @credentials.description,
68
+ :protocol_override => :https)
69
+ @token = Response.from_http_response(response)
70
+ @credentials.update_access_token(@token)
71
+ end
61
72
  end
62
73
 
63
- # Allows +username+ to access +folder_path+ and all its child folders
64
- def add_user_to_folder(username,folder_path)
65
- do_user_folder(:put,username,folder_path)
74
+ # Delete the current token
75
+ def delete_token
76
+ make_request(:delete,token_url)
77
+ @credentials.clear_access_token
66
78
  end
67
79
 
68
- # Revokes +username+ access to +folder_path+
69
- def remove_user_from_folder(username,folder_path)
70
- do_user_folder(:delete,username,folder_path)
80
+ # Get admins of your account. Returns users
81
+ def account_admins
82
+ make_request(:get,"#{account_url}/admins.xml")
71
83
  end
72
84
 
73
- # Creates a new blank diagram (or based on an existing one)
74
- #
75
- # [+diagram_name+] the name of the new diagram
76
- # [+template_diagram_id+] the id of a diagram to use as a template. You must have access to this diagram
77
- #
78
- def create_diagram(diagram_name,template_diagram_id=nil)
79
- params = Hash.new
80
- params['diagramName'] = diagram_name
81
- params['templateDiagramId'] = template_diagram_id if template_diagram_id
82
- diagrams = do_simple_rest(:post,'diagrams',"Creating diagram named #{diagram_name}",params)
83
- if diagrams.size >= 1
84
- return diagrams[0]
85
+ # Returns all documents in the account
86
+ # [+show+] if nil, all documents are returned; if :public only public are returned.
87
+ def account_documents(show=nil)
88
+ if show.nil?
89
+ make_request(:get,"#{account_url}/documents.xml")
85
90
  else
86
- raise "Got no diagrams, but creation was successful."
91
+ make_request(:get,"#{account_url}/documents.xml",:public => show == :public)
87
92
  end
88
93
  end
89
94
 
90
- # Creates a folder with the given name. The parent path should already exist
91
- def create_folder(folder_path)
92
- do_folder(:put,folder_path)
95
+ # Returns all folders in the account
96
+ def account_folders
97
+ make_request(:get,"#{account_url}/folders.xml")
93
98
  end
94
99
 
95
- # deletes the diagram with the given id. <b>This cannot be undone</b>
96
- def delete_diagram(diagram_id)
97
- do_simple_rest(:delete,"diagrams/#{diagram_id}","Deleting diagram #{diagram_id}")
100
+ # Returns account meta data
101
+ # [+show_users+] if true, include the list of users in this account
102
+ def account_get(show_users=true)
103
+ make_request(:get,"#{account_url}.xml", :showUsers => show_users)[0]
98
104
  end
99
105
 
100
- # Deletes a folder, moving all diagrams in it to the default folder.
101
- # The folder must be empty
102
- # <b>This cannot be undone</b>
103
- def delete_folder(folder_path)
104
- folder_path = Folder.encode_path_elements(folder_path)
105
- do_simple_rest(:delete,"folders/#{folder_path}","Deleting folder #{folder_path}")
106
+ # Get users in your account
107
+ def account_users
108
+ make_request(:get,"#{account_url}/users.xml")
106
109
  end
107
110
 
108
- # Returns an array of User objects representing the admins of the account
109
- def get_admins
110
- do_simple_rest(:get,'admins','Getting admins for account')
111
- end
112
-
113
- # Gets the diagram as an image, possibly saving it to a file.
114
- #
115
- # [+diagram_id+] the id of the diagram to get
116
- # [+options+] a hash of options controlling the diagram and how it's fetched
117
- # [<tt>:size</tt>] one of :thumbnail, :small, :medium, or :large (default is :large)
118
- # [<tt>:file</tt>] if present, the diagram is written to the named file
119
- # [<tt>:mime_type</tt>] the mime type to retrie. You can also use :jpeg, :png and :svg as shortcuts (default is :jpeg)
120
- # [<tt>:version</tt>] if present, the version number to retrieve (default is most recent)
111
+ # Create a new document
112
+ # [+name+] Name of the new document
113
+ # [+folder_path+] Path in which to place the document initially (nil to use default)
114
+ # [+template_id+] document id of a document to copy when initializing this new document (nil to make a blank one)
115
+ # [+type+] If Gliffy ever supports other document types, use this
121
116
  #
122
- # returns the bytes of the diagram if file was nil, otherwise, returns true
123
- #
124
- def get_diagram_as_image(diagram_id,options={:mime_type => :jpeg})
125
- params,headers = create_diagram_request_info(options)
126
- update_token
127
- extension = extension_for(options[:mime_type])
128
- extension = ''
129
- bytes = @rest.get(url("diagrams/#{diagram_id}#{extension}"),params,headers)
130
- response = nil
131
- begin
132
- response = Response.from_xml(bytes)
133
- rescue
134
- response = nil
135
- end
136
-
137
- if response.respond_to?(:success?) && !response.success?
138
- handle_error(response,"While getting bytes of diagram #{diagram_id}")
117
+ # Returns a document representing the document that was created.
118
+ def document_create(name,folder_path=nil,template_id=nil,type=:diagram)
119
+ params = {
120
+ :documentName => name,
121
+ :documentType => type
122
+ }
123
+ params[:templateDiagramId] = template_id if !template_id.nil?
124
+ params[:folderPath] = normalize_folder_path(folder_path) if !folder_path.nil?
125
+ documents = make_request(:create,"#{account_url}/documents.xml",params)
126
+ return nil if documents.nil?
127
+ documents[0]
128
+ end
129
+
130
+ # Delete an existing document
131
+ def document_delete(document_id)
132
+ make_request(:delete,document_url(document_id))
133
+ end
134
+
135
+ # Get meta-data about a document.
136
+ # [+document_id+] identifier of the document
137
+ # [+show_revisions+] if true, include info about the documents' revision history
138
+ def document_get_metadata(document_id,show_revisions=false)
139
+ make_request(:get,document_metadata_url(document_id),:showRevisions => show_revisions)[0]
140
+ end
141
+
142
+ # Get a document; returning the actual bytes
143
+ # [+document_id+] identifier of the document
144
+ # [+type+] document type. Types known to work:
145
+ # [+:jpeg+] - JPEG
146
+ # [+:png+] - PNG
147
+ # [+:svg+] - SVG (for Visio import)
148
+ # [+:xml+] - Gliffy proprietary XML format (for archiving)
149
+ # [+size+] size to show, from biggest to smallest: :L, :M, :S, :T
150
+ # [+version+] The version to get, or nil to get the most recent
151
+ def document_get(document_id,type=:jpeg,size=:L,version=nil)
152
+ params = { :size => size }
153
+ params[:version] = version if !version.nil?
154
+ response = make_request(:get,document_url(document_id,type),params,false)
155
+ if (type == :xml) || (type == :svg)
156
+ response.body
139
157
  else
140
- if options[:file]
141
- fp = File.new(options[:file],'w')
142
- fp.puts bytes
143
- fp.close
144
- true
145
- else
146
- bytes
147
- end
158
+ response
148
159
  end
149
160
  end
150
161
 
151
- # returns the URL that would get the diagram in question. Same parameters as get_diagram_as_image
152
- def get_diagram_as_url(diagram_id,options={:mime_type => :jpeg})
153
- params,headers = create_diagram_request_info(options)
162
+ # Get a link to a document
163
+ # [+document_id+] identifier of the document
164
+ # [+type+] document type. Types known to work:
165
+ # [+:jpg+] - JPEG
166
+ # [+:png+] - PNG
167
+ # [+:svg+] - SVG (for Visio import)
168
+ # [+:xml+] - Gliffy proprietary XML format (for archiving)
169
+ # [+size+] size to show, from biggest to smallest: :L, :M, :S, :T
170
+ # [+version+] The version to get, or nil to get the most recent
171
+ def document_get_url(document_id,type=:jpg,size=:L,version=nil)
172
+ params = { :size => size }
173
+ params[:version] = version if !version.nil?
174
+ make_request(:get,document_url(document_id,type),params,false,true)
175
+ end
176
+
177
+ # Get the link to edit a document
178
+ def document_edit_link(document_id,return_url,return_text='Return')
154
179
  update_token
155
- extension = extension_for(options[:mime_type])
156
- @rest.create_url(url("diagrams/#{diagram_id}#{extension}"),params)
157
- end
158
-
159
- def extension_for(mime_type)
160
- case mime_type
161
- when :jpeg
162
- return ".jpg"
163
- when :png
164
- return ".png"
165
- when :svg
166
- return ".svg"
180
+ @edit_link_request.link_for(:GET,'',{
181
+ :launchDiagramId => document_id,
182
+ :returnURL => return_url,
183
+ :returnButtonText=> return_text})
184
+ end
185
+
186
+ # Move a document to a different folder
187
+ def document_move(document_id,new_path)
188
+ make_request(:move,folders_url(new_path) + "/documents/#{document_id}.xml")
189
+ end
190
+
191
+ # Update a document's meta-data or content
192
+ # [+document_id+] identifier of document to update
193
+ # [+options+] data to update; omission of an option will not change it
194
+ # [+:name+] change the name
195
+ # [+:public+] if false, will remove public statues, if true, will make public
196
+ # [+:content+] if present, should be the gliffy XML content to update (don't use this unless it's crucial)
197
+ def document_update(document_id,options)
198
+ if (options[:content])
199
+ make_request(:update,document_url(document_id),{:content => options[:content]})
200
+ end
201
+ if (options[:name] || options[:public])
202
+ params = {}
203
+ params[:documentName] = options[:name] if options[:name]
204
+ params[:public] = options[:public] if options[:public]
205
+ make_request(:update,document_metadata_url(document_id),params)
167
206
  end
168
- ""
169
207
  end
170
208
 
171
- # Returns a Diagram with the diagram's meta data filled in.
172
- def get_diagram_metadata(diagram_id)
173
- params = {'diagramId' => diagram_id}
174
- diagrams = do_simple_rest(:get,'diagrams',"Getting meta data for diagram #{diagram_id}",params)
175
- diagrams[0]
209
+ # Add a user to a folder
210
+ def folder_add_user(path,username)
211
+ make_request(:update,folder_users_url(path,username),{:read => true, :write => true})
176
212
  end
177
213
 
178
- # Gets a list of diagrams, either for the given folder, or the entire account
179
- def get_diagrams(folder_path=nil)
180
- folder_path = Folder.encode_path_elements(folder_path) if folder_path
181
- url = (folder_path ? "folders/#{folder_path}/" : "") + "diagrams"
182
- do_simple_rest(:get,url,"Get all diagrams in " + (folder_path ? folder_path : "account"))
214
+ # Create a new folder
215
+ # [+path+] the path to the folder, each path separated by a forward slash. If this starts with a forward slash
216
+ # it will attempt to make folder with the exact given path. This will probably fail. If this DOESN'T
217
+ # start with a slash, this will make the folder inside ROOT, which is what you want. So, don't
218
+ # start this with a slash.
219
+ def folder_create(path)
220
+ make_request(:create,"#{folders_url(path)}.xml")
183
221
  end
184
222
 
185
- # Gets the link that can be used <b>by this user while his token is valid</b> to edit the diagram.
186
- #
187
- # [+diagram_id+] the id of the diagram to edit
188
- # [+return_url+] if present represents the URL to return the user to after they have completed their editing. You should not urlencode this, it will be done for you
189
- # [+return_text+] the text that should be used in Gliffy to represent the "return to the application" button.
190
- #
191
- # returns a Gliffy::LaunchLink that contains the complete URL to be used to edit the given diagram and behave as described. The GliffyLaunchLink also contains the diagram name, which can be used for linking. Note that the url is relative to the Gliffy website
192
- def get_edit_diagram_link(diagram_id,return_url=nil,return_text=nil)
193
- params = Hash.new
194
- params['returnURL'] = CGI::escape(return_url) if return_url
195
- params['returnText'] = CGI::escape(return_text) if return_text
196
-
197
- do_simple_rest(:get,"diagrams/#{diagram_id}/launchLink","Getting launch link for diagram #{diagram_id}",params)
223
+ # Delete a folder
224
+ # [+path+] the path to the folder. See folder_create.
225
+ def folder_delete(path)
226
+ make_request(:delete,"#{folders_url(path)}.xml")
198
227
  end
199
228
 
200
- # array getFolders ()
201
- def get_folders()
202
- do_simple_rest(:get,'folders','Getting folders for account')
229
+ # Get the documents in a folder
230
+ # [+path+] the path to the folder whose documents to get
231
+ def folder_documents(path)
232
+ make_request(:get,"#{folders_url(path)}/documents.xml")
203
233
  end
204
234
 
205
- # Gets the folders that +username+ has access to, in nested form
206
- def get_user_folders(username)
207
- do_simple_rest(:get,"users/#{username}/folders","Getting folders for user #{username}")
235
+ # Get users with access to the folder
236
+ # [+path+] the path to the folder whose users to get
237
+ def folder_users(path)
238
+ make_request(:get,"#{folders_url(path)}/users.xml")
208
239
  end
209
240
 
210
- # Gets the users in the given folder, or in the entire account
211
- #
212
- # [+folder_path+] if present, returns users with access to this folder
213
- def get_users(folder_path=nil)
214
- url = ''
215
- if (folder_path)
216
- folder_path = Folder.encode_path_elements(folder_path)
217
- url += "folders/#{folder_path}/"
218
- end
219
- url += 'users'
220
- do_simple_rest(:get,url,"Getting users for " + (folder_path ? "folder #{folder_path}" : 'account'))
241
+ # Remove a user from access to the folder
242
+ def folder_remove_user(path,username)
243
+ make_request(:update,folder_users_url(path,username),{:read => false, :write => false})
221
244
  end
222
245
 
223
- # returns the user token if it exists
224
- def current_token()
225
- @rest.current_token
246
+ # Create a new user
247
+ # [+username+] the name to give this user
248
+ def user_create(username)
249
+ make_request(:create,"#{account_url}/users.xml",{ :userName => username })
226
250
  end
227
251
 
228
- # move diagram +diagram_id+ to folder path +folder_path+
229
- def move_diagram(diagram_id,folder_path)
230
- folder_path = Folder.encode_path_elements(folder_path)
231
- do_simple_rest(:put,"folders/#{folder_path}/diagrams/#{diagram_id}","Moving #{diagram_id} to folder #{folder_path}")
252
+ # Delete an existing user
253
+ def user_delete(username)
254
+ make_request(:delete,"#{user_url(username)}.xml")
232
255
  end
233
256
 
234
- # Updates the user.
235
- #
236
- # [+username+] user to update
237
- # [+attributes+] has of attributes to change.
238
- # [<tt>:email</tt>] email address
239
- # [<tt>:password</tt>] password for logging into Gliffy Online
240
- # [<tt>:admin</tt>] true to make them an admin, false to revoke their admin-ness
241
- #
242
- def update_user(username,attributes)
243
- params = Hash.new
244
- params['admin'] = attributes[:admin].to_s if attributes.has_key? :admin
245
- params['email'] = attributes[:email] if attributes[:email]
246
- params['password'] = attributes[:password] if attributes[:password]
247
- do_simple_rest(:put,"users/#{username}","Updating #{username}",params)
248
- end
249
-
250
- # Updates the user's token, if he needs it
251
- #
252
- # [+force+] if true, the token is updated regardless
253
- def update_token(force=false)
254
- if force || !@rest.current_token || @rest.current_token.expired?
255
- @logger.debug('Forcing a new token') if force
256
- @logger.debug('No current token') if !@rest.current_token
257
- @rest.current_token = nil
258
- token = Response.from_xml(@rest.get(url("users/#{@username}/token")))
259
- if (token.success?)
260
- @logger.info("User #{@username} assigned token #{token.token} from Gliffy")
261
- @rest.current_token = token
262
- else
263
- handle_error(token)
264
- end
265
- else
266
- @logger.debug('Not getting a new token')
267
- end
257
+ # Get the documents a user has access to (this is potentially expensive, as it results
258
+ # in multiple calls to gliffy)
259
+ # [username] if provided, get documents for the given username, otherwise get them for the logged-in user
260
+ def user_documents(username='$username')
261
+ return user_documents_helper(username,user_folders(username))
268
262
  end
269
263
 
270
- # Override this if you want error handling that doesn't rasie an exception
271
- #
272
- # [+error_response+] an Error object that holds the error from Gliffy
273
- # [+action_cause+] a string describing the action being taken when the error ocurred
274
- def handle_error(error_response,action_cause=nil)
275
- msg = ""
276
- msg += "While #{action_cause}: " if action_cause
277
- msg += error_response.to_s
278
- raise msg
264
+ # Get the folders a user has access to
265
+ # [username] if provided, get folders for the given username, otherwise get them for the logged-in user
266
+ def user_folders(username='$username')
267
+ make_request(:get,"#{user_url(username)}/folders.xml")
279
268
  end
280
269
 
281
- private
282
-
283
- def do_user(method,username)
284
- do_simple_rest(method,"users/#{username}","#{rest_to_text(method)} user #{username}")
270
+ # Update a user's meta-data
271
+ # [+username+] the username to operate on
272
+ # [+options+] the options for updating their info. Any omitted option will not change that value on the server.
273
+ # [+:email+] sets their email address
274
+ # [+:password+] sets their password for logging into gliffy.com
275
+ # [+:admin+] if true, sets them to be an admin; if false, revokes their admin privs
276
+ def user_update(username,options)
277
+ make_request(:update,user_url(username),options)
285
278
  end
286
279
 
287
- def do_folder(method,folder_path)
288
- folder_path = Folder.encode_path_elements(folder_path)
289
- do_simple_rest(method,"folders/#{folder_path}","#{rest_to_text(method)} folder #{folder_path}")
280
+ def anything(method,url,params={},parse=false,link=false)
281
+ make_request(method,url,params,parse,link)
290
282
  end
291
283
 
292
- def do_user_folder(method,username,folder_path)
293
- folder_path = Folder.encode_path_elements(folder_path)
294
- do_simple_rest(method,"folders/#{folder_path}/users/#{username}","#{rest_to_text(method)} #{username} to #{folder_path}")
284
+ private
285
+
286
+ def account_url; 'accounts/$account_id'; end
287
+ def user_url(username='$username'); "#{account_url}/users/#{username}"; end
288
+ def token_url; "#{user_url}/oauth_token.xml"; end
289
+ def document_url(id,type=:xml); "#{account_url}/documents/#{id}.#{type.to_s}"; end
290
+ def document_metadata_url(id); "#{account_url}/documents/#{id}/meta-data.xml"; end
291
+ def folders_url(path='');
292
+ path = normalize_folder_path(path)
293
+ "#{account_url}/folders/#{path}";
294
+ end
295
+ def folder_users_url(path,username)
296
+ folders_url(path) + "/users/#{username}.xml"
295
297
  end
296
298
 
297
- def create_diagram_request_info(options)
298
- mime_type = options[:mime_type]
299
- params = Hash.new
300
- params['size'] = size_to_param(options[:size]) if options[:size]
301
- params['version'] = options[:version] if options[:version]
302
- headers = Hash.new
303
- if mime_type.is_a? Symbol
304
- headers['Accept'] = mime_type_to_header(mime_type)
305
- else
306
- headers['Accept'] = mime_type
299
+ def user_documents_helper(username,folders)
300
+ documents = []
301
+ return documents if folders.nil?
302
+ folders.each do |one_folder|
303
+ docs = folder_documents(one_folder.path)
304
+ if docs
305
+ docs.each do |doc|
306
+ documents << doc
307
+ end
308
+ end
309
+ rest = user_documents_helper(username,one_folder.child_folders)
310
+ rest.each { |d| documents << d} if rest
307
311
  end
308
- [params,headers]
312
+ return documents
309
313
  end
310
314
 
311
- def do_simple_rest_helper(method,url_fragment,description,params=nil,headers={},first=false)
315
+ # Handles the mechanics of making the request
316
+ # [+method+] the gliffy "action"
317
+ # [+url+] the url, relative to the gliffy API root, no params/query string stuff
318
+ # [+params+] hash of parameters
319
+ # [+parse+] if true, request is parsed; set to false to get the raw result back
320
+ # [+link_only+] don't make a request just send the full link (useful for <img> tags)
321
+ def make_request(method,url,params=nil,parse=true,link_only=false)
312
322
  update_token
313
- response = Response.from_xml(@rest.send(method,url(url_fragment),params,headers))
314
- if !response.success?
315
- if first
316
- @logger.warn("Possible token problem, try again after updating token")
317
- update_token true
318
- response = do_simple_rest_helper(method,url_fragment,description,params,headers,false)
323
+ if link_only
324
+ @request.link_for(method,url,params)
325
+ else
326
+ @logger.debug("Requesting #{url} with {#params.inspect}")
327
+ response = @request.send(method,url,params)
328
+ @logger.debug("Got back #{response.body}")
329
+ if parse
330
+ Response.from_http_response(response,@error_callback)
319
331
  else
320
- handle_error(response,description)
332
+ response
321
333
  end
322
334
  end
323
- response
324
- end
325
-
326
- def do_simple_rest(method,url_fragment,description,params=nil,headers={})
327
- do_simple_rest_helper(method,url_fragment,description,params,headers,true)
328
- end
329
-
330
-
331
- def url(fragment)
332
- "/accounts/#{Config.config.account_name}/#{fragment}"
333
- end
334
-
335
- def mime_type_to_header(mime_type_symbol)
336
- case mime_type_symbol
337
- when :jpeg: 'image/jpeg'
338
- when :jpg: 'image/jpg'
339
- when :png: 'image/png'
340
- when :svg: 'image/svg+xml'
341
- else raise "#{mime_type_symbol} is not a known mime type"
342
- end
343
- end
344
- def size_to_param(size)
345
- return nil if !size
346
- case size
347
- when :thumbnail: 'T'
348
- when :small: 'S'
349
- when :medium: 'M'
350
- when :large: 'L'
351
- else raise "#{size} is not a supported size"
352
- end
353
335
  end
354
336
 
355
- def rest_to_text(method)
356
- case method
357
- when :put : 'Creating'
358
- when :delete : 'Deleting'
359
- when :post : 'Updating'
360
- when :get : 'Getting'
361
- else
362
- raise "Unknown method #{method.to_s}"
337
+ ROOT_FOLDER = 'ROOT'
338
+ # Prepends the path with "ROOT" if the path doesn't start with a slash
339
+ def normalize_folder_path(path)
340
+ return '' if path.nil? || path == ''
341
+ if !(path =~ /^\//) && !(path =~ /^#{ROOT_FOLDER}$/) && !(path =~ /^#{ROOT_FOLDER}\//)
342
+ path = "#{ROOT_FOLDER}/" + path
363
343
  end
344
+ path
364
345
  end
365
-
366
-
367
346
  end
368
347
  end