├── .document ├── .gitignore ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── VERSION ├── cloudapp_api.gemspec ├── lib ├── cloudapp │ ├── account.rb │ ├── base.rb │ ├── client.rb │ ├── core_ext.rb │ ├── drop.rb │ ├── gift_card.rb │ ├── httparty.rb │ ├── multipart.rb │ └── response_error.rb └── cloudapp_api.rb └── spec ├── cloudapp_account_spec.rb ├── cloudapp_api_spec.rb ├── cloudapp_client_spec.rb ├── cloudapp_drop_spec.rb ├── cloudapp_gift_card_spec.rb ├── cloudapp_item_spec.rb ├── cloudapp_response_error_spec.rb ├── fakeweb_helper.rb ├── spec_helper.rb └── stubs ├── account ├── create ├── show ├── stats └── update ├── drop ├── create ├── delete ├── index ├── new ├── new-private ├── show ├── show-private └── update ├── error ├── 400 ├── 401 ├── 404-find ├── 404-update ├── 422-bookmark └── 422-bookmarks └── gift_card ├── redeem └── show /.document: -------------------------------------------------------------------------------- 1 | README.rdoc 2 | lib/**/*.rb 3 | bin/* 4 | features/**/*.feature 5 | LICENSE 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## MAC OS 2 | .DS_Store 3 | 4 | ## TEXTMATE 5 | *.tmproj 6 | tmtags 7 | 8 | ## EMACS 9 | *~ 10 | \#* 11 | .\#* 12 | 13 | ## VIM 14 | *.swp 15 | 16 | ## PROJECT::GENERAL 17 | .autotest 18 | .ruby-* 19 | .yardoc 20 | coverage 21 | doc 22 | rdoc 23 | pkg 24 | 25 | ## PROJECT::SPECIFIC 26 | test/test_config.yml 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | rvm: 4 | - 2.0.0 5 | - 1.9.3 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Add dependencies required to use your gem here. 4 | gem "httparty", "~> 0.13.5" 5 | gem "mime-types" 6 | 7 | # Add dependencies to develop your gem here. 8 | # Include everything needed to run rake, tests, features, etc. 9 | group :development do 10 | gem "rspec" 11 | gem 'coveralls', :require => false 12 | gem "fakeweb" 13 | gem "yard" 14 | gem "bluecloth" 15 | gem "cucumber" 16 | end 17 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | bluecloth (2.2.0) 5 | builder (3.2.2) 6 | colorize (0.5.8) 7 | coveralls (0.6.7) 8 | colorize 9 | multi_json (~> 1.3) 10 | rest-client 11 | simplecov (>= 0.7) 12 | thor 13 | cucumber (1.3.2) 14 | builder (>= 2.1.2) 15 | diff-lcs (>= 1.1.3) 16 | gherkin (~> 2.12.0) 17 | multi_json (~> 1.3) 18 | diff-lcs (1.2.4) 19 | fakeweb (1.3.0) 20 | gherkin (2.12.0) 21 | multi_json (~> 1.3) 22 | httparty (0.13.5) 23 | json (~> 1.8) 24 | multi_xml (>= 0.5.2) 25 | json (1.8.2) 26 | mime-types (1.23) 27 | multi_json (1.7.7) 28 | multi_xml (0.5.5) 29 | rest-client (1.6.7) 30 | mime-types (>= 1.16) 31 | rspec (2.13.0) 32 | rspec-core (~> 2.13.0) 33 | rspec-expectations (~> 2.13.0) 34 | rspec-mocks (~> 2.13.0) 35 | rspec-core (2.13.1) 36 | rspec-expectations (2.13.0) 37 | diff-lcs (>= 1.1.3, < 2.0) 38 | rspec-mocks (2.13.1) 39 | simplecov (0.7.1) 40 | multi_json (~> 1.0) 41 | simplecov-html (~> 0.7.1) 42 | simplecov-html (0.7.1) 43 | thor (0.18.1) 44 | yard (0.8.6.1) 45 | 46 | PLATFORMS 47 | ruby 48 | 49 | DEPENDENCIES 50 | bluecloth 51 | coveralls 52 | cucumber 53 | fakeweb 54 | httparty (~> 0.13.5) 55 | mime-types 56 | rspec 57 | yard 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Aaron Russell 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CloudApp API 2 | 3 | [![Build Status](https://travis-ci.org/aaronrussell/cloudapp_api.png)](https://travis-ci.org/aaronrussell/cloudapp_api) 4 | [![Code Climate](https://codeclimate.com/github/aaronrussell/cloudapp_api.png)](https://codeclimate.com/github/aaronrussell/cloudapp_api) 5 | [![Coverage Status](https://coveralls.io/repos/aaronrussell/cloudapp_api/badge.png?branch=master)](https://coveralls.io/r/aaronrussell/cloudapp_api) 6 | 7 | A simple Ruby wrapper for the [CloudApp API](http://support.getcloudapp.com/faqs/developers/api). Uses [HTTParty](http://github.com/jnunemaker/httparty) with a simple ActiveResource-like interface. 8 | 9 | Two interfaces are provided for interacting with the CloudApp API. The first is a ActiveResource-like interface, directly calling methods on the Drop and Account classes. The second option is to interact through a Client interface. 10 | 11 | * [Familiarise yourself with the documentation](http://rubydoc.info/github/aaronrussell/cloudapp_api/) 12 | 13 | ## Installation 14 | 15 | To install as a Gem: 16 | 17 | sudo gem install cloudapp_api 18 | 19 | **(Version 0.5.0 ends compaitibility with Ruby 1.8.7. If you need 1.8.7 support, you can still use version 0.4.0 of this gem.)** 20 | 21 | ## Authentication 22 | 23 | Authentication is necessary for most actions, the only exceptions being when creating a new Account or querying a specific Drop. 24 | 25 | CloudApp.authenticate "email@address.com", "password" 26 | 27 | ## Drops 28 | 29 | * Documentation - {CloudApp::Drop} 30 | 31 | --- 32 | 33 | ### Usage via the Drop class 34 | 35 | # Find a single drop by it's slug 36 | @drop = CloudApp::Drop.find "2wr4" 37 | 38 | # Get a list of all drops 39 | @drops = CloudApp::Drop.all 40 | 41 | # Create a new bookmark 42 | @drop = CloudApp::Drop.create :bookmark, :name => "CloudApp", :redirect_url => "http://getcloudapp.com" 43 | 44 | # Create multiple bookmarks 45 | bookmarks = [ 46 | { :name => "Authur Dent", :redirect_url => "http://en.wikipedia.org/wiki/Arthur_Dent" }, 47 | { :name => "Zaphod Beeblebrox", :redirect_url => "http://en.wikipedia.org/wiki/Zaphod_Beeblebrox" } 48 | ] 49 | @drops = CloudApp::Drop.create :bookmarks, bookmarks 50 | 51 | # Upload a file 52 | @drop = CloudApp::Drop.create :upload, :file => "/path/to/image.png" 53 | @drop = CloudApp::Drop.create :upload, :file => "/path/to/image.png", :private => true 54 | 55 | # Rename a file 56 | CloudApp::Drop.update "http://my.cl.ly/items/1912565", :name => "Big Screenshot" 57 | 58 | # Set a drop's privacy 59 | CloudApp::Drop.update "http://my.cl.ly/items/1912565", :private => true 60 | 61 | # Delete a drop 62 | CloudApp::Drop.delete "http://my.cl.ly/items/1912565" 63 | 64 | # Recover a deleted drop 65 | CloudApp::Drop.recover "http://my.cl.ly/items/1912565" 66 | 67 | ### Usage via the class instance 68 | 69 | # Rename a file 70 | @drop.update :name => "Big Screenshot" 71 | 72 | # Set the drop's privacy 73 | @drop.update :private => true 74 | 75 | # Delete a drop 76 | @drop.delete 77 | 78 | # Recover a deleted drop 79 | @drop.recover 80 | 81 | ## Drops via a Client instance 82 | 83 | * Documentation - {CloudApp::Client} 84 | 85 | --- 86 | 87 | # Find a single drop by it's slug 88 | drop = @client.drop "2wr4" 89 | 90 | # Get a list of all drops 91 | drops = @client.all 92 | 93 | # Create a new bookmark 94 | drop = @client.bookmark "http://getcloudapp.com", "CloudApp" 95 | 96 | # Create multiple new bookmarks 97 | bookmarks = [ 98 | { :name => "Authur Dent", :redirect_url => "http://en.wikipedia.org/wiki/Arthur_Dent" }, 99 | { :name => "Zaphod Beeblebrox", :redirect_url => "http://en.wikipedia.org/wiki/Zaphod_Beeblebrox" } 100 | ] 101 | drops = @client.bookmark bookmarks 102 | 103 | # Upload a file 104 | drop = @client.upload "/path/to/image.png" 105 | drop = @client.upload "/path/to/image.png", :private => true 106 | 107 | # Rename a file 108 | @client.rename "2wr4", "Big Screenshot" 109 | 110 | # Set a drop's privacy 111 | @client.privacy "2wr4", true 112 | 113 | # Delete an drop 114 | @client.delete "2wr4" 115 | 116 | # Recover a deleted drop 117 | @client.recover "2wr4" 118 | 119 | ## Account examples 120 | 121 | * Documentation - {CloudApp::Account} 122 | 123 | --- 124 | 125 | # Create a CloudApp account 126 | @account = CloudApp::Account.create :email => "arthur@dent.com", :password => "towel" 127 | 128 | # View account details 129 | @account = CloudApp::Account.find 130 | 131 | # Forgot password 132 | CloudApp::Account.reset :email => "arthur@dent.com" 133 | 134 | # Change default security 135 | @account.update :private_items => false 136 | 137 | # Change email 138 | @account.update :email => "ford@prefect.com", :current_password => "towel" 139 | 140 | # Change password 141 | @account.update :password => "happy frood", :current_password => "towel" 142 | 143 | # Set custom domain 144 | @account.update :domain => "dent.com", :domain_home_page => "http://hhgproject.org" 145 | 146 | # View account stats 147 | @account.stats 148 | 149 | ## Gift cards 150 | 151 | * Documentation - {CloudApp::GiftCard} 152 | 153 | --- 154 | 155 | # View gift card details 156 | @gift = CloudApp::GiftCard.find "ABC123" 157 | 158 | # Apply the gift card 159 | CloudApp::GiftCard.redeem "ABC123" 160 | # or 161 | @gift.redeem 162 | 163 | ## What's next on the to-do list? 164 | 165 | * Refactor the Client interface so can be used with all of the API 166 | 167 | ## Note on Patches/Pull Requests 168 | 169 | * Fork the project. 170 | * Make your feature addition or bug fix. 171 | * Add tests for it. This is important so I don't break it in a future version unintentionally. 172 | * Commit, do not mess with rakefile, version, or history. 173 | (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) 174 | * Send me a pull request. Bonus points for topic branches. 175 | 176 | ## Author & Contributors 177 | 178 | * [Aaron Russell](http://www.aaronrussell.co.uk) 179 | * [Christian Nicolai](https://github.com/cmur2) 180 | 181 | ## Copyright 182 | 183 | Copyright (c) 2010 Aaron Russell. See LICENSE for details. 184 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | begin 4 | Bundler.setup(:default, :development) 5 | rescue Bundler::BundlerError => e 6 | $stderr.puts e.message 7 | $stderr.puts "Run `bundle install` to install missing gems" 8 | exit e.status_code 9 | end 10 | require 'rake' 11 | 12 | Bundler::GemHelper.install_tasks 13 | 14 | require 'rspec/core' 15 | require 'rspec/core/rake_task' 16 | RSpec::Core::RakeTask.new(:spec) do |spec| 17 | spec.pattern = FileList['spec/**/*_spec.rb'] 18 | spec.verbose 19 | end 20 | 21 | require 'cucumber/rake/task' 22 | Cucumber::Rake::Task.new(:features) 23 | 24 | task :default => :spec 25 | 26 | require 'yard' 27 | YARD::Rake::YardocTask.new 28 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.5.0 -------------------------------------------------------------------------------- /cloudapp_api.gemspec: -------------------------------------------------------------------------------- 1 | # Generated by jeweler 2 | # DO NOT EDIT THIS FILE DIRECTLY 3 | # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' 4 | # -*- encoding: utf-8 -*- 5 | # stub: cloudapp_api 0.5.0 ruby lib 6 | 7 | Gem::Specification.new do |s| 8 | s.name = "cloudapp_api" 9 | s.version = "0.5.0" 10 | 11 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 12 | s.require_paths = ["lib"] 13 | s.authors = ["Aaron Russell"] 14 | s.date = "2015-06-01" 15 | s.description = "A simple Ruby wrapper for the CloudApp API. Uses HTTParty with a simple ActiveResource-like interface." 16 | s.email = "aaron@gc4.co.uk" 17 | s.extra_rdoc_files = [ 18 | "LICENSE", 19 | "README.md" 20 | ] 21 | s.files = [ 22 | ".document", 23 | ".travis.yml", 24 | "Gemfile", 25 | "Gemfile.lock", 26 | "LICENSE", 27 | "README.md", 28 | "Rakefile", 29 | "VERSION", 30 | "cloudapp_api.gemspec", 31 | "lib/cloudapp/account.rb", 32 | "lib/cloudapp/base.rb", 33 | "lib/cloudapp/client.rb", 34 | "lib/cloudapp/core_ext.rb", 35 | "lib/cloudapp/drop.rb", 36 | "lib/cloudapp/gift_card.rb", 37 | "lib/cloudapp/httparty.rb", 38 | "lib/cloudapp/multipart.rb", 39 | "lib/cloudapp/response_error.rb", 40 | "lib/cloudapp_api.rb", 41 | "spec/cloudapp_account_spec.rb", 42 | "spec/cloudapp_api_spec.rb", 43 | "spec/cloudapp_client_spec.rb", 44 | "spec/cloudapp_drop_spec.rb", 45 | "spec/cloudapp_gift_card_spec.rb", 46 | "spec/cloudapp_item_spec.rb", 47 | "spec/cloudapp_response_error_spec.rb", 48 | "spec/fakeweb_helper.rb", 49 | "spec/spec_helper.rb", 50 | "spec/stubs/account/create", 51 | "spec/stubs/account/show", 52 | "spec/stubs/account/stats", 53 | "spec/stubs/account/update", 54 | "spec/stubs/drop/create", 55 | "spec/stubs/drop/delete", 56 | "spec/stubs/drop/index", 57 | "spec/stubs/drop/new", 58 | "spec/stubs/drop/new-private", 59 | "spec/stubs/drop/show", 60 | "spec/stubs/drop/show-private", 61 | "spec/stubs/drop/update", 62 | "spec/stubs/error/400", 63 | "spec/stubs/error/401", 64 | "spec/stubs/error/404-find", 65 | "spec/stubs/error/404-update", 66 | "spec/stubs/error/422-bookmark", 67 | "spec/stubs/error/422-bookmarks", 68 | "spec/stubs/gift_card/redeem", 69 | "spec/stubs/gift_card/show" 70 | ] 71 | s.homepage = "http://github.com/aaronrussell/cloudapp_api" 72 | s.rubygems_version = "2.4.4" 73 | s.summary = "A simple Ruby wrapper for the CloudApp API. Uses HTTParty with a simple ActiveResource-like interface." 74 | 75 | s.add_runtime_dependency 'httparty', "~> 0.13.5" 76 | s.add_runtime_dependency 'mime-types', ">= 1.16" 77 | s.add_development_dependency 'rspec', "~> 2.13.0" 78 | s.add_development_dependency 'coveralls', "~> 0.6.7" 79 | s.add_development_dependency 'fakeweb', "~> 1.3.0" 80 | s.add_development_dependency 'yard', "~> 0.8.6.1" 81 | s.add_development_dependency 'bluecloth', "~> 2.2.0" 82 | s.add_development_dependency 'cucumber', "~> 1.3.2" 83 | end 84 | 85 | -------------------------------------------------------------------------------- /lib/cloudapp/account.rb: -------------------------------------------------------------------------------- 1 | module CloudApp 2 | 3 | # An ActiveResource-like interface through which to interract with CloudApp accounts. 4 | # 5 | # @example Create a CloudApp account 6 | # CloudApp::Account.create :email => "arthur@dent.com", :password => "towel" 7 | # 8 | # @example Most other account actions require authentication first 9 | # CloudApp.authenticate "username", "password" 10 | # 11 | # @example Usage via the Account class 12 | # # View account details 13 | # @account = CloudApp::Account.find 14 | # 15 | # # Change default security 16 | # CloudApp::Account.update :private_items => false 17 | # 18 | # # Change email 19 | # CloudApp::Account.update :email => "ford@prefect.com", :current_password => "towel" 20 | # 21 | # # Change password 22 | # CloudApp::Account.update :password => "happy frood", :current_password => "towel" 23 | # 24 | # # Set custom domain 25 | # CloudApp::Account.update :domain => "dent.com", :domain_home_page => "http://hhgproject.org" 26 | # 27 | # # Forgot password 28 | # CloudApp::Account.reset :email => "arthur@dent.com" 29 | # 30 | # # View account stats 31 | # CloudApp::Account.stats 32 | # 33 | # @example Usage via the class instance 34 | # # Change default security 35 | # @account.update :private_items => false 36 | # 37 | # # Change email 38 | # @account.update :email => "ford@prefect.com", :current_password => "towel" 39 | # 40 | # # Change password 41 | # @account.update :password => "happy frood", :current_password => "towel" 42 | # 43 | # # Set custom domain 44 | # @account.update :domain => "dent.com", :domain_home_page => "http://hhgproject.org" 45 | # 46 | # # Forgot password 47 | # @account.reset 48 | # 49 | # # View account stats 50 | # @account.stats 51 | # 52 | class Account < Base 53 | 54 | # Get the basic details of the authenticated account. 55 | # 56 | # Requires authentication. 57 | # 58 | # @return [CloudApp::Account] 59 | def self.find 60 | res = get "/account", :digest_auth => @@auth 61 | res.ok? ? Account.new(res) : bad_response(res) 62 | end 63 | 64 | # Create a CloudApp account. 65 | # 66 | # @param [Hash] opts options parameters 67 | # @option opts [String] :email Account email address 68 | # @option opts [String] :password Account password 69 | # @option opts [Boolean] :accept_tos Accept CloudApp terms of service 70 | # @return [CloudApp::Account] 71 | def self.create(opts = {}) 72 | res = post "/register", :body => {:user => opts} 73 | res.ok? ? Account.new(res) : bad_response(res) 74 | end 75 | 76 | # Modify the authenticated accounts details. Can change the default security of newly 77 | # created drops, the accounts email address, password, and custom domain details. 78 | # 79 | # Note that when changing email address or password, the current password is required. 80 | # Also note that to change custom domains requires an account with a Pro subscription. 81 | # 82 | # Requires authentication 83 | # 84 | # @param [Hash] opts options parameters 85 | # @option opts [Boolean] :private_items Change default security of new drops 86 | # @option opts [String] :email Change email address 87 | # @option opts [String] :password Change password 88 | # @option opts [String] :current_password Current account password 89 | # @option opts [String] :domain Set custom domain 90 | # @option opts [String] :domain_home_page URL to redirect visitors to custom domain's root 91 | # @return [CloudApp::Account] 92 | def self.update(opts = {}) 93 | res = put "/account", {:body => {:user => opts}, :digest_auth => @@auth} 94 | res.ok? ? Account.new(res) : bad_response(res) 95 | end 96 | 97 | # Dispatch an email containing a link to reset the account's password. 98 | # 99 | # @param [Hash] opts options parameters 100 | # @option opts [String] :email Account email address 101 | # @return [Boolean] 102 | def self.reset(opts = {}) 103 | res = post "/reset", :body => {:user => opts} 104 | res.ok? ? true : bad_response(res) 105 | end 106 | 107 | # Get the total number of drops created and total views for all drops. 108 | # 109 | # Requires authentication. 110 | # 111 | # @return [Hash] 112 | def self.stats 113 | res = get "/account/stats", :digest_auth => @@auth 114 | res.ok? ? res.symbolize_keys! : bad_response(res) 115 | end 116 | 117 | attr_reader :id, :email, :domain, :domain_home_page, :private_items, 118 | :subscribed, :subscription_expires_at, :alpha, 119 | :created_at, :updated_at, :activated_at 120 | 121 | # Modify the authenticated accounts details. Can change the default security of newly 122 | # created drops, the accounts email address, password, and custom domain details. 123 | # 124 | # Note that when changing email address or password, the current password is required. 125 | # Also note that to change custom domains requires an account with a Pro subscription. 126 | # 127 | # @param [Hash] opts options parameters 128 | # @option opts [Boolean] :private_items Change default security of new drops 129 | # @option opts [String] :email Change email address 130 | # @option opts [String] :password Change password 131 | # @option opts [String] :current_password Current account password 132 | # @option opts [String] :domain Set custom domain 133 | # @option opts [String] :domain_home_page URL to redirect visitors to custom domain's root 134 | # @return [CloudApp::Account] 135 | def update(opts = {}) 136 | self.class.update opts 137 | end 138 | 139 | # Dispatch an email containing a link to reset the account's password. 140 | # 141 | # @param [Hash] opts options parameters 142 | # @option opts [String] :email Account email address 143 | # @return [Boolean] 144 | def reset 145 | self.class.reset :email => self.email 146 | end 147 | 148 | # Get the total number of drops created and total views for all drops. 149 | # 150 | # @return [Hash] 151 | def stats 152 | self.class.stats 153 | end 154 | 155 | end 156 | 157 | end 158 | -------------------------------------------------------------------------------- /lib/cloudapp/base.rb: -------------------------------------------------------------------------------- 1 | require "httparty" 2 | 3 | module CloudApp 4 | 5 | # Globally set request headers 6 | HEADERS = { 7 | "User-Agent" => "Ruby.CloudApp.API", 8 | "Accept" => "application/json", 9 | "Content-Type" => "application/json" 10 | } 11 | 12 | # Base class for setting HTTParty configurations globally 13 | class Base 14 | 15 | include HTTParty 16 | base_uri "my.cl.ly" 17 | headers HEADERS 18 | format :json 19 | 20 | # Define empty auth hash 21 | @@auth = {} 22 | 23 | # Sets the authentication credentials in a class variable. 24 | # 25 | # @param [String] email cl.ly email 26 | # @param [String] password cl.ly password 27 | # @return [Hash] authentication credentials 28 | def self.authenticate(email, password) 29 | @@auth = {:username => email, :password => password} 30 | end 31 | 32 | # Examines a bad response and raises an approriate exception 33 | # 34 | # @param [HTTParty::Response] response 35 | def self.bad_response(response) 36 | if response.class == HTTParty::Response 37 | raise ResponseError, response 38 | end 39 | raise StandardError, "Unknown error" 40 | end 41 | 42 | attr_reader :data 43 | 44 | # Create a new CloudApp::Base object. 45 | # 46 | # Only used internally 47 | # 48 | # @param [Hash] attributes 49 | # @return [CloudApp::Base] 50 | def initialize(attributes = {}) 51 | @data = attributes 52 | load(@data) 53 | end 54 | 55 | private 56 | 57 | # Sets the attributes for object. 58 | # 59 | # @param [Hash] attributes 60 | def load(attributes = {}) 61 | attributes.each do |key, val| 62 | if key =~ /^.*_at$/ and val 63 | # if this is a date/time key and it's not nil, try to parse it first 64 | # as DateTime, then as Date only 65 | begin 66 | dt = DateTime.strptime(val, "%Y-%m-%dT%H:%M:%SZ") 67 | newval = Time.utc(dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec) 68 | rescue ArgumentError => ex 69 | newval = DateTime.strptime(val, "%Y-%m-%d") 70 | end 71 | self.instance_variable_set("@#{key}", newval) 72 | else 73 | self.instance_variable_set("@#{key}", val) 74 | end 75 | end 76 | end 77 | 78 | end 79 | 80 | end 81 | -------------------------------------------------------------------------------- /lib/cloudapp/client.rb: -------------------------------------------------------------------------------- 1 | module CloudApp 2 | 3 | # A client interface through which to interract with the CloudApp API. 4 | # 5 | # @example Creating a client instance and set authentication credentials 6 | # @client = CloudApp::Client.new 7 | # @client.authenticate "username", "password" 8 | # 9 | # @example Creating editing and deleting drops 10 | # # Find a single drop by it's slug 11 | # drop = @client.drop "2wr4" 12 | # 13 | # # Get a list of all drops 14 | # drops = @client.all 15 | # 16 | # # Create a new bookmark 17 | # drop = @client.bookmark "http://getcloudapp.com", "CloudApp" 18 | # 19 | # # Create multiple new bookmarks 20 | # bookmarks = [ 21 | # { :name => "Authur Dent", :redirect_url => "http://en.wikipedia.org/wiki/Arthur_Dent" }, 22 | # { :name => "Zaphod Beeblebrox", :redirect_url => "http://en.wikipedia.org/wiki/Zaphod_Beeblebrox" } 23 | # ] 24 | # drops = @client.bookmark bookmarks 25 | # 26 | # # Upload a file 27 | # drop = @client.upload "/path/to/image.png" 28 | # drop = @client.upload "/path/to/image.png", :private => true 29 | # 30 | # # Rename a file 31 | # @client.rename "2wr4", "Big Screenshot" 32 | # 33 | # # Set a drop's privacy 34 | # @client.privacy "2wr4", true 35 | # 36 | # # Delete an drop 37 | # @client.delete "2wr4" 38 | # 39 | # # Recover a deleted drop 40 | # @client.recover "2wr4" 41 | # 42 | class Client 43 | 44 | # Creates a new CloudApp::Client instance. 45 | # 46 | # You can pass +:username+ and +:password+ parameters to the call. 47 | # 48 | # @param [Hash] opts authentication credentials. 49 | # @option opts [String] :username cl.ly username 50 | # @option opts [String] :password cl.ly username 51 | # @return [CloudApp::Client] 52 | def initialize(opts = {}) 53 | if opts[:username] && opts[:password] 54 | Base.authenticate(opts[:username], opts[:password]) 55 | end 56 | end 57 | 58 | # Sets the authentication credentials in a class variable. 59 | # 60 | # @param [String] username cl.ly username 61 | # @param [String] password cl.ly password 62 | # @return [Hash] authentication credentials 63 | def authenticate(username, password) 64 | Base.authenticate(username, password) 65 | end 66 | 67 | # Get metadata about a cl.ly URL like name, type, or view count. 68 | # 69 | # Finds the drop by it's slug id, for example "2wr4". 70 | # 71 | # @param [String] id cl.ly slug id 72 | # @return [CloudApp::Drop] 73 | def drop(id) 74 | Drop.find(id) 75 | end 76 | 77 | alias_method :item, :drop 78 | 79 | # Page through your drops. 80 | # 81 | # Requires authentication. 82 | # 83 | # @param [Hash] opts options parameters 84 | # @option opts [Integer] :page (1) Page number starting at 1 85 | # @option opts [Integer] :per_page (5) Number of items per page 86 | # @option opts [String] :type ('image') Filter items by type (image, bookmark, text, archive, audio, video, or unknown) 87 | # @option opts [Boolean] :deleted (true) Show trashed drops 88 | # @return [Array[CloudApp::Drop]] 89 | def drops(opts = {}) 90 | Drop.all(opts) 91 | end 92 | 93 | alias_method :items, :drops 94 | 95 | # Create one or more new bookmark drops. 96 | # 97 | # Requires authentication. 98 | # 99 | # @overload bookmark(url, name = "") 100 | # @param [String] url url to bookmark 101 | # @param [String] name name of bookmark 102 | # @overload bookmark(opts) 103 | # @param [Array] opts array of bookmark option parameters (containing +:name+ and +:redirect_url+) 104 | # @return [CloudApp::Drop] 105 | def bookmark(*args) 106 | if args[0].is_a? Array 107 | Drop.create(:bookmarks, args) 108 | else 109 | url, name = args[0], (args[1] || "") 110 | Drop.create(:bookmark, {:name => name, :redirect_url => url}) 111 | end 112 | end 113 | 114 | # Create a new drop by uploading a file. 115 | # 116 | # Requires authentication. 117 | # 118 | # @param [String] file local path to file 119 | # @param [optional, Hash] opts options paramaters 120 | # @option opts [Boolean] :private override the account default privacy setting 121 | # @return [CloudApp::Drop] 122 | def upload(file, opts = {}) 123 | Drop.create(:upload, opts.merge(:file => file)) 124 | end 125 | 126 | # Change the name of the drop. 127 | # 128 | # Finds the drop by it's slug id, for example "2wr4". 129 | # 130 | # Requires authentication. 131 | # 132 | # @param [String] id drop id 133 | # @param [String] name new drop name 134 | # @return [CloudApp::Drop] 135 | def rename(id, name = "") 136 | drop = Drop.find(id) 137 | drop.update(:name => name) 138 | end 139 | 140 | # Modify a drop with a private URL to have a public URL or vice versa. 141 | # 142 | # Finds the drop by it's slug id, for example "2wr4". 143 | # 144 | # Requires authentication. 145 | # 146 | # @param [String] id drop id 147 | # @param [Boolean] privacy privacy setting 148 | # @return [CloudApp::Drop] 149 | def privacy(id, privacy = false) 150 | drop = Drop.find(id) 151 | drop.update(:private => privacy) 152 | end 153 | 154 | # Send the drop to the trash. 155 | # 156 | # Finds the drop by it's slug id, for example "2wr4". 157 | # 158 | # Requires authentication. 159 | # 160 | # @param [String] id drop id 161 | # @return [CloudApp::Drop] 162 | def delete(id) 163 | drop = Drop.find(id) 164 | drop.delete 165 | end 166 | 167 | # Recover a deleted drop from the trash. 168 | # 169 | # Finds the drop by it's slug id, for example "2wr4". 170 | # 171 | # Requires authentication. 172 | # 173 | # @param [String] id drop id 174 | # @return [CloudApp::Drop] 175 | def recover(id) 176 | drop = Drop.find(id) 177 | drop.recover 178 | end 179 | 180 | end 181 | 182 | end 183 | -------------------------------------------------------------------------------- /lib/cloudapp/core_ext.rb: -------------------------------------------------------------------------------- 1 | class Hash #:nodoc: 2 | 3 | # Return a new hash with all keys converted to symbols. 4 | def symbolize_keys 5 | inject({}) do |options, (key, value)| 6 | options[(key.to_sym rescue key) || key] = value 7 | options 8 | end 9 | end 10 | 11 | # Destructively convert all keys to symbols. 12 | def symbolize_keys! 13 | self.replace(self.symbolize_keys) 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /lib/cloudapp/drop.rb: -------------------------------------------------------------------------------- 1 | module CloudApp 2 | 3 | # An ActiveResource-like interface through which to interract with CloudApp drops. 4 | # 5 | # @example Gets started by Authenticating 6 | # CloudApp.authenticate "username", "password" 7 | # 8 | # @example Usage via the Drop class 9 | # # Find a single drop by it's slug 10 | # @drop = CloudApp::Drop.find "2wr4" 11 | # 12 | # # Get a list of all drops 13 | # @drops = CloudApp::Drop.all 14 | # 15 | # # Create a new bookmark 16 | # @drop = CloudApp::Drop.create :bookmark, :name => "CloudApp", :redirect_url => "http://getcloudapp.com" 17 | # 18 | # # Create multiple bookmarks 19 | # bookmarks = [ 20 | # { :name => "Authur Dent", :redirect_url => "http://en.wikipedia.org/wiki/Arthur_Dent" }, 21 | # { :name => "Zaphod Beeblebrox", :redirect_url => "http://en.wikipedia.org/wiki/Zaphod_Beeblebrox" } 22 | # ] 23 | # @drops = CloudApp::Drop.create :bookmarks, bookmarks 24 | # 25 | # # Upload a file 26 | # @drop = CloudApp::Drop.create :upload, :file => "/path/to/image.png" 27 | # @drop = CloudApp::Drop.create :upload, :file => "/path/to/image.png", :private => true 28 | # 29 | # # Rename a file 30 | # CloudApp::Drop.update "http://my.cl.ly/items/1912565", :name => "Big Screenshot" 31 | # 32 | # # Set a drop's privacy 33 | # CloudApp::Drop.update "http://my.cl.ly/items/1912565", :private => true 34 | # 35 | # # Delete a drop 36 | # CloudApp::Drop.delete "http://my.cl.ly/items/1912565" 37 | # 38 | # # Recover a deleted drop 39 | # CloudApp::Drop.recover "http://my.cl.ly/items/1912565" 40 | # 41 | # @example Usage via the class instance 42 | # # Rename a file 43 | # @drop.update :name => "Big Screenshot" 44 | # 45 | # # Set the drop's privacy 46 | # @drop.update :private => true 47 | # 48 | # # Delete a drop 49 | # @drop.delete 50 | # 51 | # # Recover a deleted drop 52 | # @drop.recover 53 | # 54 | class Drop < Base 55 | 56 | # Get metadata about a cl.ly URL like name, type, or view count. 57 | # 58 | # Finds the drop by it's slug id, for example "2wr4". 59 | # 60 | # @param [String] id cl.ly slug id 61 | # @return [CloudApp::Drop] 62 | def self.find(id) 63 | res = get "http://cl.ly/#{id}" 64 | res.ok? ? Drop.new(res) : bad_response(res) 65 | end 66 | 67 | # Page through your drops. 68 | # 69 | # Requires authentication. 70 | # 71 | # @param [Hash] opts options parameters 72 | # @option opts [Integer] :page Page number starting at 1 73 | # @option opts [Integer] :per_page Number of items per page 74 | # @option opts [String] :type Filter items by type (image, bookmark, text, archive, audio, video, or unknown) 75 | # @option opts [Boolean] :deleted Show trashed drops 76 | # @return [Array[CloudApp::Drop]] 77 | def self.all(opts = {}) 78 | res = get "/items", {:query => (opts.empty? ? nil : opts), :digest_auth => @@auth} 79 | res.ok? ? res.collect{|i| Drop.new(i)} : bad_response(res) 80 | end 81 | 82 | # Create a new drop. Multiple bookmarks can be created at once by 83 | # passing an array of bookmark options parameters. 84 | # 85 | # Requires authentication. 86 | # 87 | # @param [Symbol] kind type of drop (can be +:bookmark+, +:bookmarks+ or +:upload+) 88 | # @overload self.create(:bookmark, opts = {}) 89 | # @param [Hash] opts options paramaters 90 | # @option opts [String] :name Name of bookmark (only required for +:bookmark+ kind) 91 | # @option opts [String] :redirect_url Redirect URL (only required for +:bookmark+ kind) 92 | # @overload self.create(:bookmarks, bookmarks) 93 | # @param [Array] bookmarks array of bookmark option parameters (containing +:name+ and +:redirect_url+) 94 | # @overload self.create(:upload, opts = {}) 95 | # @param [Hash] opts options paramaters 96 | # @option opts [String] :file Path to file (only required for +:upload+ kind) 97 | # @option opts [Boolean] :private override the account default privacy setting 98 | # @return [CloudApp::Drop] 99 | def self.create(kind, opts = {}) 100 | case kind 101 | when :bookmark 102 | res = post "/items", {:body => {:item => opts}, :digest_auth => @@auth} 103 | when :bookmarks 104 | res = post "/items", {:body => {:items => opts}, :digest_auth => @@auth} 105 | when :upload 106 | r = get "/items/new", {:query => ({:item => {:private => opts[:private]}} if opts.has_key?(:private)), :digest_auth => @@auth} 107 | return bad_response(r) unless r.ok? 108 | res = post r['url'], Multipart.new(r['params'].merge!(:file => File.new(opts[:file]))).payload.merge!(:digest_auth => @@auth) 109 | else 110 | # TODO raise an error 111 | return false 112 | end 113 | res.ok? ? (res.is_a?(Array) ? res.collect{|i| Drop.new(i)} : Drop.new(res)) : bad_response(res) 114 | end 115 | 116 | # Modify a drop. Can currently modify it's name or security setting by passing parameters. 117 | # 118 | # Requires authentication. 119 | # 120 | # @param [String] href href attribute of drop 121 | # @param [Hash] opts options paramaters 122 | # @option opts [String] :name for renaming the drop 123 | # @option opts [Boolean] :privacy set drop privacy 124 | # @return [CloudApp::Drop] 125 | def self.update(href, opts = {}) 126 | res = put href, {:body => {:item => opts}, :digest_auth => @@auth} 127 | res.ok? ? Drop.new(res) : bad_response(res) 128 | end 129 | 130 | # Send a drop to the trash. 131 | # 132 | # Requires authentication. 133 | # 134 | # @param [String] href href attribute of the drop 135 | # @return [CloudApp::Drop] 136 | def self.delete(href) 137 | # Use delete on the Base class to avoid recursion 138 | res = Base.delete href, :digest_auth => @@auth 139 | res.ok? ? Drop.new(res) : bad_response(res) 140 | end 141 | 142 | # Recover a drop from the trash. 143 | # 144 | # Requires authentication. 145 | # 146 | # @param [String] href href attribute of the drop 147 | # @return [CloudApp::Drop] 148 | def self.recover(href) 149 | res = put href, {:body => {:deleted => true, :item => {:deleted_at => nil}}, :digest_auth => @@auth} 150 | res.ok? ? Drop.new(res) : bad_response(res) 151 | end 152 | 153 | attr_reader :href, :name, :private, :url, :content_url, :item_type, :view_counter, 154 | :icon, :remote_url, :redirect_url, :source, :created_at, :updated_at, :deleted_at 155 | 156 | # Modify the drop. Can currently modify it's name or security setting by passing parameters. 157 | # 158 | # @param [Hash] opts options paramaters 159 | # @option opts [String] :name for renaming the drop 160 | # @option opts [Boolean] :privacy set the drop's privacy 161 | # @return [CloudApp::Drop] 162 | def update(opts = {}) 163 | self.class.update self.href, opts 164 | end 165 | 166 | # Send the drop to the trash. 167 | # 168 | # @return [CloudApp::Drop] 169 | def delete 170 | self.class.delete self.href 171 | end 172 | 173 | # Recover the drop from the trash. 174 | # 175 | # @return [CloudApp::Drop] 176 | def recover 177 | self.class.recover self.href 178 | end 179 | 180 | # Is the drop an image? 181 | # 182 | # @return [Boolean] 183 | def image? 184 | item_type == 'image' 185 | end 186 | 187 | # Is the drop a bookmark? 188 | # 189 | # @return [Boolean] 190 | def bookmark? 191 | item_type == 'bookmark' 192 | end 193 | 194 | # Is the drop a text file? 195 | # 196 | # @return [Boolean] 197 | def text? 198 | item_type == 'text' 199 | end 200 | 201 | # Is the drop an archive? 202 | # 203 | # @return [Boolean] 204 | def archive? 205 | item_type == 'archive' 206 | end 207 | 208 | # Is the drop an audio file? 209 | # 210 | # @return [Boolean] 211 | def audio? 212 | item_type == 'audio' 213 | end 214 | 215 | # Is the drop a video file? 216 | # 217 | # @return [Boolean] 218 | def video? 219 | item_type == 'video' 220 | end 221 | 222 | # Is the drop an unknown file type? 223 | # 224 | # @return [Boolean] 225 | def unknown? 226 | item_type == 'unknown' 227 | end 228 | 229 | # Return the drops raw data as a string, useful for returning the text of documents 230 | # 231 | # @return [String] 232 | def raw 233 | @raw ||= HTTParty.get(content_url).to_s 234 | end 235 | 236 | private 237 | 238 | def extension 239 | File.extname(content_url)[1..-1].to_s.downcase if content_url 240 | end 241 | 242 | end 243 | 244 | # The Item class is now deprecated in favour of the Drop class. 245 | # For legacy purposes you can still use the Item class but it is recommended you 246 | # update your code to use the Drop class to ensure future compatibility. 247 | class Item < Drop; end 248 | 249 | end 250 | -------------------------------------------------------------------------------- /lib/cloudapp/gift_card.rb: -------------------------------------------------------------------------------- 1 | module CloudApp 2 | 3 | # An ActiveResource-like interface through which to interract with CloudApp gift cards. 4 | # 5 | # 6 | # @example Gets started by Authenticating 7 | # CloudApp.authenticate "username", "password" 8 | # 9 | # @example Usage via the GiftCard class 10 | # # View gift card details 11 | # @gift = CloudApp::GiftCard.find "ABC123" 12 | # 13 | # # Apply the gift card 14 | # CloudApp::GiftCard.redeem "ABC123" 15 | # # or 16 | # @gift.redeem 17 | # 18 | class GiftCard < Base 19 | 20 | # Get the details of an unredeemed gift card. 21 | # 22 | # Requires authentication. 23 | # 24 | # @param [String] code Gift card code 25 | # @return [CloudApp::GiftCard] 26 | def self.find(code) 27 | res = get "/gift_cards/#{code}", :digest_auth => @@auth 28 | res.ok? ? GiftCard.new(res) : bad_response(res) 29 | end 30 | 31 | # Apply a gift card to the authenticated account. 32 | # 33 | # Requires authentication. 34 | # 35 | # @param [String] code Gift card code 36 | # @return [CloudApp::GiftCard] 37 | def self.redeem(code) 38 | res = put "/gift_cards/#{code}", {:body => {}, :digest_auth => @@auth} 39 | res.ok? ? GiftCard.new(res) : bad_response(res) 40 | end 41 | 42 | attr_reader :id, :code, :plan, :months, :href, 43 | :created_at, :updated_at, :redeemed_at, :effective_at, :expires_at 44 | 45 | # Apply the gift card to the authenticated account. 46 | # 47 | # @return [CloudApp::GiftCard] 48 | def redeem 49 | self.class.redeem code 50 | end 51 | 52 | end 53 | 54 | end -------------------------------------------------------------------------------- /lib/cloudapp/httparty.rb: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | module HTTParty #:nodoc: 4 | 5 | class Response < ::BasicObject #:nodoc: 6 | def ok? 7 | [200, 201, 202].include?(self.code) 8 | end 9 | end 10 | 11 | class Request #:nodoc: 12 | 13 | private 14 | 15 | def body 16 | options[:body].is_a?(Hash) ? options[:body].to_json : options[:body] 17 | end 18 | 19 | def setup_raw_request 20 | # This is a cloudapp hack to ensure the correct headers are set on redirect from S3 21 | if @redirect 22 | options[:headers] = CloudApp::HEADERS 23 | options[:query] = {} 24 | options[:body] = {} 25 | end 26 | @raw_request = http_method.new(uri.request_uri) 27 | @raw_request.body = body if body 28 | @raw_request.initialize_http_header(options[:headers]) 29 | @raw_request.basic_auth(username, password) if options[:basic_auth] 30 | setup_digest_auth if options[:digest_auth] 31 | end 32 | 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /lib/cloudapp/multipart.rb: -------------------------------------------------------------------------------- 1 | require "mime/types" 2 | 3 | module CloudApp 4 | 5 | # TODO - Document the Multipart Class 6 | class Multipart #:nodoc: 7 | 8 | EOL = "\r\n" #:nodoc: 9 | 10 | def initialize(params) 11 | @params = params 12 | file = @params.delete(:file) 13 | bound = "--#{boundary}" 14 | @body = bound + EOL 15 | @params.each do |key, val| 16 | @body += create_regular_field(key, val) 17 | @body += EOL + bound + EOL 18 | end 19 | @body += create_file_field(file) 20 | @body += EOL + bound + "--#{EOL}" 21 | end 22 | 23 | def payload #:nodoc: 24 | { 25 | :headers => {"User-Agent" => "Ruby.CloudApp.API", 26 | "Content-Type" => "multipart/form-data; boundary=#{boundary}"}, 27 | :body => @body 28 | } 29 | end 30 | 31 | def boundary #:nodoc: 32 | @boundary ||= "#{HEADERS["User-Agent"]}.#{Array.new(16/2) { rand(256) }.pack("C*").unpack("H*").first}" 33 | end 34 | 35 | def create_regular_field(key, val) #:nodoc: 36 | %Q{Content-Disposition: form-data; name="#{key}"} + EOL + EOL + val 37 | end 38 | 39 | def create_file_field(file) #:nodoc: 40 | %Q{Content-Disposition: form-data; name="file"; filename="#{File.basename(file.path)}"} + EOL + 41 | "Content-Type: #{mime_for(file.path)}" + EOL + EOL + 42 | file.read 43 | end 44 | 45 | def mime_for(path) #:nodoc: 46 | (MIME::Types.type_for(path)[0] || MIME::Types["application/octet-stream"][0]).simplified 47 | end 48 | 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /lib/cloudapp/response_error.rb: -------------------------------------------------------------------------------- 1 | module CloudApp 2 | 3 | # Error raised on a bad response 4 | class ResponseError < StandardError 5 | 6 | attr_reader :response, :code, :errors 7 | 8 | # Instantiate an instance of CloudApp::ResponseError 9 | # 10 | # Only used internally 11 | # 12 | # @param [HTTParty::Response] res 13 | # @return [CloudApp::ResponseError] 14 | def initialize(res) 15 | @response = res.response 16 | @code = res.code 17 | begin 18 | @errors = parse_errors(res.parsed_response) 19 | rescue JSON::ParserError => ex 20 | @errors = [res.response.body] 21 | end 22 | end 23 | 24 | # Returns error code and message 25 | # 26 | # @return [String] 27 | def to_s 28 | "#{code.to_s} #{response.msg}".strip 29 | end 30 | 31 | private 32 | 33 | def parse_errors(errors) 34 | return case errors 35 | when Hash 36 | errors.collect{|k,v| "#{k}: #{v}"} 37 | when String 38 | [errors] 39 | when Array 40 | errors 41 | else [] 42 | end 43 | end 44 | 45 | end 46 | 47 | end 48 | -------------------------------------------------------------------------------- /lib/cloudapp_api.rb: -------------------------------------------------------------------------------- 1 | require "httparty" 2 | require "yaml" unless defined?(YAML) 3 | YAML::ENGINE.yamler = "syck" if defined?(YAML::ENGINE) && RUBY_VERSION < "2.0.0" 4 | 5 | ["base", "drop", "account", "gift_card", "client", "multipart", "httparty", "core_ext", "response_error"].each do |inc| 6 | require File.join(File.dirname(__FILE__), "cloudapp", inc) 7 | end 8 | 9 | # A simple Ruby wrapper for the CloudApp API. Uses HTTParty and provides 10 | # two alternative interfaces for interracting with the API. 11 | # An ActiveResource-like interface is provided alongside a simple client interface. 12 | module CloudApp 13 | 14 | # Version number 15 | VERSION = "0.3.1" 16 | 17 | # Sets the authentication credentials in a class variable 18 | # 19 | # @param [String] email cl.ly username 20 | # @param [String] password cl.ly password 21 | # @return [Hash] authentication credentials 22 | def CloudApp.authenticate(email, password) 23 | Base.authenticate(email, password) 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /spec/cloudapp_account_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe CloudApp::Account do 4 | 5 | before(:each) do 6 | fake_it_all 7 | CloudApp.authenticate "testuser@test.com", "password" 8 | @account = CloudApp::Account.find 9 | end 10 | 11 | it "should be a Account object" do 12 | @account.should be_a_kind_of CloudApp::Account 13 | end 14 | 15 | it "should return an id" do 16 | @account.id.should == 1 17 | end 18 | 19 | it "should return an email" do 20 | @account.email.should == "arthur@dent.com" 21 | end 22 | 23 | it "should return a blank domain" do 24 | @account.domain.should == nil 25 | end 26 | 27 | it "should return a blank domain home page" do 28 | @account.domain_home_page.should == nil 29 | end 30 | 31 | it "should return a private items booleans" do 32 | @account.private_items.should == true 33 | end 34 | 35 | it "should return a subscribed boolean" do 36 | @account.subscribed.should == true 37 | end 38 | 39 | it "should return a subscription expiration date" do 40 | @account.subscription_expires_at == "2012-05-21" 41 | end 42 | 43 | it "should return a alpha boolean" do 44 | @account.alpha.should == false 45 | end 46 | 47 | it "should return timestamps" do 48 | @account.created_at.should be_a_kind_of Time 49 | @account.updated_at.should be_a_kind_of Time 50 | @account.activated_at.should be_a_kind_of Time 51 | end 52 | 53 | it "should return the raw data hash" do 54 | @account.data.should be_a_kind_of Hash 55 | @account.data['email'].should == "arthur@dent.com" 56 | end 57 | 58 | end 59 | 60 | 61 | describe "Change default security" do 62 | 63 | before(:each) do 64 | fake_it_all 65 | CloudApp.authenticate "testuser@test.com", "password" 66 | @account = CloudApp::Account.update :private_items => false 67 | end 68 | 69 | it "should be a Account object" do 70 | @account.should be_a_kind_of CloudApp::Account 71 | end 72 | 73 | it "should have private items set to false" do 74 | @account.private_items.should == false 75 | end 76 | 77 | end 78 | 79 | 80 | describe "Change email" do 81 | 82 | before(:each) do 83 | fake_it_all 84 | CloudApp.authenticate "testuser@test.com", "password" 85 | @email = "ford@prefect.com" 86 | @account = CloudApp::Account.update :email => @email, :current_password => "towel" 87 | end 88 | 89 | it "should be a Account object" do 90 | @account.should be_a_kind_of CloudApp::Account 91 | end 92 | 93 | it "should have the new email address" do 94 | @account.email.should == @email 95 | end 96 | 97 | end 98 | 99 | 100 | describe "Change password" do 101 | 102 | before(:each) do 103 | fake_it_all 104 | CloudApp.authenticate "testuser@test.com", "password" 105 | @account = CloudApp::Account.update :password => "hoopy frood", :current_password => "towel" 106 | end 107 | 108 | it "should be a Account object" do 109 | @account.should be_a_kind_of CloudApp::Account 110 | end 111 | 112 | end 113 | 114 | 115 | describe "Reset password" do 116 | 117 | before(:each) do 118 | fake_it_all 119 | @response = CloudApp::Account.reset :email => "arthur@dent.com" 120 | end 121 | 122 | it "should return true" do 123 | @response.should == true 124 | end 125 | 126 | end 127 | 128 | 129 | describe "Register account" do 130 | 131 | before(:each) do 132 | fake_it_all 133 | @email = "arthur@dent.com" 134 | @account = CloudApp::Account.create :email => @email, :current_password => "towel", :accept_tos => true 135 | end 136 | 137 | it "should be a Account object" do 138 | @account.should be_a_kind_of CloudApp::Account 139 | end 140 | 141 | it "should have the same email" do 142 | @account.email.should == @email 143 | end 144 | 145 | end 146 | 147 | 148 | describe "Set custom domain" do 149 | 150 | before(:each) do 151 | fake_it_all 152 | CloudApp.authenticate "testuser@test.com", "password" 153 | @domain = "dent.com" 154 | @dhp = "http://hhgproject.org" 155 | @account = CloudApp::Account.update :domain => @domain, :domain_home_page => @dhp 156 | end 157 | 158 | it "should be a Account object" do 159 | @account.should be_a_kind_of CloudApp::Account 160 | end 161 | 162 | it "should have the same domain" do 163 | @account.domain.should == @domain 164 | end 165 | 166 | it "should have the same domain home page" do 167 | @account.domain_home_page.should == @dhp 168 | end 169 | 170 | end 171 | 172 | 173 | describe "View account statistics" do 174 | 175 | before(:each) do 176 | fake_it_all 177 | CloudApp.authenticate "testuser@test.com", "password" 178 | @account = CloudApp::Account.find 179 | @stats = @account.stats 180 | end 181 | 182 | it "should be a Hash object" do 183 | @stats.should be_a_kind_of Hash 184 | end 185 | 186 | it "should have a number of items" do 187 | @stats[:items].should be_true 188 | @stats[:items].should be_a_kind_of Integer 189 | end 190 | 191 | it "should have a number of views" do 192 | @stats[:views].should be_true 193 | @stats[:views].should be_a_kind_of Integer 194 | end 195 | 196 | end 197 | -------------------------------------------------------------------------------- /spec/cloudapp_api_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe CloudApp do 4 | 5 | it "should set correct headers" do 6 | CloudApp::HEADERS['User-Agent'].should == "Ruby.CloudApp.API" 7 | CloudApp::HEADERS['Accept'].should == "application/json" 8 | CloudApp::HEADERS['Content-Type'].should == "application/json" 9 | end 10 | 11 | it "should be authenticatable" do 12 | auth = { 13 | :username => "testuser@test.com", 14 | :password => "password" 15 | } 16 | CloudApp.authenticate(auth[:username], auth[:password]).should == auth 17 | end 18 | 19 | end 20 | 21 | -------------------------------------------------------------------------------- /spec/cloudapp_client_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe CloudApp::Client do 4 | 5 | before(:each) do 6 | fake_it_all 7 | CloudApp.authenticate "testuser@test.com", "password" 8 | @client = CloudApp::Client.new 9 | end 10 | 11 | it "should be reautheticatable" do 12 | username = "joe.bloggs@testing.com" 13 | password = "password" 14 | auth = @client.authenticate username, password 15 | auth[:username].should == username 16 | end 17 | 18 | it "should find an drop" do 19 | drop = @client.drop "2wr4" 20 | drop.should be_a_kind_of CloudApp::Drop 21 | end 22 | 23 | it "should list all drops" do 24 | drops = @client.drops 25 | drops.should be_a_kind_of Array 26 | drops.each do |drop| 27 | drop.should be_a_kind_of CloudApp::Drop 28 | end 29 | end 30 | 31 | it "should bookmark an drop" do 32 | name = "CloudApp" 33 | drop = @client.bookmark "http://getcloudapp.com", name 34 | drop.should be_a_kind_of CloudApp::Drop 35 | drop.name.should == name 36 | end 37 | 38 | it "should bookmark multiple drops" do 39 | # overwrite the normal fake uri for this spec 40 | FakeWeb.register_uri :post, 'http://my.cl.ly/items', :response => stub_file(File.join('drop', 'index')) 41 | bookmarks = [ 42 | { :name => "Authur Dent", :redirect_url => "http://en.wikipedia.org/wiki/Arthur_Dent" }, 43 | { :name => "Ford Prefect", :redirect_url => "http://en.wikipedia.org/wiki/Ford_Prefect_(character)"}, 44 | { :name => "Zaphod Beeblebrox", :redirect_url => "http://en.wikipedia.org/wiki/Zaphod_Beeblebrox" } 45 | ] 46 | drops = @client.bookmark bookmarks 47 | drops.should be_a_kind_of Array 48 | drops.each do |drop| 49 | drop.should be_a_kind_of CloudApp::Drop 50 | end 51 | end 52 | 53 | it "should upload a file" do 54 | drop = @client.upload "README.md" 55 | drop.should be_a_kind_of CloudApp::Drop 56 | drop.item_type.should == "image" 57 | end 58 | 59 | it "should upload a file with specific privacy" do 60 | # override the upload fakeweb uri 61 | FakeWeb.register_uri :post, 'http://f.cl.ly', :status => ["303"], :location => "http://my.cl.ly/items/s3?item[private]=true" 62 | drop = @client.upload "README.md", :private => true 63 | drop.should be_a_kind_of CloudApp::Drop 64 | drop.private.should == true 65 | end 66 | 67 | it "should rename an drop" do 68 | name = "CloudApp" 69 | drop = @client.rename "2wr4", name 70 | drop.should be_a_kind_of CloudApp::Drop 71 | drop.name.should == name 72 | end 73 | 74 | it "should set an drops privacy" do 75 | drop = @client.privacy "2wr4", false 76 | drop.should be_a_kind_of CloudApp::Drop 77 | drop.private.should == false 78 | end 79 | 80 | it "should delete an drop" do 81 | drop = @client.delete "2wr4" 82 | drop.should be_a_kind_of CloudApp::Drop 83 | drop.deleted_at.should be_a_kind_of Time 84 | end 85 | 86 | it "should recover an drop" do 87 | drop = @client.recover "2wr4" 88 | drop.should be_a_kind_of CloudApp::Drop 89 | drop.deleted_at.should == nil 90 | end 91 | 92 | end 93 | -------------------------------------------------------------------------------- /spec/cloudapp_drop_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe CloudApp::Drop do 4 | 5 | before(:each) do 6 | fake_it_all 7 | @drop = CloudApp::Drop.find "2wr4" 8 | end 9 | 10 | it "should be a Drop object" do 11 | @drop.should be_a_kind_of CloudApp::Drop 12 | end 13 | 14 | it "should return a name" do 15 | @drop.name.should == "CloudApp Logo.png" 16 | end 17 | 18 | it "should return an href" do 19 | @drop.href.should == "http://my.cl.ly/items/1912559" 20 | end 21 | 22 | it "should return a privacy boolean" do 23 | @drop.private.should == false 24 | end 25 | 26 | it "should return a url" do 27 | @drop.url.should == "http://cl.ly/2wr4" 28 | end 29 | 30 | it "should return a content url" do 31 | @drop.content_url.should == "http://cl.ly/2wr4/CloudApp_Logo.png" 32 | end 33 | 34 | it "should return a drop type" do 35 | @drop.item_type.should == "image" 36 | end 37 | 38 | it "should return a view counter" do 39 | @drop.view_counter.should == 42 40 | end 41 | 42 | it "should return an icon url" do 43 | @drop.icon.should == "http://my.cl.ly/images/item_types/image.png" 44 | end 45 | 46 | it "should return a remote url" do 47 | @drop.remote_url == "http://f.cl.ly/items/7c7aea1395c3db0aee18/CloudApp%20Logo.png" 48 | end 49 | 50 | it "should not return a redirect url" do 51 | @drop.redirect_url == nil 52 | end 53 | 54 | it "should return a source" do 55 | @drop.source == "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)" 56 | end 57 | 58 | it "should return timestamps" do 59 | @drop.created_at.should be_a_kind_of Time 60 | @drop.updated_at.should be_a_kind_of Time 61 | @drop.deleted_at.should == nil 62 | end 63 | 64 | it "should return the raw data hash" do 65 | @drop.data.should be_a_kind_of Hash 66 | @drop.data['name'].should == "CloudApp Logo.png" 67 | end 68 | 69 | end 70 | 71 | 72 | describe "Bookmark link" do 73 | 74 | before(:each) do 75 | fake_it_all 76 | CloudApp.authenticate "testuser@test.com", "password" 77 | @name = "CloudApp" 78 | @redirect_url = "http://getcloudapp.com" 79 | @drop = CloudApp::Drop.create :bookmark, {:name => @name, :redirect_url => @redirect_url} 80 | end 81 | 82 | it "should be a Drop object" do 83 | @drop.should be_a_kind_of CloudApp::Drop 84 | end 85 | 86 | it "should return the same name" do 87 | @drop.name.should == @name 88 | end 89 | 90 | it "should return the same redirect_url" do 91 | @drop.redirect_url.should == @redirect_url 92 | end 93 | 94 | end 95 | 96 | 97 | describe "Bookmark multiple links" do 98 | 99 | before(:each) do 100 | fake_it_all 101 | # overwrite the normal fake uri for this spec 102 | FakeWeb.register_uri :post, 'http://my.cl.ly/items', :response => stub_file(File.join('drop', 'index')) 103 | CloudApp.authenticate "testuser@test.com", "password" 104 | @bookmarks = [ 105 | { :name => "Authur Dent", :redirect_url => "http://en.wikipedia.org/wiki/Arthur_Dent" }, 106 | { :name => "Ford Prefect", :redirect_url => "http://en.wikipedia.org/wiki/Ford_Prefect_(character)"}, 107 | { :name => "Zaphod Beeblebrox", :redirect_url => "http://en.wikipedia.org/wiki/Zaphod_Beeblebrox" } 108 | ] 109 | @drops = CloudApp::Drop.create :bookmarks, @bookmarks 110 | end 111 | 112 | it "should be an Array" do 113 | @drops.should be_a_kind_of Array 114 | end 115 | 116 | it "should contain Drop objects" do 117 | @drops.each do |drop| 118 | drop.should be_a_kind_of CloudApp::Drop 119 | end 120 | end 121 | 122 | end 123 | 124 | 125 | describe "Change security of an drop" do 126 | 127 | before(:each) do 128 | fake_it_all 129 | CloudApp.authenticate "testuser@test.com", "password" 130 | @drop = CloudApp::Drop.update "http://my.cl.ly/items/1912565", {:private => false} 131 | end 132 | 133 | it "should be an Drop object" do 134 | @drop.should be_a_kind_of CloudApp::Drop 135 | end 136 | 137 | it "should not be private" do 138 | @drop.private.should == false 139 | end 140 | 141 | end 142 | 143 | 144 | 145 | describe "Delete a drop" do 146 | 147 | before(:each) do 148 | fake_it_all 149 | CloudApp.authenticate "testuser@test.com", "password" 150 | @drop = CloudApp::Drop.delete "http://my.cl.ly/items/1912565" 151 | end 152 | 153 | it "should be an Drop object" do 154 | @drop.should be_a_kind_of CloudApp::Drop 155 | end 156 | 157 | it "should have a deleted_at timestamp" do 158 | @drop.deleted_at.should be_a_kind_of Time 159 | end 160 | 161 | end 162 | 163 | 164 | describe "Empty trash" do 165 | end 166 | 167 | 168 | describe "List drops" do 169 | 170 | before(:each) do 171 | fake_it_all 172 | CloudApp.authenticate "testuser@test.com", "password" 173 | @drops = CloudApp::Drop.all 174 | end 175 | 176 | it "should be an Array" do 177 | @drops.should be_a_kind_of Array 178 | end 179 | 180 | it "should contain Drop objects" do 181 | @drops.each do |drop| 182 | drop.should be_a_kind_of CloudApp::Drop 183 | end 184 | end 185 | 186 | end 187 | 188 | 189 | describe "Recover deleted drop" do 190 | 191 | before(:each) do 192 | fake_it_all 193 | CloudApp.authenticate "testuser@test.com", "password" 194 | @drop = CloudApp::Drop.recover "http://my.cl.ly/items/1912565" 195 | end 196 | 197 | it "should be an Drop object" do 198 | @drop.should be_a_kind_of CloudApp::Drop 199 | end 200 | 201 | it "should not have a deleted_at timestamp" do 202 | @drop.deleted_at.should == nil 203 | end 204 | 205 | end 206 | 207 | 208 | describe "Rename drop" do 209 | 210 | before(:each) do 211 | fake_it_all 212 | CloudApp.authenticate "testuser@test.com", "password" 213 | @name = "CloudApp" 214 | @drop = CloudApp::Drop.update "http://my.cl.ly/items/1912565", {:name => @name} 215 | end 216 | 217 | it "should be an Drop object" do 218 | @drop.should be_a_kind_of CloudApp::Drop 219 | end 220 | 221 | it "should be have the same name" do 222 | @drop.name.should == @name 223 | end 224 | 225 | end 226 | 227 | 228 | describe "Upload file" do 229 | 230 | before(:each) do 231 | fake_it_all 232 | CloudApp.authenticate "testuser@test.com", "password" 233 | @drop = CloudApp::Drop.create :upload, {:file => "README.md"} 234 | end 235 | 236 | it "should be an Drop object" do 237 | @drop.should be_a_kind_of CloudApp::Drop 238 | end 239 | 240 | it "should return a drop type" do 241 | @drop.item_type.should == "image" 242 | end 243 | 244 | end 245 | 246 | 247 | describe "Upload file with specific privacy" do 248 | 249 | before(:each) do 250 | fake_it_all 251 | # override the upload fakeweb uri 252 | FakeWeb.register_uri :post, 'http://f.cl.ly', :status => ["303"], :location => "http://my.cl.ly/items/s3?item[private]=true" 253 | CloudApp.authenticate "testuser@test.com", "password" 254 | @drop = CloudApp::Drop.create :upload, {:file => "README.md", :private => true} 255 | end 256 | 257 | it "should be an Drop object" do 258 | @drop.should be_a_kind_of CloudApp::Drop 259 | end 260 | 261 | it "should return as private" do 262 | @drop.private.should == true 263 | end 264 | 265 | end 266 | -------------------------------------------------------------------------------- /spec/cloudapp_gift_card_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe CloudApp::GiftCard do 4 | 5 | before(:each) do 6 | fake_it_all 7 | @gift = CloudApp::GiftCard.find "ABC123" 8 | end 9 | 10 | it "should be a GiftCard object" do 11 | @gift.should be_a_kind_of CloudApp::GiftCard 12 | end 13 | 14 | it "should return an id" do 15 | @gift.id.should == 1 16 | end 17 | 18 | it "should return a code" do 19 | @gift.code.should == "ABC123" 20 | end 21 | 22 | it "should return a plan" do 23 | @gift.plan.should == "pro" 24 | end 25 | 26 | it "should return a months attribute" do 27 | @gift.months.should == 12 28 | end 29 | 30 | it "should return the gift card url" do 31 | @gift.href.should == "https://my.cl.ly/gift_cards/ABC123" 32 | end 33 | 34 | it "should return timestamps" do 35 | @gift.created_at.should be_a_kind_of Time 36 | @gift.updated_at.should be_a_kind_of Time 37 | @gift.redeemed_at.should == nil 38 | @gift.effective_at.should == nil 39 | @gift.expires_at.should == nil 40 | end 41 | 42 | it "should return the raw data hash" do 43 | @gift.data.should be_a_kind_of Hash 44 | @gift.data['code'].should == "ABC123" 45 | end 46 | 47 | end 48 | 49 | describe "Redeem gift card" do 50 | 51 | before(:each) do 52 | fake_it_all 53 | @gift = CloudApp::GiftCard.redeem "ABC123" 54 | end 55 | 56 | it "should be a GiftCard object" do 57 | @gift.should be_a_kind_of CloudApp::GiftCard 58 | end 59 | 60 | it "should have a redeemed at time" do 61 | @gift.redeemed_at.should be_a_kind_of Time 62 | end 63 | 64 | it "should have an effective at date" do 65 | @gift.effective_at.should be_a_kind_of Date 66 | end 67 | 68 | it "should have an expires at date" do 69 | @gift.expires_at.should be_a_kind_of Date 70 | end 71 | 72 | end 73 | -------------------------------------------------------------------------------- /spec/cloudapp_item_spec.rb: -------------------------------------------------------------------------------- 1 | # For legacy purpose still test director on the Item object 2 | # Item is deprecated and should not be used. Instead use the Drop object. 3 | 4 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 5 | 6 | describe CloudApp::Item do 7 | 8 | before(:each) do 9 | fake_it_all 10 | @item = CloudApp::Item.find "2wr4" 11 | end 12 | 13 | it "should be a Item object" do 14 | @item.should be_a_kind_of CloudApp::Drop 15 | end 16 | 17 | it "should return a name" do 18 | @item.name.should == "CloudApp Logo.png" 19 | end 20 | 21 | it "should return an href" do 22 | @item.href.should == "http://my.cl.ly/items/1912559" 23 | end 24 | 25 | it "should return a privacy boolean" do 26 | @item.private.should == false 27 | end 28 | 29 | it "should return a url" do 30 | @item.url.should == "http://cl.ly/2wr4" 31 | end 32 | 33 | it "should return a content url" do 34 | @item.content_url.should == "http://cl.ly/2wr4/CloudApp_Logo.png" 35 | end 36 | 37 | it "should return a item type" do 38 | @item.item_type.should == "image" 39 | end 40 | 41 | it "should return a view counter" do 42 | @item.view_counter.should == 42 43 | end 44 | 45 | it "should return an icon url" do 46 | @item.icon.should == "http://my.cl.ly/images/item_types/image.png" 47 | end 48 | 49 | it "should return a remote url" do 50 | @item.remote_url == "http://f.cl.ly/items/7c7aea1395c3db0aee18/CloudApp%20Logo.png" 51 | end 52 | 53 | it "should not return a redirect url" do 54 | @item.redirect_url == nil 55 | end 56 | 57 | it "should return timestamps" do 58 | @item.created_at.should be_a_kind_of Time 59 | @item.updated_at.should be_a_kind_of Time 60 | @item.deleted_at.should == nil 61 | end 62 | 63 | end 64 | 65 | 66 | describe "Bookmark link" do 67 | 68 | before(:each) do 69 | fake_it_all 70 | CloudApp.authenticate "testuser@test.com", "password" 71 | @name = "CloudApp" 72 | @redirect_url = "http://getcloudapp.com" 73 | @item = CloudApp::Item.create :bookmark, {:name => @name, :redirect_url => @redirect_url} 74 | end 75 | 76 | it "should be a Item object" do 77 | @item.should be_a_kind_of CloudApp::Drop 78 | end 79 | 80 | it "should return the same name" do 81 | @item.name.should == @name 82 | end 83 | 84 | it "should return the same redirect_url" do 85 | @item.redirect_url.should == @redirect_url 86 | end 87 | 88 | end 89 | 90 | 91 | describe "Bookmark multiple links" do 92 | 93 | before(:each) do 94 | fake_it_all 95 | # overwrite the normal fake uri for this spec 96 | FakeWeb.register_uri :post, 'http://my.cl.ly/items', :response => stub_file(File.join('drop', 'index')) 97 | CloudApp.authenticate "testuser@test.com", "password" 98 | @bookmarks = [ 99 | { :name => "Authur Dent", :redirect_url => "http://en.wikipedia.org/wiki/Arthur_Dent" }, 100 | { :name => "Ford Prefect", :redirect_url => "http://en.wikipedia.org/wiki/Ford_Prefect_(character)"}, 101 | { :name => "Zaphod Beeblebrox", :redirect_url => "http://en.wikipedia.org/wiki/Zaphod_Beeblebrox" } 102 | ] 103 | @items = CloudApp::Item.create :bookmarks, @bookmarks 104 | end 105 | 106 | it "should be an Array" do 107 | @items.should be_a_kind_of Array 108 | end 109 | 110 | it "should contain Item objects" do 111 | @items.each do |item| 112 | item.should be_a_kind_of CloudApp::Drop 113 | end 114 | end 115 | 116 | end 117 | 118 | 119 | describe "Change security of an item" do 120 | 121 | before(:each) do 122 | fake_it_all 123 | CloudApp.authenticate "testuser@test.com", "password" 124 | @item = CloudApp::Item.update "http://my.cl.ly/items/1912565", {:private => false} 125 | end 126 | 127 | it "should be an Item object" do 128 | @item.should be_a_kind_of CloudApp::Drop 129 | end 130 | 131 | it "should not be private" do 132 | @item.private.should == false 133 | end 134 | 135 | end 136 | 137 | 138 | 139 | describe "Delete an item" do 140 | 141 | before(:each) do 142 | fake_it_all 143 | CloudApp.authenticate "testuser@test.com", "password" 144 | @item = CloudApp::Item.delete "http://my.cl.ly/items/1912565" 145 | end 146 | 147 | it "should be an Item object" do 148 | @item.should be_a_kind_of CloudApp::Drop 149 | end 150 | 151 | it "should have a deleted_at timestamp" do 152 | @item.deleted_at.should be_a_kind_of Time 153 | end 154 | 155 | end 156 | 157 | 158 | describe "Empty trash" do 159 | end 160 | 161 | 162 | describe "List items" do 163 | 164 | before(:each) do 165 | fake_it_all 166 | CloudApp.authenticate "testuser@test.com", "password" 167 | @items = CloudApp::Item.all 168 | end 169 | 170 | it "should be an Array" do 171 | @items.should be_a_kind_of Array 172 | end 173 | 174 | it "should contain Item objects" do 175 | @items.each do |item| 176 | item.should be_a_kind_of CloudApp::Drop 177 | end 178 | end 179 | 180 | end 181 | 182 | 183 | describe "Recover deleted item" do 184 | 185 | before(:each) do 186 | fake_it_all 187 | CloudApp.authenticate "testuser@test.com", "password" 188 | @item = CloudApp::Item.recover "http://my.cl.ly/items/1912565" 189 | end 190 | 191 | it "should be an Item object" do 192 | @item.should be_a_kind_of CloudApp::Drop 193 | end 194 | 195 | it "should not have a deleted_at timestamp" do 196 | @item.deleted_at.should == nil 197 | end 198 | 199 | end 200 | 201 | 202 | describe "Rename item" do 203 | 204 | before(:each) do 205 | fake_it_all 206 | CloudApp.authenticate "testuser@test.com", "password" 207 | @name = "CloudApp" 208 | @item = CloudApp::Item.update "http://my.cl.ly/items/1912565", {:name => @name} 209 | end 210 | 211 | it "should be an Item object" do 212 | @item.should be_a_kind_of CloudApp::Drop 213 | end 214 | 215 | it "should be have the same name" do 216 | @item.name.should == @name 217 | end 218 | 219 | end 220 | 221 | 222 | describe "Upload file" do 223 | 224 | before(:each) do 225 | fake_it_all 226 | CloudApp.authenticate "testuser@test.com", "password" 227 | @item = CloudApp::Item.create :upload, {:file => "README.md"} 228 | end 229 | 230 | it "should be an Item object" do 231 | @item.should be_a_kind_of CloudApp::Drop 232 | end 233 | 234 | it "should return a item type" do 235 | @item.item_type.should == "image" 236 | end 237 | 238 | end 239 | 240 | 241 | describe "Upload file with specific privacy" do 242 | 243 | before(:each) do 244 | fake_it_all 245 | # override the upload fakeweb uri 246 | FakeWeb.register_uri :post, 'http://f.cl.ly', :status => ["303"], :location => "http://my.cl.ly/items/s3?item[private]=true" 247 | CloudApp.authenticate "testuser@test.com", "password" 248 | @item = CloudApp::Item.create :upload, {:file => "README.md", :private => true} 249 | end 250 | 251 | it "should be an Item object" do 252 | @item.should be_a_kind_of CloudApp::Drop 253 | end 254 | 255 | it "should return as private" do 256 | @item.private.should == true 257 | end 258 | 259 | end 260 | 261 | 262 | -------------------------------------------------------------------------------- /spec/cloudapp_response_error_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe CloudApp::ResponseError, "when not logged in" do 4 | 5 | before(:each) do 6 | fake_it_all_with_errors 7 | @error = lambda { CloudApp::Drop.all } 8 | end 9 | 10 | it "should raise a 401" do 11 | @error.should raise_error(CloudApp::ResponseError, "401 Unauthorized") 12 | end 13 | 14 | it "should return a code and error messages" do 15 | @error.should raise_error{|e| 16 | e.code.should == 401 17 | e.errors[0].should == "HTTP Digest: \"Access denied.\"" 18 | } 19 | end 20 | 21 | end 22 | 23 | 24 | describe CloudApp::ResponseError, "when item doesn't exist" do 25 | 26 | before(:each) do 27 | fake_it_all_with_errors 28 | @error = lambda { CloudApp::Drop.find "12345" } 29 | end 30 | 31 | it "should raise a 404" do 32 | @error.should raise_error(CloudApp::ResponseError, "404 Not Found") 33 | end 34 | 35 | it "should return a code and error messages" do 36 | @error.should raise_error{|e| 37 | e.code.should == 404 38 | e.errors[0].should == "

Not Found

" 39 | } 40 | end 41 | 42 | end 43 | 44 | 45 | describe CloudApp::ResponseError, "when updating someone elses item" do 46 | 47 | before(:each) do 48 | fake_it_all_with_errors 49 | @error = lambda { CloudApp::Drop.update "http://my.cl.ly/items/12345" } 50 | end 51 | 52 | it "should raise a 404" do 53 | @error.should raise_error(CloudApp::ResponseError, "404 Not Found") 54 | end 55 | 56 | it "should return a code and error messages" do 57 | @error.should raise_error{|e| 58 | e.code.should == 404 59 | } 60 | end 61 | 62 | end 63 | 64 | 65 | describe "when recovering an unrecoverable item" do 66 | 67 | before(:each) do 68 | fake_it_all_with_errors 69 | @error = lambda { CloudApp::Drop.recover "http://my.cl.ly/items/12345" } 70 | end 71 | 72 | it "should raise a 404" do 73 | @error.should raise_error(CloudApp::ResponseError, "404 Not Found") 74 | end 75 | 76 | it "should return a code and error messages" do 77 | @error.should raise_error{|e| 78 | e.code.should == 404 79 | } 80 | end 81 | 82 | end 83 | 84 | 85 | describe CloudApp::ResponseError, "badly formatted bookmark" do 86 | 87 | before(:each) do 88 | fake_it_all_with_errors 89 | FakeWeb.register_uri :post, 'http://my.cl.ly/items', :response => stub_file(File.join('error', '422-bookmark')) 90 | CloudApp.authenticate "testuser@test.com", "password" 91 | @error = lambda { CloudApp::Drop.create :bookmark } 92 | end 93 | 94 | it "should raise a 422" do 95 | @error.should raise_error(CloudApp::ResponseError, "422") 96 | end 97 | 98 | it "should return an array of error messages" do 99 | @error.should raise_error{|e| 100 | e.errors.should be_a_kind_of(Array) 101 | e.errors[0].should == "URL can't be blank" 102 | } 103 | end 104 | 105 | end 106 | 107 | 108 | describe CloudApp::ResponseError, "badly formatted bookmarks" do 109 | 110 | before(:each) do 111 | fake_it_all_with_errors 112 | FakeWeb.register_uri :post, 'http://my.cl.ly/items', :response => stub_file(File.join('error', '422-bookmarks')) 113 | CloudApp.authenticate "testuser@test.com", "password" 114 | @error = lambda { CloudApp::Drop.create :bookmarks, [{}] } 115 | end 116 | 117 | it "should raise a 422" do 118 | @error.should raise_error(CloudApp::ResponseError, "422") 119 | end 120 | 121 | it "should return a nested array of error messages" do 122 | @error.should raise_error{|e| 123 | e.errors.should be_a_kind_of(Array) 124 | e.errors[0].should be_a_kind_of(Array) 125 | e.errors[0][0].should == "URL can't be blank" 126 | } 127 | end 128 | 129 | end 130 | 131 | -------------------------------------------------------------------------------- /spec/fakeweb_helper.rb: -------------------------------------------------------------------------------- 1 | require 'fakeweb' 2 | 3 | def stub_file(stub) 4 | File.join(File.dirname(__FILE__), 'stubs', stub) 5 | end 6 | 7 | def fake_it_all 8 | FakeWeb.clean_registry 9 | FakeWeb.register_uri :head, %r{http://(my.|f.)?cl.ly(/items)?}, :status => ["200", "OK"] 10 | FakeWeb.register_uri :post, 'http://f.cl.ly', :status => ["303"], :location => "http://my.cl.ly/items/s3" 11 | FakeWeb.register_uri :post, 'http://my.cl.ly/reset', :status => ["200", "OK"] 12 | { 13 | # GET URLs 14 | :get => { 15 | %r{http://cl.ly/\w+} => File.join('drop', 'show'), 16 | 'http://my.cl.ly/items' => File.join('drop', 'index'), 17 | 'http://my.cl.ly/items/new' => File.join('drop', 'new'), 18 | 'http://my.cl.ly/items/new?item[private]=true' => File.join('drop', 'new-private'), 19 | 'http://my.cl.ly/items/s3' => File.join('drop', 'show'), 20 | 'http://my.cl.ly/items/s3?item[private]=true' => File.join('drop', 'show-private'), 21 | 'http://my.cl.ly/account' => File.join('account', 'show'), 22 | 'http://my.cl.ly/account/stats' => File.join('account', 'stats'), 23 | %r{http://my.cl.ly/gift_cards/\w+} => File.join('gift_card', 'show') 24 | }, 25 | # POST URLs 26 | :post => { 27 | 'http://my.cl.ly/items' => File.join('drop', 'create'), 28 | 'http://my.cl.ly/register' => File.join('account', 'create') 29 | }, 30 | # PUT URLs 31 | :put => { 32 | %r{http://my.cl.ly/items/\d+} => File.join('drop', 'update'), 33 | 'http://my.cl.ly/account' => File.join('account', 'update'), 34 | %r{http://my.cl.ly/gift_cards/\w+} => File.join('gift_card', 'redeem') 35 | }, 36 | # DELETE URLs 37 | :delete => { 38 | %r{http://my.cl.ly/items/\d+} => File.join('drop', 'delete') 39 | } 40 | }. 41 | each do |method, requests| 42 | requests.each do |url, response| 43 | FakeWeb.register_uri(method, url, :response => stub_file(response)) 44 | end 45 | end 46 | end 47 | 48 | def fake_it_all_with_errors 49 | FakeWeb.clean_registry 50 | FakeWeb.register_uri :head, %r{http://(my.|f.)?cl.ly(/items)?}, :status => ["200", "OK"] 51 | { 52 | :get => { 53 | 'http://my.cl.ly/items' => File.join('error', '401'), 54 | %r{http://cl.ly/\w+} => File.join('error', '404-find'), 55 | 'http://my.cl.ly/items/new' => File.join('drop', 'new') 56 | }, 57 | :put => { 58 | %r{http://my.cl.ly/items/\d+} => File.join('error', '404-update') 59 | } 60 | }.each do |method, requests| 61 | requests.each do |url, response| 62 | FakeWeb.register_uri(method, url, :response => stub_file(response)) 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 2 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 3 | require 'rspec' 4 | require 'fakeweb_helper.rb' 5 | require 'cloudapp_api' 6 | require 'coveralls' 7 | Coveralls.wear! 8 | 9 | # Requires supporting files with custom matchers and macros, etc, 10 | # in ./support/ and its subdirectories. 11 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} 12 | 13 | RSpec.configure do |config| 14 | config.color_enabled = true 15 | 16 | config.before :suite do 17 | FakeWeb.allow_net_connect = false 18 | end 19 | 20 | config.after :suite do 21 | FakeWeb.allow_net_connect = true 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/stubs/account/create: -------------------------------------------------------------------------------- 1 | HTTP/1.1 201 Created 2 | Status: 201 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "id": 1, 7 | "email": "arthur@dent.com", 8 | "domain": null, 9 | "domain_home_page": null, 10 | "private_items": true, 11 | "subscribed": false, 12 | "alpha": false, 13 | "created_at": "2010-12-10T17:07:01Z", 14 | "updated_at": "2010-12-10T17:07:01Z", 15 | "activated_at": null 16 | } -------------------------------------------------------------------------------- /spec/stubs/account/show: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "id": 1, 7 | "email": "arthur@dent.com", 8 | "domain": null, 9 | "domain_home_page": null, 10 | "private_items": true, 11 | "subscribed": true, 12 | "subscription_expires_at": "2012-05-21", 13 | "alpha": false, 14 | "created_at": "2010-12-10T17:07:01Z", 15 | "updated_at": "2010-12-10T17:12:51Z", 16 | "activated_at": "2010-12-10T17:12:51Z" 17 | } 18 | -------------------------------------------------------------------------------- /spec/stubs/account/stats: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "items": 42, 7 | "views": 31337 8 | } -------------------------------------------------------------------------------- /spec/stubs/account/update: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "id": 1, 7 | "email": "ford@prefect.com", 8 | "domain": "dent.com", 9 | "domain_home_page": "http://hhgproject.org", 10 | "private_items": false, 11 | "subscribed": false, 12 | "alpha": false, 13 | "created_at": "2010-12-10T17:07:01Z", 14 | "updated_at": "2010-12-10T20:33:38Z", 15 | "activated_at": "2010-12-10T17:12:51Z" 16 | } -------------------------------------------------------------------------------- /spec/stubs/drop/create: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "href": "http://my.cl.ly/items/1912565", 7 | "name": "CloudApp", 8 | "private": true, 9 | "url": "http://cl.ly/4febbfdfb185c63d5e14", 10 | "content_url": "http://cl.ly/4febbfdfb185c63d5e14/content", 11 | "item_type": "bookmark", 12 | "view_counter": 0, 13 | "icon": "http://my.cl.ly/images/item_types/bookmark.png", 14 | "remote_url": null, 15 | "redirect_url": "http://getcloudapp.com", 16 | "source": "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)", 17 | "created_at": "2010-10-23T19:50:24Z", 18 | "updated_at": "2010-10-23T19:50:39Z", 19 | "deleted_at": null 20 | } 21 | -------------------------------------------------------------------------------- /spec/stubs/drop/delete: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "href": "http://my.cl.ly/items/1912565", 7 | "name": "CloudApp", 8 | "private": false, 9 | "url": "http://cl.ly/2wt6", 10 | "content_url": "http://cl.ly/2wt6/content", 11 | "item_type": "bookmark", 12 | "view_counter": 0, 13 | "icon": "http://my.cl.ly/images/item_types/bookmark.png", 14 | "remote_url": null, 15 | "redirect_url": "http://getcloudapp.com", 16 | "source": "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)", 17 | "created_at": "2010-10-23T21:15:21Z", 18 | "updated_at": "2010-10-23T21:17:04Z", 19 | "deleted_at": "2010-10-25T14:37:43Z" 20 | } 21 | -------------------------------------------------------------------------------- /spec/stubs/drop/index: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | [{ 6 | "href": "http://my.cl.ly/items/1912729", 7 | "name": "My CloudApp", 8 | "private": true, 9 | "url": "http://cl.ly/40b6ab341aca432a34ee", 10 | "content_url": "http://cl.ly/40b6ab341aca432a34ee/content", 11 | "item_type": "bookmark", 12 | "view_counter": 0, 13 | "icon": "http://my.cl.ly/images/item_types/bookmark.png", 14 | "remote_url": null, 15 | "redirect_url": "http://my.cl.ly", 16 | "source": "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)", 17 | "created_at": "2010-10-23T20:10:37Z", 18 | "updated_at": "2010-10-23T20:10:41Z", 19 | "deleted_at": null 20 | }, { 21 | "href": "http://my.cl.ly/items/1912565", 22 | "name": "CloudApp", 23 | "private": false, 24 | "url": "http://cl.ly/2wt6", 25 | "content_url": "http://cl.ly/2wt6/content", 26 | "item_type": "bookmark", 27 | "view_counter": 2, 28 | "icon": "http://my.cl.ly/images/item_types/bookmark.png", 29 | "remote_url": null, 30 | "redirect_url": "http://getcloudapp.com", 31 | "source": "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)", 32 | "created_at": "2010-10-23T19:50:24Z", 33 | "updated_at": "2010-10-23T19:50:39Z", 34 | "deleted_at": null 35 | }, { 36 | "href": "http://my.cl.ly/items/1912559", 37 | "name": "CloudApp Logo.png", 38 | "private": false, 39 | "url": "http://cl.ly/2wr4", 40 | "content_url": "http://cl.ly/2wr4/content", 41 | "item_type": "image", 42 | "view_counter": 2, 43 | "icon": "http://my.cl.ly/images/item_types/image.png", 44 | "remote_url": "http://f.cl.ly/items/7c7aea1395c3db0aee18/CloudApp%20Logo.png", 45 | "redirect_url": null, 46 | "source": "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)", 47 | "created_at": "2010-10-23T19:50:13Z", 48 | "updated_at": "2010-10-23T19:50:38Z", 49 | "deleted_at": null 50 | }] 51 | -------------------------------------------------------------------------------- /spec/stubs/drop/new: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "uploads_remaining": 10, 7 | "max_upload_size": 26214400, 8 | "url": "http://f.cl.ly", 9 | "params": { 10 | "AWSAccessKeyId": "AKIAIDPUZISHSBEOFS6Q", 11 | "key": "items/qL/${filename}", 12 | "acl": "public-read", 13 | "success_action_redirect": "http://my.cl.ly/items/s3", 14 | "signature": "2vRWmaSy46WGs0MDUdLHAqjSL8k=", 15 | "policy": "eyJleHBpcmF0aW9uIjoiMjAxMC0wNC0wMVQwMDowMDowMFoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJsaW5lYnJlYWstdGVzdCJ9LHsiYWNsIjoicHVibGljLXJlYWQifSx7InN1Y2Nlc3NfYWN0aW9uX3JlZGlyZWN0IjoiaHR0cDovL215LmNsb3VkYXBwLmxvY2FsL3VwbG9hZHMvczMifSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVwbG9hZHMvcUwvIl1dfQ==" 16 | } 17 | } -------------------------------------------------------------------------------- /spec/stubs/drop/new-private: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "uploads_remaining": 10, 7 | "max_upload_size": 26214400, 8 | "url": "http://f.cl.ly", 9 | "params": { 10 | "AWSAccessKeyId": "AKIAIDPUZISHSBEOFS6Q", 11 | "key": "items/qL/${filename}", 12 | "acl": "public-read", 13 | "success_action_redirect": "http://my.cl.ly/items/s3?item[private]=true", 14 | "signature": "2vRWmaSy46WGs0MDUdLHAqjSL8k=", 15 | "policy": "eyJleHBpcmF0aW9uIjoiMjAxMC0wNC0wMVQwMDowMDowMFoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJsaW5lYnJlYWstdGVzdCJ9LHsiYWNsIjoicHVibGljLXJlYWQifSx7InN1Y2Nlc3NfYWN0aW9uX3JlZGlyZWN0IjoiaHR0cDovL215LmNsb3VkYXBwLmxvY2FsL3VwbG9hZHMvczMifSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVwbG9hZHMvcUwvIl1dfQ==" 16 | } 17 | } -------------------------------------------------------------------------------- /spec/stubs/drop/show: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "href": "http://my.cl.ly/items/1912559", 7 | "name": "CloudApp Logo.png", 8 | "private": false, 9 | "url": "http://cl.ly/2wr4", 10 | "content_url": "http://cl.ly/2wr4/CloudApp_Logo.png", 11 | "item_type": "image", 12 | "view_counter": 42, 13 | "icon": "http://my.cl.ly/images/item_types/image.png", 14 | "remote_url": "http://f.cl.ly/items/7c7aea1395c3db0aee18/CloudApp%20Logo.png", 15 | "redirect_url": null, 16 | "source": "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)", 17 | "created_at": "2010-10-23T19:50:13Z", 18 | "updated_at": "2010-10-23T19:50:38Z", 19 | "deleted_at": null 20 | } 21 | -------------------------------------------------------------------------------- /spec/stubs/drop/show-private: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "href": "http://my.cl.ly/items/1912559", 7 | "name": "CloudApp Logo.png", 8 | "private": true, 9 | "url": "http://cl.ly/2wr4", 10 | "content_url": "http://cl.ly/2wr4/CloudApp_Logo.png", 11 | "item_type": "image", 12 | "view_counter": 42, 13 | "icon": "http://my.cl.ly/images/item_types/image.png", 14 | "remote_url": "http://f.cl.ly/items/7c7aea1395c3db0aee18/CloudApp%20Logo.png", 15 | "redirect_url": null, 16 | "source": "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)", 17 | "created_at": "2010-10-23T19:50:13Z", 18 | "updated_at": "2010-10-23T19:50:38Z", 19 | "deleted_at": null 20 | } 21 | -------------------------------------------------------------------------------- /spec/stubs/drop/update: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "href": "http://my.cl.ly/items/1912565", 7 | "name": "CloudApp", 8 | "private": false, 9 | "url": "http://cl.ly/2wt6", 10 | "content_url": "http://cl.ly/2wt6/content", 11 | "item_type": "bookmark", 12 | "view_counter": 0, 13 | "icon": "http://my.cl.ly/images/item_types/bookmark.png", 14 | "remote_url": null, 15 | "redirect_url": "http://getcloudapp.com", 16 | "source": "Cloud/1.5.1 CFNetwork/520.0.13 Darwin/11.0.0 (x86_64) (MacBookPro5%2C5)", 17 | "created_at": "2010-10-23T21:15:21Z", 18 | "updated_at": "2010-10-23T21:17:04Z", 19 | "deleted_at": null 20 | } 21 | -------------------------------------------------------------------------------- /spec/stubs/error/400: -------------------------------------------------------------------------------- 1 | HTTP/1.1 400 Bad Request 2 | Status: 400 3 | Content-Type: application/xml 4 | 5 | 6 | MalformedPOSTRequestThe body of your POST request is not well-formed multipart/form-data.1BD4C1A789889BA49i/ZNBBvYD+KKoHBRUU6/9uqu/0XvFkNmvBiiLhn/hEZXOes/xVRrHim//JC9mmi -------------------------------------------------------------------------------- /spec/stubs/error/401: -------------------------------------------------------------------------------- 1 | HTTP/1.1 401 Unauthorized 2 | Status: 401 3 | Content-Type: text/plain; charset=utf-8 4 | 5 | HTTP Digest: "Access denied." -------------------------------------------------------------------------------- /spec/stubs/error/404-find: -------------------------------------------------------------------------------- 1 | HTTP/1.1 404 Not Found 2 | Status: 404 3 | Content-Type: text/html; charset=utf-8 4 | 5 |

Not Found

-------------------------------------------------------------------------------- /spec/stubs/error/404-update: -------------------------------------------------------------------------------- 1 | HTTP/1.1 404 Not Found 2 | Status: 404 3 | Content-Type: text/html; charset=utf-8 4 | 5 | 6 | 7 | 8 | The page you were looking for doesn't exist (404) 9 | 21 | 22 | 23 | 24 | 25 |
26 |

The page you were looking for doesn't exist.

27 |

You may have mistyped the address or the page may have moved.

28 |
29 | 30 | -------------------------------------------------------------------------------- /spec/stubs/error/422-bookmark: -------------------------------------------------------------------------------- 1 | HTTP/1.1 422 2 | Status: 422 3 | Content-Type: application/json; charset=utf-8 4 | 5 | ["URL can't be blank"] -------------------------------------------------------------------------------- /spec/stubs/error/422-bookmarks: -------------------------------------------------------------------------------- 1 | HTTP/1.1 422 2 | Status: 422 3 | Content-Type: application/json; charset=utf-8 4 | 5 | [["URL can't be blank"]] -------------------------------------------------------------------------------- /spec/stubs/gift_card/redeem: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "id": 1, 7 | "code": "ABC123", 8 | "plan": "pro", 9 | "months": 12, 10 | "href": "https://my.cl.ly/gift_cards/ABC123", 11 | "created_at": "2011-01-08T20:11:26Z", 12 | "updated_at": "2011-01-08T21:26:26Z", 13 | "redeemed_at": "2011-01-08T21:26:26Z", 14 | "effective_at": "2011-01-10", 15 | "expires_at": "2012-01-10" 16 | } -------------------------------------------------------------------------------- /spec/stubs/gift_card/show: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Status: 200 3 | Content-Type: application/json; charset=utf-8 4 | 5 | { 6 | "id": 1, 7 | "code": "ABC123", 8 | "plan": "pro", 9 | "months": 12, 10 | "href": "https://my.cl.ly/gift_cards/ABC123", 11 | "created_at": "2011-01-08T20:11:26Z", 12 | "updated_at": "2011-01-08T20:11:26Z", 13 | "redeemed_at": null, 14 | "effective_at": null, 15 | "expires_at": null 16 | } --------------------------------------------------------------------------------