peterosullivan-highrise 3.0.2

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.
Files changed (64) hide show
  1. data/.gitignore +2 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +46 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +89 -0
  7. data/Rakefile +14 -0
  8. data/autotest/discover.rb +1 -0
  9. data/examples/config_initializers_highrise.rb +4 -0
  10. data/examples/extending.rb +31 -0
  11. data/examples/sample.rb +9 -0
  12. data/highrise.gemspec +33 -0
  13. data/lib/highrise/account.rb +7 -0
  14. data/lib/highrise/base.rb +25 -0
  15. data/lib/highrise/comment.rb +3 -0
  16. data/lib/highrise/company.rb +15 -0
  17. data/lib/highrise/deal.rb +8 -0
  18. data/lib/highrise/deal_category.rb +3 -0
  19. data/lib/highrise/email.rb +9 -0
  20. data/lib/highrise/group.rb +3 -0
  21. data/lib/highrise/kase.rb +19 -0
  22. data/lib/highrise/membership.rb +3 -0
  23. data/lib/highrise/note.rb +9 -0
  24. data/lib/highrise/pagination.rb +72 -0
  25. data/lib/highrise/party.rb +11 -0
  26. data/lib/highrise/person.rb +45 -0
  27. data/lib/highrise/recording.rb +5 -0
  28. data/lib/highrise/rfc822.rb +30 -0
  29. data/lib/highrise/searchable.rb +23 -0
  30. data/lib/highrise/subject.rb +31 -0
  31. data/lib/highrise/tag.rb +12 -0
  32. data/lib/highrise/taggable.rb +20 -0
  33. data/lib/highrise/task.rb +11 -0
  34. data/lib/highrise/task_category.rb +3 -0
  35. data/lib/highrise/user.rb +17 -0
  36. data/lib/highrise/version.rb +3 -0
  37. data/lib/highrise.rb +22 -0
  38. data/spec/highrise/account_spec.rb +10 -0
  39. data/spec/highrise/base_spec.rb +48 -0
  40. data/spec/highrise/comment_spec.rb +5 -0
  41. data/spec/highrise/company_spec.rb +17 -0
  42. data/spec/highrise/deal_category_spec.rb +13 -0
  43. data/spec/highrise/deal_spec.rb +23 -0
  44. data/spec/highrise/email_spec.rb +13 -0
  45. data/spec/highrise/group_spec.rb +5 -0
  46. data/spec/highrise/kase_spec.rb +17 -0
  47. data/spec/highrise/membership_spec.rb +5 -0
  48. data/spec/highrise/note_spec.rb +14 -0
  49. data/spec/highrise/pagination_behavior.rb +50 -0
  50. data/spec/highrise/pagination_spec.rb +8 -0
  51. data/spec/highrise/party_spec.rb +16 -0
  52. data/spec/highrise/person_spec.rb +33 -0
  53. data/spec/highrise/recording_spec.rb +7 -0
  54. data/spec/highrise/searchable_behavior.rb +13 -0
  55. data/spec/highrise/searchable_spec.rb +8 -0
  56. data/spec/highrise/subject_spec.rb +34 -0
  57. data/spec/highrise/tag_spec.rb +18 -0
  58. data/spec/highrise/taggable_behavior.rb +27 -0
  59. data/spec/highrise/taggable_spec.rb +9 -0
  60. data/spec/highrise/task_category_spec.rb +13 -0
  61. data/spec/highrise/task_spec.rb +11 -0
  62. data/spec/highrise/user_spec.rb +18 -0
  63. data/spec/spec_helper.rb +11 -0
  64. metadata +182 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg/**
2
+ .rvmrc
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.8.7
4
+ - ree-1.8.7
5
+ - 1.8.7-p249
6
+ - jruby
7
+ # branches:
8
+ # only:
9
+ # - master
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ highrise (3.0.1)
5
+ activeresource (~> 3.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activemodel (3.1.0)
11
+ activesupport (= 3.1.0)
12
+ bcrypt-ruby (~> 3.0.0)
13
+ builder (~> 3.0.0)
14
+ i18n (~> 0.6)
15
+ activeresource (3.1.0)
16
+ activemodel (= 3.1.0)
17
+ activesupport (= 3.1.0)
18
+ activesupport (3.1.0)
19
+ multi_json (~> 1.0)
20
+ bcrypt-ruby (3.0.0)
21
+ bcrypt-ruby (3.0.0-java)
22
+ builder (3.0.0)
23
+ diff-lcs (1.1.2)
24
+ i18n (0.6.0)
25
+ multi_json (1.0.3)
26
+ rake (0.8.7)
27
+ rspec (2.0.1)
28
+ rspec-core (~> 2.0.1)
29
+ rspec-expectations (~> 2.0.1)
30
+ rspec-mocks (~> 2.0.1)
31
+ rspec-core (2.0.1)
32
+ rspec-expectations (2.0.1)
33
+ diff-lcs (>= 1.1.2)
34
+ rspec-mocks (2.0.1)
35
+ rspec-core (~> 2.0.1)
36
+ rspec-expectations (~> 2.0.1)
37
+
38
+ PLATFORMS
39
+ java
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ activeresource (~> 3.0)
44
+ highrise!
45
+ rake (= 0.8.7)
46
+ rspec (~> 2.0.1)
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Ken Mayer & Marcos Tapajos
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.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ ##whats in this fork
2
+
3
+ This fork is very close to the orginal gem. I have added a few features and shortcut methods;
4
+
5
+
6
+ Highrise::Tag.delete_by_name('tag_name')
7
+
8
+ Highrise::Person.url_for(123)
9
+ Highrise::Person.find(123).tagged?('tag_name')
10
+ Highrise::Person.find(123).email_address
11
+ Highrise::Person.find(123).email_valid?
12
+ Highrise::Person.find(123).phone_number
13
+
14
+ # Highrise (3.0.0) [![Build Status](https://secure.travis-ci.org/tapajos/highrise.png)](http://travis-ci.org/tapajos/highrise)
15
+
16
+ ## What is it?
17
+
18
+ This gem provides a set of classes to access information on [Highrise][h] via the published [API][api]:
19
+
20
+ Account, Comment, Company, Deal, DealCategory, Email, Group, Case, Membership, Note, Party, Person, Recording, Subject, Tag, Task, TaskCategory and User.
21
+
22
+ All these classes are inherited from ActiveResouce::Base. Refer to the [ActiveResouce][ar] documentation for more information.
23
+
24
+ ## Installing
25
+
26
+ gem install peterosullivan-highrise
27
+
28
+ ### Dependencies (see <code>highrise.gemspec</code> or run <code>bundle check</code>)
29
+
30
+ ### Documentation
31
+
32
+ I'm on [rdoc.info][rdoc]
33
+
34
+ ### Configure your key
35
+
36
+ require 'highrise'
37
+
38
+ Highrise::Base.site = 'https://your_site.highrisehq.com'
39
+ Highrise::Base.user = 'api-auth-token'
40
+
41
+ If you are using this in a Rails application, putting this code in a config/initializers/highrise.rb
42
+ file is recommended. See config_initializers_highrise.rb in the examples/ directory.
43
+
44
+ ## Usage
45
+
46
+ @tags = Highrise::Tag.find(:all)
47
+
48
+ @people = Highrise::Person.find_all_across_pages(:params => {:tag_id => 12345})
49
+
50
+ @person.tag!("VIP")
51
+
52
+ ## License
53
+
54
+ This code is free to be used under the terms of the [MIT license][mit].
55
+
56
+ ## Bugs, Issues, Kudos and Catcalls
57
+
58
+ Comments are welcome. Send your feedback through the [issue tracker on GitHub][i]
59
+
60
+ If you have fixes: Submit via pull requests. Do not include version changes to the
61
+ version file.
62
+
63
+ ## Authors
64
+
65
+ * [Marcos Tapajós][tapajos]
66
+ * [Ken Mayer][kmayer]
67
+
68
+ ## Contributors
69
+
70
+ * [Nicolas Bianco][slainer86]
71
+ * [Luis Gustavo][luisbebop]
72
+ * [Thiago Lelis][ThiagoLelis]
73
+ * [Denis Odorcic][odorcicd]
74
+
75
+
76
+
77
+ [api]: http://developer.37signals.com/highrise
78
+ [ar]: http://api.rubyonrails.org/classes/ActiveResource/Base.html
79
+ [c]: http://api.rubyonrails.org/classes/ActiveSupport/Cache
80
+ [h]: http://www.highrisehq.com/
81
+ [i]: https://github.com/tapajos/highrise/issues
82
+ [kmayer]: https://github.com/kmayer
83
+ [luisbebop]: https://github.com/luisbebop
84
+ [mit]:http://www.opensource.org/licenses/mit-license.php
85
+ [slainer86]: https://github.com/slainer86
86
+ [odorcicd]: https://github.com/odorcicd
87
+ [rdoc]: http://rdoc.info/projects/tapajos/highrise
88
+ [tapajos]: http://www.improveit.com.br/en/company/tapajos
89
+ [ThiagoLelis]: https://github.com/ThiagoLelis
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ require 'bundler'
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require 'rspec/core/rake_task'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :spec
9
+
10
+ desc "Run all specs"
11
+ RSpec::Core::RakeTask.new do |t|
12
+ t.pattern = 'spec/**/*_spec.rb'
13
+ t.rspec_opts = ["-c", "-f progress"]
14
+ end
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
@@ -0,0 +1,4 @@
1
+ if Rails.env != 'test' then
2
+ Highrise::Base.site = 'https://example.com.i'
3
+ Highrise::Base.user = 'my_fancy_auth_token'
4
+ end
@@ -0,0 +1,31 @@
1
+ #
2
+ # Example of extending a class when you need to synthesize an attribute.
3
+ #
4
+ # Adds Highrise::Person.{phone,fax,email} to the Person class inside your
5
+ # module
6
+ #
7
+
8
+ module MyModule
9
+ include Highrise
10
+
11
+ Highrise::Person.class_eval do
12
+ class << self
13
+ def lookup(id, list, item, location)
14
+ module_eval <<-EOT
15
+ def #{id}
16
+ contact_data.#{list}.each do |i|
17
+ return i.#{item}.strip if i.location == "#{location}"
18
+ end
19
+ ''
20
+ end
21
+ EOT
22
+ end
23
+
24
+ private :lookup
25
+ end
26
+
27
+ lookup(:phone, 'phone_numbers', 'number', 'Work')
28
+ lookup(:fax, 'phone_numbers', 'number', 'Fax')
29
+ lookup(:email, 'email_addresses', 'address', 'Work')
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ require 'highrise'
2
+ require 'pp'
3
+
4
+ Highrise::Base.site = 'https://yoursite.highrisehq.com'
5
+ Highrise::Base.user = 'xxx'
6
+
7
+ @tags = Highrise::Tag.find(:all)
8
+
9
+ pp @tags
data/highrise.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "highrise/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "peterosullivan-highrise"
7
+ s.version = Highrise::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+
10
+ s.required_rubygems_version = ">= 1.3.6"
11
+ s.add_dependency "activeresource", "~>3.0"
12
+ s.add_development_dependency "rspec", "~>2.0.1"
13
+ s.add_development_dependency "rake", "=0.8.7"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features,examples}/*`.split("\n")
17
+ s.require_paths = ["lib"]
18
+
19
+ s.authors = ["Marcos Tapaj\303\263s", "Ken Mayer", "Peter O'Sullivan"]
20
+ s.email = ["marcos@tapajos.me", "kmayer@bitwrangler.com", "peter@peterosullivan.net"]
21
+ s.homepage = "https://github.com/peterosullivan/highrise"
22
+ s.summary = %q{Ruby wrapper around Highrise API}
23
+ s.description = <<-EOT
24
+ Based on the original API module from DHH, http://developer.37signals.com/highrise/, this
25
+ gem is a cleaned up, tested version of the same. A fork of Tapaj gem. See the homepage for add features.
26
+
27
+ Configure by adding the following:
28
+
29
+ require 'highrise'
30
+ Highrise::Base.site = 'http://your_site.highrisehq.com/'
31
+ Highrise::Base.user = 'your_api_auth_token'
32
+ EOT
33
+ end
@@ -0,0 +1,7 @@
1
+ module Highrise
2
+ class Account < Base
3
+ def self.me
4
+ find(:one, :from => "/account.xml")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_resource'
2
+
3
+ module Highrise
4
+ class Base < ActiveResource::Base
5
+
6
+ def self.url_for(n)
7
+ base = site.to_s.split('@')[1]
8
+ File.join('https://', base, element_path(n)).gsub(".xml",'')
9
+ end
10
+
11
+ protected
12
+ # Dynamic finder for attributes
13
+ def self.method_missing(method, *args)
14
+ if method.to_s =~ /^find_(all_)?by_([_a-zA-Z]\w*)$/
15
+ raise ArgumentError, "Dynamic finder method must take an argument." if args.empty?
16
+ options = args.extract_options!
17
+ resources = respond_to?(:find_all_across_pages) ? send(:find_all_across_pages, options) : send(:find, :all)
18
+ resources.send($1 == 'all_' ? 'select' : 'detect') { |container| container.send($2) == args.first }
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Highrise
2
+ class Comment < Base; end
3
+ end
@@ -0,0 +1,15 @@
1
+ module Highrise
2
+ class Company < Subject
3
+ include Pagination
4
+ include Taggable
5
+ include Searchable
6
+
7
+ def people
8
+ Person.find_all_across_pages(:from => "/companies/#{id}/people.xml")
9
+ end
10
+
11
+ def label
12
+ 'Party'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ module Highrise
2
+ class Deal < Subject
3
+ def update_status(status)
4
+ raise ArgumentError, "status must be one of 'pending', 'won', or 'lost'" unless %w[pending won lost].include?(status)
5
+ self.put(:status, :status => {:name => status})
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module Highrise
2
+ class DealCategory < Base; end
3
+ end
@@ -0,0 +1,9 @@
1
+ module Highrise
2
+ class Email < Base
3
+ include Pagination
4
+
5
+ def comments
6
+ Comment.find(:all, :from => "/emails/#{email_id}/comments.xml")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Highrise
2
+ class Group < Base; end
3
+ end
@@ -0,0 +1,19 @@
1
+ module Highrise
2
+ class Kase < Subject
3
+ def open!
4
+ update_attribute(:closed_at, nil)
5
+ end
6
+
7
+ def close!
8
+ update_attribute(:closed_at, Time.now.utc)
9
+ end
10
+
11
+ def self.open
12
+ Kase.find(:all, :from => "/kases/open.xml")
13
+ end
14
+
15
+ def self.closed
16
+ Kase.find(:all, :from => "/kases/closed.xml")
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Highrise
2
+ class Membership < Base; end
3
+ end
@@ -0,0 +1,9 @@
1
+ module Highrise
2
+ class Note < Base
3
+ include Pagination
4
+
5
+ def comments
6
+ Comment.find(:all, :from => "/notes/#{id}/comments.xml")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,72 @@
1
+ module Highrise
2
+ module Pagination
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def find_all_across_pages(options = {})
9
+ records = []
10
+ each(options) { |record| records << record }
11
+ records
12
+ end
13
+
14
+ # This only is usefull for company, person & recordings, but should be safely ignored by other classes
15
+ def find_all_across_pages_since(time)
16
+ find_all_across_pages(:params => { :since => time.utc.strftime("%Y%m%d%H%M%S") })
17
+ end
18
+
19
+ # This is useful only for Company, Person, Note, Comment, Email and Task, but should be safely ignored by other classes
20
+ def find_all_deletions_across_pages(options = {})
21
+ # point to the global deletions feed
22
+ options[:from] = '/deletions.xml'
23
+
24
+ records = []
25
+ each_deletions(options) { |record| records << record }
26
+ records
27
+ end
28
+
29
+ # This is useful only for Company, Person, Note, Comment, Email and Task, but should be safely ignored by other classes
30
+ def find_all_deletions_across_pages_since(time)
31
+ find_all_deletions_across_pages(:params => { :since => time.utc.strftime("%Y%m%d%H%M%S") })
32
+ end
33
+
34
+ private
35
+
36
+ def each(options = {})
37
+ options[:params] ||= {}
38
+ options[:params][:n] = 0
39
+
40
+ loop do
41
+ if (records = self.find(:all, options)).try(:any?)
42
+ records.each { |record| yield record }
43
+ options[:params][:n] += records.size
44
+ else
45
+ break # no people included on that page, thus no more people total
46
+ end
47
+ end
48
+ end
49
+
50
+ def each_deletions(options = {})
51
+ options[:params] ||= {}
52
+ # first index for deletions is 1
53
+ options[:params][:n] = 1
54
+
55
+ loop do
56
+ if (records = self.find(:all, options)).try(:any?)
57
+ # reject the records whose resource type is different from self
58
+ records.reject!{|r| r.class.to_s.split('::').last != self.to_s.split('::').last}
59
+
60
+ records.each{ |record| yield record }
61
+
62
+ # index increment for deletions is 1 per page of 500 resources
63
+ options[:params][:n] += 1
64
+ else
65
+ break # no deletions included on that page, thus no more deletions
66
+ end
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,11 @@
1
+ module Highrise
2
+ class Party < Base
3
+ def self.recently_viewed
4
+ find(:all, :from => "/parties/recently_viewed.xml")
5
+ end
6
+
7
+ def self.deletions_since(time)
8
+ find(:all, :from => "/parties/deletions.xml", :params => { :since => time.utc.strftime("%Y%m%d%H%M%S") })
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ module Highrise
2
+ class Person < Subject
3
+ require 'highrise/rfc822'
4
+ include Pagination
5
+ include Taggable
6
+ include Searchable
7
+
8
+ def company
9
+ Company.find(company_id) if company_id
10
+ end
11
+
12
+ def name
13
+ "#{first_name rescue ''} #{last_name rescue ''}".strip
14
+ end
15
+
16
+ def address
17
+ contact_data.addresses.first
18
+ end
19
+
20
+ def web_address
21
+ contact_data.web_addresses.first
22
+ end
23
+
24
+ def label
25
+ 'Party'
26
+ end
27
+
28
+ def phone_number
29
+ contact_data.phone_numbers.first.number rescue nil
30
+ end
31
+
32
+ def email_valid?
33
+ !!(email_address && (email_address =~ RFC822::EmailAddress))
34
+ end
35
+
36
+ def email_address
37
+ contact_data.email_addresses.first.address rescue nil
38
+ end
39
+
40
+ def tagged? name
41
+ tags.any?{ | tag | tag['name'].to_s == name}
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ module Highrise
2
+ class Recording < Base
3
+ include Pagination
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ #
2
+ # RFC822 Email Address Regex
3
+ # --------------------------
4
+ #
5
+ # Originally written by Cal Henderson
6
+ # c.f. http://iamcal.com/publish/articles/php/parsing_email/
7
+ #
8
+ # Translated to Ruby by Tim Fletcher, with changes suggested by Dan Kubb.
9
+ #
10
+ # Licensed under a Creative Commons Attribution-ShareAlike 2.5 License
11
+ # http://creativecommons.org/licenses/by-sa/2.5/
12
+ #
13
+ module RFC822
14
+ EmailAddress = begin
15
+ qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'
16
+ dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]'
17
+ atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-' +
18
+ '\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+'
19
+ quoted_pair = '\\x5c[\\x00-\\x7f]'
20
+ domain_literal = "\\x5b(?:#{dtext}|#{quoted_pair})*\\x5d"
21
+ quoted_string = "\\x22(?:#{qtext}|#{quoted_pair})*\\x22"
22
+ domain_ref = atom
23
+ sub_domain = "(?:#{domain_ref}|#{domain_literal})"
24
+ word = "(?:#{atom}|#{quoted_string})"
25
+ domain = "#{sub_domain}(?:\\x2e#{sub_domain})*"
26
+ local_part = "#{word}(?:\\x2e#{word})*"
27
+ addr_spec = "#{local_part}\\x40#{domain}"
28
+ pattern = /\A#{addr_spec}\z/
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ module Highrise
2
+ module Searchable
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ # List By Search Criteria
9
+ # Ex: Highrise::Person.search(:email => "john.doe@example.com", :country => "CA")
10
+ # Available criteria are: city, state, country, zip, phone, email
11
+ def search(options = {})
12
+ raise ArgumentError, "cannot convert #{options}:#{options.class} to hash" if options.kind_of?(String)
13
+ search_params = options.inject({}) { |h, (k, v)| h["criteria[#{k}]"] = v; h }
14
+ # This might have to be changed in the future if other non-pagable resources become searchable
15
+ if self.respond_to?(:find_all_across_pages)
16
+ self.find_all_across_pages(:from => "/#{self.collection_name}/search.xml", :params => search_params)
17
+ else
18
+ self.find(:all, {:from => "/#{self.collection_name}/search.xml", :params => search_params})
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ module Highrise
2
+ class Subject < Base
3
+ def notes
4
+ Note.find_all_across_pages(:from => "/#{self.class.collection_name}/#{id}/notes.xml")
5
+ end
6
+
7
+ def add_note(attrs={})
8
+ attrs[:subject_id] = self.id
9
+ attrs[:subject_type] = self.label
10
+ Note.create attrs
11
+ end
12
+
13
+ def add_task(attrs={})
14
+ attrs[:subject_id] = self.id
15
+ attrs[:subject_type] = self.label
16
+ Task.create attrs
17
+ end
18
+
19
+ def emails
20
+ Email.find_all_across_pages(:from => "/#{self.class.collection_name}/#{id}/emails.xml")
21
+ end
22
+
23
+ def upcoming_tasks
24
+ Task.find(:all, :from => "/#{self.class.collection_name}/#{id}/tasks.xml")
25
+ end
26
+
27
+ def label
28
+ self.class.name.split('::').last
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ module Highrise
2
+ class Tag < Base
3
+ def ==(object)
4
+ (object.instance_of?(self.class) && object.id == self.id && object.name == self.name)
5
+ end
6
+
7
+ def self.delete_by_name(name)
8
+ tag = find_by_name(name)
9
+ tag.destroy if tag
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ module Highrise
2
+ module Taggable
3
+ def tags
4
+ self.get(:tags)
5
+ end
6
+
7
+ def tag!(tag_name)
8
+ self.post(:tags, :name => tag_name) unless tag_name.blank?
9
+ end
10
+
11
+ def untag!(tag_name)
12
+ to_delete = self.tags.find{|tag| tag['name'] == tag_name} unless tag_name.blank?
13
+ self.untag_id!(to_delete['id']) unless to_delete.nil?
14
+ end
15
+ protected
16
+ def untag_id!(tag_id)
17
+ self.delete("tags/#{tag_id}")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module Highrise
2
+ class Task < Base
3
+ # find(:all, :from => :upcoming)
4
+ # find(:all, :from => :assigned)
5
+ # find(:all, :from => :completed)
6
+
7
+ def complete!
8
+ load_attributes_from_response(post(:complete))
9
+ end
10
+ end
11
+ end