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.
- data/.gitignore +2 -0
- data/.travis.yml +9 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +46 -0
- data/MIT-LICENSE +20 -0
- data/README.md +89 -0
- data/Rakefile +14 -0
- data/autotest/discover.rb +1 -0
- data/examples/config_initializers_highrise.rb +4 -0
- data/examples/extending.rb +31 -0
- data/examples/sample.rb +9 -0
- data/highrise.gemspec +33 -0
- data/lib/highrise/account.rb +7 -0
- data/lib/highrise/base.rb +25 -0
- data/lib/highrise/comment.rb +3 -0
- data/lib/highrise/company.rb +15 -0
- data/lib/highrise/deal.rb +8 -0
- data/lib/highrise/deal_category.rb +3 -0
- data/lib/highrise/email.rb +9 -0
- data/lib/highrise/group.rb +3 -0
- data/lib/highrise/kase.rb +19 -0
- data/lib/highrise/membership.rb +3 -0
- data/lib/highrise/note.rb +9 -0
- data/lib/highrise/pagination.rb +72 -0
- data/lib/highrise/party.rb +11 -0
- data/lib/highrise/person.rb +45 -0
- data/lib/highrise/recording.rb +5 -0
- data/lib/highrise/rfc822.rb +30 -0
- data/lib/highrise/searchable.rb +23 -0
- data/lib/highrise/subject.rb +31 -0
- data/lib/highrise/tag.rb +12 -0
- data/lib/highrise/taggable.rb +20 -0
- data/lib/highrise/task.rb +11 -0
- data/lib/highrise/task_category.rb +3 -0
- data/lib/highrise/user.rb +17 -0
- data/lib/highrise/version.rb +3 -0
- data/lib/highrise.rb +22 -0
- data/spec/highrise/account_spec.rb +10 -0
- data/spec/highrise/base_spec.rb +48 -0
- data/spec/highrise/comment_spec.rb +5 -0
- data/spec/highrise/company_spec.rb +17 -0
- data/spec/highrise/deal_category_spec.rb +13 -0
- data/spec/highrise/deal_spec.rb +23 -0
- data/spec/highrise/email_spec.rb +13 -0
- data/spec/highrise/group_spec.rb +5 -0
- data/spec/highrise/kase_spec.rb +17 -0
- data/spec/highrise/membership_spec.rb +5 -0
- data/spec/highrise/note_spec.rb +14 -0
- data/spec/highrise/pagination_behavior.rb +50 -0
- data/spec/highrise/pagination_spec.rb +8 -0
- data/spec/highrise/party_spec.rb +16 -0
- data/spec/highrise/person_spec.rb +33 -0
- data/spec/highrise/recording_spec.rb +7 -0
- data/spec/highrise/searchable_behavior.rb +13 -0
- data/spec/highrise/searchable_spec.rb +8 -0
- data/spec/highrise/subject_spec.rb +34 -0
- data/spec/highrise/tag_spec.rb +18 -0
- data/spec/highrise/taggable_behavior.rb +27 -0
- data/spec/highrise/taggable_spec.rb +9 -0
- data/spec/highrise/task_category_spec.rb +13 -0
- data/spec/highrise/task_spec.rb +11 -0
- data/spec/highrise/user_spec.rb +18 -0
- data/spec/spec_helper.rb +11 -0
- metadata +182 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
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) [](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,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
|
data/examples/sample.rb
ADDED
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,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,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,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,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
|
data/lib/highrise/tag.rb
ADDED
@@ -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
|