Class: SmugMugAPI

Inherits:
Object
  • Object
show all
Defined in:
lib/smugmugapi.rb,
lib/smugmug/core.rb,
lib/smugmug/logon.rb,
lib/smugmug/upload.rb,
lib/smugmug/utility.rb,
lib/smugmug/exception.rb,
lib/smugmug/xmlstruct.rb

Defined Under Namespace

Classes: Error, XMLStruct

Constant Summary collapse

VERSION =
"0.9.0"
USERAGENT =
"SumMug Ruby API Library"

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base = "smugmug") ⇒ SmugMugAPI

Returns a new instance of SmugMugAPI.



11
12
13
# File 'lib/smugmugapi.rb', line 11

def initialize(base="smugmug")
  @base = base
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *params) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/smugmugapi.rb', line 15

def method_missing(method, *params)
  cmd = @base + "." + SmugMugAPI.camelize(method, false)
  if SmugMugAPI.groups.include?(method.to_s)
    SmugMugAPI.new(cmd)
  else
    param_hash = params.first || {}
    SmugMugAPI.call(
      { :method => cmd }.merge(param_hash)
    )
  end  
end

Class Attribute Details

.agentObject



27
28
29
# File 'lib/smugmug/core.rb', line 27

def agent
  @agent || USERAGENT
end

.api_keyObject



19
20
21
# File 'lib/smugmug/core.rb', line 19

def api_key
  @api_key || 'RXcw7ywveg9pEj1n6HBJfuDXqsFsx4jw'
end

.api_versionObject



15
16
17
# File 'lib/smugmug/core.rb', line 15

def api_version
  @api_version || '1.2.0'
end

.default_paramsObject



11
12
13
# File 'lib/smugmug/core.rb', line 11

def default_params
  @default_params ||= { :APIKey => api_key }
end

Class Method Details

.api_pathObject



23
24
25
# File 'lib/smugmug/core.rb', line 23

def api_path
  @url || "api.smugmug.com/hack/rest/#{api_version}/"
end

.call(params = {}, transport = "http") ⇒ Object



84
85
86
# File 'lib/smugmug/core.rb', line 84

def call(params={}, transport = "http")
  parse_response(get(params, {}, transport))
end

.camelize(str, upcase_first_char = true) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
# File 'lib/smugmug/utility.rb', line 2

def self.camelize(str, upcase_first_char = true)
  if upcase_first_char
    str = str.to_s.gsub(/(^|_)(.)/) { $2.upcase }
  else
    str = str.to_s.gsub(/_(.)/) { $1.upcase }
  end
  str = str.gsub(/URL/i, "URL").gsub(/EXIF/i, "EXIF")
  str = str.gsub(/(?!^)ID$/i, "ID")
  str = str.gsub(/EXIF/i, "EXIF")
  str = str.gsub(/X(.?)Large/i) { "X#{$1}Large" }
  str = "method" if str == "Method" #special case
  str
end

.get(passed_params, headers = {}, transport = 'http') ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/smugmug/core.rb', line 41

def get(passed_params, headers={}, transport='http')
  params = default_params.merge(passed_params)

  url = transport + "://" + api_path + "?" +
    params.map { |k,v| URI.encode("#{SmugMugAPI.camelize(k)}=#{v}") }.join("&")
  uri = URI.parse(url)
  headers['User-Agent'] = agent
  
  http = Net::HTTP.new(uri.host, uri.port)
  if transport == 'https'
    http.use_ssl     = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  end

  http.start do
    http.get(uri.path + '?' + uri.query, headers)
  end
end

.groupsObject



31
32
33
34
35
36
37
38
39
# File 'lib/smugmug/core.rb', line 31

def groups
  # it would be better to have a smugmug reflection method to 
  # get this information but this is a fairly exhaustive list 
  # and it will be easy to add to this as well
  %w(albums albumtemplates categories images login subcategories users 
  
     communities family friends orders pricing propricing sharegroups 
     styles themes watermarks)
end

.http_call(params = {}) ⇒ Object



80
81
82
# File 'lib/smugmug/core.rb', line 80

def http_call(params={})
  call(params, 'http')
end

.https_call(params = {}) ⇒ Object



76
77
78
# File 'lib/smugmug/core.rb', line 76

def https_call(params={})
  call(params, 'https')
end

.parse_response(response) ⇒ Object

Raises:



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/smugmug/core.rb', line 60

def parse_response(response)
  puts "HTTP #{response.code}: #{response.message}" if $DEBUG
  
  raise SmugMugAPI::Error.new("HTTP #{response.code} on #{url}") unless response.code.to_i == 200
  
  doc = REXML::Document.new(response.body)
  if doc.root.attributes['stat'] != 'ok'
    err = doc.root.elements['/rsp/err']
    code = err.attributes['code']
    msg = err.attributes['msg']
    raise SmugMugAPI::Error.new("#{code}: #{msg}")
  end

  XMLStruct.new(doc)      
end

Instance Method Details

#login(email, password) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/smugmug/logon.rb', line 3

def (email, password)
  res = SmugMugAPI.https_call(
  :method => 'smugmug.login.withPassword',
  :EmailAddress => email,
  :Password => password
  )

  SmugMugAPI.default_params[:SessionID] = res.session.id

  if block_given?
    begin
      yield res
    ensure
      logout
    end
  else
    res
  end
end

#login_with_hash(user, hash) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/smugmug/logon.rb', line 23

def (user, hash)
  res = SmugMugAPI.https_call(
    :method       => 'smugmug.login.withHash',
    :UserID       => user,
    :PasswordHash => hash
  )

  SmugMugAPI.default_params[:SessionID] = res.session.id

  if block_given?
    begin
      yield res
    ensure
      logout
    end
  else
    res
  end
end

#logoutObject



43
44
45
46
47
# File 'lib/smugmug/logon.rb', line 43

def logout
  result = SmugMugAPI.call(:method => 'smugmug.logout')
  SmugMugAPI.default_params.delete(:SessionID)
  result
end

#upload(fname, params = {}) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/smugmug/upload.rb', line 6

def upload(fname, params={})
  base_name = File.basename(fname)
  uri = URI.parse("http://upload.smugmug.com/#{base_name}")
  image = IO::read(fname)

  Net::HTTP.start(uri.host, uri.port) do |http|
    headers = {
      'Content-Type'  => 'image/jpeg',
      'Content-Lenth' => image.size.to_s,
      'Content-MD5'   => Digest::MD5.hexdigest(image),
      'X-Smug-SessionID' => SmugMugAPI.default_params[:SessionID],
      'X-Smug-Version'   => SmugMugAPI.api_version,
      'X-Smug-ResponseType' => 'REST',
      'X-Smug-FileName' => base_name
    }

    adjusted_headers = Hash[*params.map { |k,v| [ "X-Smug-" + SmugMugAPI.camelize(k), v.to_s ] }.flatten ]
    headers = headers.merge(adjusted_headers)

    resp = http.send_request('PUT', uri.request_uri, image, headers)
    SmugMugAPI.parse_response(resp)
  end
end