picturelife 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 70cb3e82a2e7a9da6aef56b46beedb101c8dd3a3
4
+ data.tar.gz: 814c20f34212c76c3ef2ab463482c045eebc4fb4
5
+ SHA512:
6
+ metadata.gz: 7a293f8d2025a200ce2c9eddb7b81b4a8a273771817f9bed148f6a072b12552bec02b883bb562b130b9b84f2f1e3153efcbad3fa779b56418b904fce2198c15c
7
+ data.tar.gz: 4f630b5d9a3bf5ff323b32d1a604153c8dab6090be1dea547d6e41ddd9b927104c519c86d9765836ed1c779647ad2ac236c6108fb84853a390a3a3e9dbe50eba
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in picturelife.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,11 @@
1
+ guard 'rspec' do
2
+
3
+ watch(%r{^lib/(.+).rb$}) do |m|
4
+ "spec/#{m[1]}_spec.rb"
5
+ end
6
+
7
+ watch(%r{^spec/(.+).rb$}) do |m|
8
+ "spec/#{m[1]}.rb"
9
+ end
10
+
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Albert Zak
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Picturelife
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ gem 'picturelife'
8
+
9
+ And then execute:
10
+
11
+ $ bundle
12
+
13
+ ## Features
14
+
15
+ - Resumable photo upload
16
+ - Authentication via OAuth
17
+ - Minimal dependencies
18
+ - Ruby syntax
19
+
20
+ ## Usage
21
+
22
+ ### Setup
23
+ ```ruby
24
+
25
+ require 'picturelife'
26
+
27
+ Picturelife.client_id = ENV['CLIENT_ID']
28
+ Picturelife.client_secret = ENV['CLIENT_SECRET']
29
+
30
+ Picturelife.redirect_uri = 'http://localhost:3000/oauth'
31
+
32
+ ```
33
+
34
+ ### Authorization
35
+
36
+ ```ruby
37
+
38
+ <a href="<%= Picturelife.authorization_uri %>">Click here</a> to connect to Picturelife!</a>
39
+
40
+ ```
41
+
42
+ ```ruby
43
+
44
+ get '/oauth' do
45
+ code = params['code']
46
+ Picturelife.access_token_from_code = code
47
+ end
48
+
49
+ ```
50
+
51
+ ```ruby
52
+
53
+ Picturelife::Medias.index(limit: 10)
54
+
55
+
56
+ ```
57
+
58
+
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rspec/core/rake_task'
2
+ require 'bundler/gem_tasks'
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |task|
5
+ task.rspec_opts = ['--color', '--format', 'nested']
6
+ end
7
+
8
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ require 'cgi'
2
+ require 'json'
3
+ require 'oauth'
4
+ require 'excon'
5
+ require 'net/http'
6
+ require 'digest/sha2'
7
+ require 'picturelife/error'
8
+ require 'picturelife/util'
9
+ require 'picturelife/base'
10
+ require 'picturelife/stub'
11
+ require 'picturelife/oauth'
12
+ require 'picturelife/api'
13
+ require 'picturelife/ruler'
14
+
15
+ Excon.defaults[:ssl_verify_peer] = false
16
+
17
+ include Picturelife::Util
18
+ include Picturelife::Ruler
19
+
20
+ module Picturelife
21
+ VERSION = "0.0.1"
22
+ end
@@ -0,0 +1,37 @@
1
+ module Picturelife
2
+
3
+ API_ENDPOINT = "https://api.picturelife.com/"
4
+
5
+ class Api
6
+ class << self
7
+
8
+ def call(uri, args = nil)
9
+ needs_token!
10
+
11
+ api_get(build_uri(uri, args))
12
+ end
13
+
14
+ private
15
+
16
+ def build_uri(uri, args = nil)
17
+ [API_ENDPOINT, uri, build_parameters(args)].join
18
+ end
19
+
20
+ def build_parameters(args = nil)
21
+ args = {} if args.nil?
22
+
23
+ args.merge!(access_token: Picturelife.access_token)
24
+
25
+ return ['?', URI.encode_www_form(args)].join
26
+ end
27
+
28
+ def api_get(uri)
29
+ uri = URI(URI.encode(uri))
30
+ response = Net::HTTP.get(uri)
31
+ response = JSON.parse(response)
32
+ raise ApiError.new(response["status"], response["error"], response) if (response["status"] != 20000 && response["status"] != 200)
33
+ response
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,35 @@
1
+ module Picturelife
2
+ class << self
3
+ attr_accessor :client_id
4
+ attr_accessor :client_secret
5
+ attr_accessor :access_token
6
+ attr_accessor :refresh_token
7
+ attr_reader :redirect_uri
8
+
9
+ def redirect_uri=(uri)
10
+ @redirect_uri = escape_uri(uri)
11
+ end
12
+
13
+ def configured?
14
+ @client_id &&
15
+ @client_secret &&
16
+ @redirect_uri
17
+ end
18
+
19
+ def authenticated?
20
+ !! @access_token
21
+ end
22
+
23
+ def reset_configuration!
24
+ @client_id = nil
25
+ @client_secret = nil
26
+ @redirect_uri = nil
27
+ reset_authentication!
28
+ end
29
+
30
+ def reset_authentication!
31
+ @access_token = nil
32
+ @refresh_token = nil
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,51 @@
1
+ module Picturelife
2
+
3
+ class NotConfiguredError < StandardError
4
+ def initialize
5
+ super <<-MSG.gsub(/^ {6}/, '')
6
+
7
+ You need to set up your API Credentials like this:
8
+ Picturelife.client_id = ENV['CLIENT_ID']
9
+ Picturelife.client_secret = ENV['CLIENT_SECRET']
10
+ Picturelife.redirect_uri = 'http://localhost:3000/oauth'
11
+ MSG
12
+ end
13
+ end
14
+
15
+ class NotAuthenticatedError < StandardError
16
+ def initialize
17
+ super <<-MSG.gsub(/^ {6}/, '')
18
+
19
+ Send your User to `Picturelife.authorization_uri` and catch
20
+ the access token from your `Picturelife.redirect_uri` like so:
21
+ Picturelife.access_token(params[:code])
22
+ MSG
23
+ end
24
+ end
25
+
26
+ class ApiError < StandardError
27
+ attr_reader :code
28
+ def initialize(code = nil, msg = nil, response = nil)
29
+ puts @code = code
30
+ puts response.to_s
31
+ super msg
32
+ end
33
+ end
34
+
35
+ class RulerError < ApiError; end
36
+ class OAuthError < ApiError; end
37
+
38
+ module Util
39
+
40
+ def needs_configuration!
41
+ raise NotConfiguredError unless Picturelife.configured?
42
+ end
43
+
44
+ def needs_token!
45
+ needs_configuration!
46
+ raise NotAuthenticatedError unless Picturelife.authenticated?
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,105 @@
1
+ module Picturelife
2
+
3
+ OAUTH_ENDPOINT = "https://api.picturelife.com/oauth/"
4
+
5
+ class << self
6
+ def authorization_uri
7
+ needs_configuration!
8
+
9
+ [
10
+ OAUTH_ENDPOINT,
11
+ "authorize?",
12
+ "client_id=#{@client_id}",
13
+ "&client_secret=#{@client_secret}",
14
+ "&redirect_uri=#{@redirect_uri}",
15
+ "&response_type=code"
16
+ ].join
17
+ end
18
+
19
+ def access_token_from_code=(code)
20
+ needs_configuration!
21
+
22
+ uri = [
23
+ OAUTH_ENDPOINT,
24
+ "access_token?",
25
+ "client_id=#{@client_id}",
26
+ "&client_secret=#{@client_secret}",
27
+ "&code=#{code}",
28
+ "&client_uuid=#{client_uuid}"
29
+ ].join
30
+
31
+ res = api_oauth_get(uri)
32
+
33
+ if res['status'] != 200
34
+ raise OAuthError.new(res['status'], res['error'], res)
35
+ else
36
+ @refresh_token = res['refresh_token']
37
+ @user_id = res['user_id']
38
+ @token_expires = Time.at(res['expires'])
39
+ @access_token = res['access_token']
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def api_oauth_get(uri)
46
+ uri = URI(URI.encode(uri))
47
+ response = Net::HTTP.get(uri)
48
+ response = JSON.parse(hashrocket_to_json(response))
49
+ raise OAuthError.new(response["error"]) if response["status"] != 200
50
+ response
51
+ end
52
+ end
53
+
54
+
55
+ class OAuth
56
+
57
+ attr_accessor :verb, :uri, :body
58
+
59
+ def initialize(verb, uri, body)
60
+ @verb = verb
61
+ @uri = uri
62
+ @body = body
63
+ end
64
+
65
+ def authorization_header
66
+ header = "OAuth "
67
+ oauth_params.each do |k, v|
68
+ header += "#{k}=\"#{v}\", "
69
+ end
70
+ header.slice(0..-3) # chop off last ", "
71
+ end
72
+
73
+ private
74
+
75
+ def oauth_params
76
+ {
77
+ 'oauth_timestamp' => Time.now.getutc.to_i.to_s,
78
+ 'oauth_token' => escape_uri(Picturelife.access_token),
79
+ 'oauth_consumer_key' => Picturelife.client_id,
80
+ 'oauth_signature_method' => 'HMAC-SHA1',
81
+ 'oauth_signature' => signature,
82
+ 'oauth_nonce' => nonce,
83
+ 'oauth_version' => '1.0'
84
+ }
85
+ end
86
+
87
+ def signature
88
+ body = @body.dup
89
+ body['access_token'] = Picturelife.access_token
90
+ body = body.map { |k, v| [k.to_s, v.to_s] }
91
+ body = body.sort.map { |k, v| escape_uri("#{k}=#{v}") }.join('%26')
92
+
93
+ base = [verb, escape_uri(uri), body].join('&')
94
+ key = [Picturelife.client_secret, Picturelife.access_token].join('&')
95
+ escape_uri(sign(key, base))
96
+ end
97
+
98
+ def sign(key, base)
99
+ digest = OpenSSL::Digest::Digest.new('sha1')
100
+ hmac = OpenSSL::HMAC.digest(digest, key, base)
101
+ Base64.encode64(hmac).chomp.gsub(/\n/, '')
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,103 @@
1
+ module Picturelife
2
+
3
+ RULER_ENDPOINT = "https://services.picturelife.com/ruler/"
4
+
5
+ module Ruler
6
+
7
+ def upload(file_path, options = {}, processing_needs = [])
8
+ needs_token!
9
+
10
+ @file_path = file_path
11
+ @signature = get_signature(file_path)
12
+ @filename = get_filename(file_path)
13
+ @force = !! options[:force]
14
+ @options = options
15
+ @processing_needs = processing_needs
16
+
17
+ media_exists || perform_upload
18
+
19
+ rescue RulerError => e
20
+ (e.code == 519256) ? retry : raise(e)
21
+ rescue Timeout::Error, Errno::ECONNRESET
22
+ retry
23
+ end
24
+
25
+ def head(file_path)
26
+ @file_path = file_path
27
+ @signature = get_signature(file_path)
28
+ @filename = get_filename(file_path)
29
+
30
+ ruler('HEAD')
31
+ end
32
+
33
+ private
34
+
35
+ def media_exists
36
+ medias = Picturelife::Medias.check_signatures(signatures: @signature)['signatures'] || {}
37
+ return false if medias.empty?
38
+ return Picturelife::Medias.show(media_id: medias[@signature]['media_id']) unless @force
39
+ return false
40
+ end
41
+
42
+ def perform_upload
43
+ header = { 'Content-Range' => "bytes #{filesize_uploaded}-#{filesize_total}/#{filesize_total}" }
44
+ location = ruler(:put, file_partial, header)['location']
45
+ create_media_from_ruler(location)
46
+ end
47
+
48
+ def file_partial
49
+ IO.binread(@file_path, nil, filesize_uploaded)
50
+ end
51
+
52
+ def filesize_total
53
+ File.size(@file_path)
54
+ end
55
+
56
+ def filesize_uploaded
57
+ @filesize_uploaded ||= lambda do
58
+ uploaded = ruler(:head)['X-Ruler-Size']
59
+ uploaded = uploaded.first if uploaded
60
+ uploaded.to_i
61
+ end.call
62
+ end
63
+
64
+ def create_media_from_ruler(location)
65
+ Picturelife::Media.create({
66
+ url: location,
67
+ signature: @signature,
68
+ force: (!!@force).to_s,
69
+ local_path: @file_path,
70
+ processing_needs: @processing_needs.map(&:to_s).join(',')
71
+ }.merge(@options))
72
+ end
73
+
74
+ def auth
75
+ {
76
+ 'Authorization' => "Bearer #{Picturelife.access_token}",
77
+ 'User-Agent' => "rubygem/#{VERSION}"
78
+ }
79
+ end
80
+
81
+ def ruler(verb, data = nil, headers = {})
82
+ http = Excon.new(RULER_ENDPOINT + @filename)
83
+ res = http.request(
84
+ method: verb,
85
+ query: { signature: @signature },
86
+ headers: auth.merge(headers),
87
+ body: data,
88
+ idempotent: true
89
+ )
90
+
91
+ body = res.body
92
+ body = (body && body.length >= 2) ? JSON.parse(body) : {}
93
+ body.merge!(res.headers)
94
+
95
+ unless body['X-Ruler-Error-Code'].to_s.empty?
96
+ raise RulerError.new(body['X-Ruler-Error-Code'], body['X-Ruler-Error'], body)
97
+ else
98
+ body
99
+ end
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,22 @@
1
+ module Picturelife
2
+
3
+ def self.const_missing(name)
4
+ Stub.new(underscore(name.to_s))
5
+ end
6
+
7
+ class Stub
8
+
9
+ attr_reader :module_name
10
+
11
+ def initialize(module_name)
12
+ @module_name = module_name
13
+ end
14
+
15
+ def method_missing(name, args = nil)
16
+ method = [module_name, name].join('/')
17
+ Api.call(method, args)
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,39 @@
1
+ module Picturelife
2
+ module Util
3
+
4
+ def escape_uri(text)
5
+ return '' if text.nil?
6
+ CGI::escape(text)
7
+ end
8
+
9
+ def underscore(camelcase)
10
+ camelcase.gsub(/(.)([A-Z])/,'\1_\2').downcase
11
+ end
12
+
13
+ def api_get(uri)
14
+ uri = URI(URI.encode(uri))
15
+ JSON.parse(Net::HTTP.get(uri))
16
+ end
17
+
18
+ def hashrocket_to_json(string)
19
+ string.gsub('=>', ':')
20
+ end
21
+
22
+ def client_uuid
23
+ @client_uuid ||= rand(10**10).to_s
24
+ end
25
+
26
+ def nonce
27
+ rand(10**10).to_s
28
+ end
29
+
30
+ def get_signature(file_path)
31
+ Digest::SHA256.hexdigest File.read(file_path)
32
+ end
33
+
34
+ def get_filename(file_path)
35
+ [get_signature(file_path), '_', client_uuid, File.extname(file_path)].join
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'picturelife'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'picturelife'
8
+ spec.version = Picturelife::VERSION
9
+ spec.authors = ['Albert Zak']
10
+ spec.email = ['me@albertzak.com']
11
+ spec.summary = %q{Picturelife API. OAuth. Resumable Uploads.}
12
+ spec.description = 'A gem to access the Picturelife API.'
13
+ spec.homepage = 'https://github.com/albertzak/picturelife'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'json'
22
+ spec.add_dependency 'excon'
23
+ spec.add_dependency 'oauth'
24
+
25
+ spec.add_development_dependency 'bundler'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'rspec'
28
+ spec.add_development_dependency 'rspec-nc'
29
+ spec.add_development_dependency 'guard'
30
+ spec.add_development_dependency 'guard-rspec'
31
+ spec.add_development_dependency 'pry'
32
+ spec.add_development_dependency 'pry-remote'
33
+ spec.add_development_dependency 'pry-nav'
34
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ describe Picturelife do
4
+ before(:each) do
5
+ Picturelife.client_id = 'aaa'
6
+ Picturelife.client_secret = 'bbb'
7
+ Picturelife.redirect_uri = 'ccc'
8
+
9
+ Picturelife.stub(:authenticated?).and_return(true)
10
+
11
+ Net::HTTP.stub(:get).and_return('{"status":20000}')
12
+
13
+ File.stub(:read).and_return('image')
14
+ File.stub(:extname).and_return('jpg')
15
+ end
16
+
17
+ it 'accepts api keys' do
18
+ expect { Picturelife.client_id = 'test' }.not_to raise_error
19
+ expect { Picturelife.client_secret = 'test' }.not_to raise_error
20
+ expect { Picturelife.redirect_uri = 'test' }.not_to raise_error
21
+ end
22
+
23
+ it 'raises error if not configured' do
24
+ Picturelife.reset_configuration!
25
+ expect { Picturelife.authorization_uri }. to raise_error(Picturelife::NotConfiguredError)
26
+ end
27
+
28
+ it 'raises error if not authenticated' do
29
+ Picturelife.stub(:authenticated?).and_return(false)
30
+ expect { Picturelife::Api.call('/') }. to raise_error(Picturelife::NotAuthenticatedError)
31
+ end
32
+
33
+ it 'escapes redirect uri' do
34
+ Picturelife.redirect_uri = 'http://localhost:4567/?code=a'
35
+ expect(Picturelife.redirect_uri).to eq 'http%3A%2F%2Flocalhost%3A4567%2F%3Fcode%3Da'
36
+ end
37
+
38
+ it 'builds valid authorization url' do
39
+ expect(Picturelife.authorization_uri).to include 'aaa'
40
+ expect(Picturelife.authorization_uri).to include 'bbb'
41
+ expect(Picturelife.authorization_uri).to include 'ccc'
42
+ end
43
+
44
+ it 'gets and sets access token' do
45
+ Net::HTTP.stub(:get).and_return('{"access_token":"token","status":200}')
46
+
47
+ Picturelife.access_token_from_code = 'code'
48
+ expect(Picturelife.access_token).to eq 'token'
49
+ end
50
+
51
+ it 'generated client uuid' do
52
+ expect(Picturelife.send(:client_uuid)).to be_kind_of(String)
53
+ end
54
+
55
+ it 'caches uuid' do
56
+ uuid = Proc.new { Picturelife.send(:client_uuid) }
57
+ expect(uuid).to eq uuid
58
+ end
59
+
60
+ it 'queries API' do
61
+ expect(Net::HTTP).to receive(:get) do |uri|
62
+ expect(uri.scheme).to eq 'https'
63
+ expect(uri.query).to include 'client_id=aaa'
64
+ expect(uri.query).to include 'client_secret=bbb'
65
+ expect(uri.query).to include 'code=code'
66
+ expect(uri.to_s).to include Picturelife::OAUTH_ENDPOINT
67
+ end.and_return('{"access_token"=>"ddd","status"=>200}')
68
+
69
+ Picturelife.access_token_from_code = 'code'
70
+ end
71
+
72
+ it 'API returns hashrocket that is converted to json' do
73
+ parsable = hashrocket_to_json('{"access_token"=>"ddd"}')
74
+ expect { JSON.parse(parsable) }.not_to raise_error
75
+ end
76
+
77
+ it 'stubs missing constant names' do
78
+ expect { Picturelife::SmartFilters }.not_to raise_error
79
+ end
80
+
81
+ it 'stubs missing methods on missing constants' do
82
+ expect { Picturelife::SmartFilters.index }.not_to raise_error
83
+ end
84
+
85
+ it 'stubs call correct api method' do
86
+ expect(Picturelife::Api).to receive(:call).with('smart_filters/index', nil)
87
+ Picturelife::SmartFilters.index
88
+ end
89
+
90
+ it 'stubs call correct api method with argument' do
91
+ expect(Picturelife::Api).to receive(:call).with('smart_filters/index', include_system: true)
92
+ Picturelife::SmartFilters.index(include_system: true)
93
+ end
94
+
95
+ it 'stubs call correct api method with multiple args' do
96
+ expect(Picturelife::Api).to receive(:call).with('smart_filters/index', { include_system: true, limit: 10 })
97
+ Picturelife::SmartFilters.index({ include_system: true, limit: 10 })
98
+ end
99
+
100
+ it 'builds url parameters without args' do
101
+ url = Picturelife::Api.send(:build_uri, 'smart_filters/index')
102
+ expect(url).to include('https://api.picturelife.com/smart_filters/index')
103
+ end
104
+
105
+ it 'builds url parameters from args' do
106
+ url = Picturelife::Api.send(:build_uri, 'smart_filters/index', {limit: 10})
107
+ expect(url).to include('https://api.picturelife.com/smart_filters/index?limit=10')
108
+ end
109
+
110
+ it 'builds url parameters from multiple args' do
111
+ url = Picturelife::Api.send(:build_uri, 'smart_filters/index', {limit: 10, include_system: true})
112
+ expect(url).to include('https://api.picturelife.com/smart_filters/index?limit=10&include_system=true')
113
+ end
114
+
115
+ it 'adds access token to url parameters' do
116
+ Picturelife.stub(:access_token).and_return('123')
117
+ url = Picturelife::Api.send(:build_uri, 'smart_filters/index', {limit: 10, include_system: true})
118
+ expect(url).to eq('https://api.picturelife.com/smart_filters/index?limit=10&include_system=true&access_token=123')
119
+ end
120
+
121
+ it 'needs authentication for calls to api' do
122
+ Picturelife.stub(:authenticated?).and_return(false)
123
+ expect { Picturelife::Api.call('index') }.to raise_error(Picturelife::NotAuthenticatedError)
124
+ end
125
+
126
+ it 'needs authentication for calls to ruler' do
127
+ Picturelife.stub(:authenticated?).and_return(false)
128
+ expect { Picturelife::Ruler.upload(StringIO.new) }.to raise_error(Picturelife::NotAuthenticatedError)
129
+ end
130
+
131
+ it 'needs authentication for calls to ruler' do
132
+ Picturelife::Ruler.should_receive(:media_exists).and_return('media_id')
133
+ expect(Picturelife::Ruler.upload(StringIO.new)).to eq('media_id')
134
+ end
135
+
136
+
137
+ end
@@ -0,0 +1,2 @@
1
+ require 'pry'
2
+ require 'picturelife'
metadata ADDED
@@ -0,0 +1,231 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: picturelife
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Albert Zak
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: excon
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: oauth
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-nc
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: guard-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: pry
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: pry-remote
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: pry-nav
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description: A gem to access the Picturelife API.
182
+ email:
183
+ - me@albertzak.com
184
+ executables: []
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - .gitignore
189
+ - Gemfile
190
+ - Guardfile
191
+ - LICENSE.txt
192
+ - README.md
193
+ - Rakefile
194
+ - lib/picturelife.rb
195
+ - lib/picturelife/api.rb
196
+ - lib/picturelife/base.rb
197
+ - lib/picturelife/error.rb
198
+ - lib/picturelife/oauth.rb
199
+ - lib/picturelife/ruler.rb
200
+ - lib/picturelife/stub.rb
201
+ - lib/picturelife/util.rb
202
+ - picturelife.gemspec
203
+ - spec/picturelife_spec.rb
204
+ - spec/spec_helper.rb
205
+ homepage: https://github.com/albertzak/picturelife
206
+ licenses:
207
+ - MIT
208
+ metadata: {}
209
+ post_install_message:
210
+ rdoc_options: []
211
+ require_paths:
212
+ - lib
213
+ required_ruby_version: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - '>='
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ required_rubygems_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - '>='
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ requirements: []
224
+ rubyforge_project:
225
+ rubygems_version: 2.0.3
226
+ signing_key:
227
+ specification_version: 4
228
+ summary: Picturelife API. OAuth. Resumable Uploads.
229
+ test_files:
230
+ - spec/picturelife_spec.rb
231
+ - spec/spec_helper.rb