kmayer-highrise 0.7.0
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/MIT-LICENSE +20 -0
- data/README.mkdn +69 -0
- data/Rakefile +68 -0
- data/lib/highrise/base.rb +4 -0
- data/lib/highrise/comment.rb +4 -0
- data/lib/highrise/company.rb +14 -0
- data/lib/highrise/curlhelper.rb +27 -0
- data/lib/highrise/curly.rb +96 -0
- data/lib/highrise/email.rb +9 -0
- data/lib/highrise/group.rb +4 -0
- data/lib/highrise/kase.rb +8 -0
- data/lib/highrise/membership.rb +4 -0
- data/lib/highrise/note.rb +9 -0
- data/lib/highrise/pagination.rb +29 -0
- data/lib/highrise/person.rb +20 -0
- data/lib/highrise/subject.rb +15 -0
- data/lib/highrise/tag.rb +7 -0
- data/lib/highrise/taggable.rb +29 -0
- data/lib/highrise/task.rb +11 -0
- data/lib/highrise/user.rb +7 -0
- data/lib/highrise/version.rb +9 -0
- data/lib/highrise.rb +26 -0
- data/spec/highrise/base_spec.rb +13 -0
- data/spec/highrise/comment_spec.rb +14 -0
- data/spec/highrise/companies/16883216.html +1723 -0
- data/spec/highrise/company_spec.rb +70 -0
- data/spec/highrise/curlhelper_spec.rb +35 -0
- data/spec/highrise/curly_spec.rb +36 -0
- data/spec/highrise/email_spec.rb +25 -0
- data/spec/highrise/group_spec.rb +14 -0
- data/spec/highrise/kase_spec.rb +25 -0
- data/spec/highrise/membership_spec.rb +14 -0
- data/spec/highrise/note_spec.rb +23 -0
- data/spec/highrise/pagination_spec.rb +7 -0
- data/spec/highrise/people/16887003.html +1733 -0
- data/spec/highrise/person_spec.rb +83 -0
- data/spec/highrise/subject_spec.rb +43 -0
- data/spec/highrise/tag_spec.rb +21 -0
- data/spec/highrise/task_spec.rb +23 -0
- data/spec/highrise/user_spec.rb +30 -0
- data/spec.opts +7 -0
- data/spec_helper.rb +20 -0
- metadata +99 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [name of plugin creator]
|
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.mkdn
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Highrise
|
2
|
+
|
3
|
+
## What
|
4
|
+
|
5
|
+
[Highrise][h] is a gem that provides an easy way to use the [Highrise API][api].
|
6
|
+
|
7
|
+
## Installing
|
8
|
+
|
9
|
+
gem install kmayer-highrise
|
10
|
+
|
11
|
+
## Dependencies
|
12
|
+
|
13
|
+
* ActiveResorce >= 2.2.2
|
14
|
+
* ActiveSupport >= 2.1
|
15
|
+
* Curb
|
16
|
+
* Hpricot
|
17
|
+
|
18
|
+
## Configure your key.
|
19
|
+
|
20
|
+
require 'rubygems'
|
21
|
+
require 'highrise'
|
22
|
+
Highrise::Base.site = 'http://your_api:login@your_site.highrisehq.com/'
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
This gem provides a set of classes to access all available informations on [Highrise][h].
|
27
|
+
|
28
|
+
These are the list of classes:
|
29
|
+
|
30
|
+
Comment, Company, Email, Group, Case, Membership, Note, Person, Subject, Tag, Task and User.
|
31
|
+
|
32
|
+
All these classes are inherited of ActiveResouce::Base. For more informations see the ActiveResouce documentation.
|
33
|
+
|
34
|
+
## License
|
35
|
+
|
36
|
+
This code is free to be used under the terms of the [MIT license][mit].
|
37
|
+
|
38
|
+
## Contact
|
39
|
+
|
40
|
+
Comments are welcome. Send your feedback through [this page][co]
|
41
|
+
|
42
|
+
## Authors
|
43
|
+
|
44
|
+
[Marcos Tapajós][mt]
|
45
|
+
|
46
|
+
## Contributors
|
47
|
+
|
48
|
+
* [Nicolas Bianco][nb]
|
49
|
+
* [Luis Gustavo][lg]
|
50
|
+
* [Thiago Lelis][tl]
|
51
|
+
* [Ken Mayer][km]
|
52
|
+
|
53
|
+
## Shameless advertisement
|
54
|
+
|
55
|
+
(From the original author) This plugin is brought to you by [Improve It][ii].
|
56
|
+
|
57
|
+
[![Improve It][logo]][ii]
|
58
|
+
|
59
|
+
[logo]:http://www.improveit.com.br/images/logo/logo_improve_it_screen.gif "Improve It"
|
60
|
+
[mt]: http://www.improveit.com.br/en/company/tapajos
|
61
|
+
[ii]: http://www.improveit.com.br/en
|
62
|
+
[co]: http://github.com/kmayer
|
63
|
+
[mit]:http://www.opensource.org/licenses/mit-license.php
|
64
|
+
[h]: http://www.highrisehq.com/
|
65
|
+
[km]: http://github.com/kmayer
|
66
|
+
[lg]: http://github.com/luisbebop
|
67
|
+
[nb]: http://github.com/slainer86
|
68
|
+
[tl]: http://github.com/ThiagoLelis
|
69
|
+
[api]: http://developer.37signals.com/highrise
|
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require "date"
|
7
|
+
require "fileutils"
|
8
|
+
require "rubygems"
|
9
|
+
require "rake/gempackagetask"
|
10
|
+
|
11
|
+
require File.join(File.dirname(__FILE__), 'lib', 'highrise', 'version')
|
12
|
+
|
13
|
+
VERSION=Highrise::VERSION::STRING
|
14
|
+
|
15
|
+
highrise_gemspec = Gem::Specification.new do |s|
|
16
|
+
s.name = "highrise"
|
17
|
+
s.version = VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.has_rdoc = true
|
20
|
+
s.extra_rdoc_files = ["README.mkdn"]
|
21
|
+
s.summary = "Ruby wrapper around Highrise API"
|
22
|
+
s.description = %{
|
23
|
+
Based on the original API module from DHH, http://developer.37signals.com/highrise/, this
|
24
|
+
gem is a cleaned up, tested version of the same. Contributors have added support for tags
|
25
|
+
which are not supported by the API directly
|
26
|
+
|
27
|
+
Configure by adding the following:
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'highrise'
|
31
|
+
Highrise::Base.site = 'http://your_api:login@your_site.highrisehq.com/'
|
32
|
+
}
|
33
|
+
s.authors = ["Marcos Tapajós", "Ken Mayer"]
|
34
|
+
s.email = "kmayer@bitwrangler.com"
|
35
|
+
s.homepage = "http://github.com/kmayer/highrise"
|
36
|
+
s.require_path = "lib"
|
37
|
+
s.autorequire = "highrise"
|
38
|
+
s.files = %w(README.mkdn Rakefile MIT-LICENSE spec.opts spec_helper.rb) + Dir.glob("{bin,lib,spec}/**/*")
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::GemPackageTask.new(highrise_gemspec) do |pkg|
|
42
|
+
pkg.gem_spec = highrise_gemspec
|
43
|
+
end
|
44
|
+
|
45
|
+
namespace :gem do
|
46
|
+
namespace :spec do
|
47
|
+
desc "Update highrise.gemspec"
|
48
|
+
task :generate do
|
49
|
+
File.open("highrise.gemspec", "w") do |f|
|
50
|
+
f.puts(highrise_gemspec.to_ruby)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "Instal gem"
|
57
|
+
task :install => :package do
|
58
|
+
sh %{sudo gem install --local pkg/highrise-#{VERSION}}
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'Default: run unit tests.'
|
62
|
+
task :default => :spec
|
63
|
+
|
64
|
+
desc "Run all specs"
|
65
|
+
Spec::Rake::SpecTask.new do |t|
|
66
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
67
|
+
t.spec_opts = ['--options', 'spec.opts']
|
68
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Highrise
|
2
|
+
class Company < Subject
|
3
|
+
include Pagination
|
4
|
+
include Taggable
|
5
|
+
|
6
|
+
def self.find_all_across_pages_since(time)
|
7
|
+
find_all_across_pages(:params => { :since => time.utc.to_s(:db).gsub(/[^\d]/, '') })
|
8
|
+
end
|
9
|
+
|
10
|
+
def people
|
11
|
+
Person.find(:all, :from => "/companies/#{id}/people.xml")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Highrise
|
2
|
+
class CurlHelper
|
3
|
+
|
4
|
+
# thanks mislav ;) http://github.com/mislav/curly/tree/master
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@curly = Curly.new
|
8
|
+
@curly.http_auth_types = Curl::CURLAUTH_BASIC
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_userpwd_from_url(url)
|
12
|
+
userpwd_from_url_regex = /(http|https):\/\/((?:[\w\.\-\+%!$&'\(\)*\+,;=]+:)*[\w\.\-\+%!$&'\(\)*\+,;=]+)?/
|
13
|
+
match = userpwd_from_url_regex.match(url)
|
14
|
+
match.captures[1] unless match.nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_document(url)
|
18
|
+
@curly.userpwd = get_userpwd_from_url(url)
|
19
|
+
@curly.get(url).doc
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_document_from_id(collection_name_and_id)
|
23
|
+
get_document("#{Highrise::Base.site.to_s}#{collection_name_and_id}")
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
class Curly < ActiveSupport::BasicObject
|
2
|
+
attr_reader :uri
|
3
|
+
|
4
|
+
def initialize(uri = nil)
|
5
|
+
@curl = Curl::Easy.new
|
6
|
+
self.uri = uri
|
7
|
+
self.follow_location = true
|
8
|
+
yield self if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def uri=(obj)
|
12
|
+
case obj
|
13
|
+
when String
|
14
|
+
unless @uri
|
15
|
+
@uri = URI.parse(obj)
|
16
|
+
else
|
17
|
+
@uri += obj
|
18
|
+
end
|
19
|
+
when URI::HTTP
|
20
|
+
@uri = obj
|
21
|
+
when nil
|
22
|
+
return
|
23
|
+
else
|
24
|
+
raise "unsupported URI type (#{obj.class.name} given)"
|
25
|
+
end
|
26
|
+
|
27
|
+
self.url = @uri.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(method, *args, &block)
|
31
|
+
@curl.send(method, *args, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def cookiejar=(filename)
|
35
|
+
self.enable_cookies = true
|
36
|
+
@curl.cookiejar = filename
|
37
|
+
end
|
38
|
+
|
39
|
+
def get(uri = nil)
|
40
|
+
self.uri = uri
|
41
|
+
http_get
|
42
|
+
raise "expected 2xx, got #{response_code} (GET #{url})" unless success?
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def success?
|
47
|
+
response_code >= 200 and response_code < 300
|
48
|
+
end
|
49
|
+
|
50
|
+
def doc
|
51
|
+
Hpricot body_unicode
|
52
|
+
end
|
53
|
+
|
54
|
+
def encoding
|
55
|
+
return @encoding unless @encoding == false
|
56
|
+
@encoding = if body_str =~ /;\s*charset=([\w-]+)\s*['"]/
|
57
|
+
$1.downcase
|
58
|
+
else
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def post(params)
|
64
|
+
fields = params.map do |key, value|
|
65
|
+
Curl::PostField.content(key.to_s, value.to_s)
|
66
|
+
end
|
67
|
+
http_post *fields
|
68
|
+
end
|
69
|
+
|
70
|
+
class Form
|
71
|
+
def initialize(element)
|
72
|
+
@node = element
|
73
|
+
end
|
74
|
+
|
75
|
+
def elements
|
76
|
+
@node.search('input, button, select, textarea')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
def body_unicode
|
83
|
+
body = body_str
|
84
|
+
if encoding and encoding != 'utf-8'
|
85
|
+
body = Iconv.conv('UTF-8', encoding, body)
|
86
|
+
end
|
87
|
+
body
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
Hpricot::Doc.class_eval do
|
93
|
+
def forms
|
94
|
+
search('form').map { |f| Curly::Form.new(f) }
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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
|
+
def each(options = {})
|
15
|
+
options[:params] ||= {}
|
16
|
+
options[:params][:n] = 0
|
17
|
+
|
18
|
+
loop do
|
19
|
+
if (records = self.find(:all, options)).any?
|
20
|
+
records.each { |record| yield record }
|
21
|
+
options[:params][:n] += records.size
|
22
|
+
else
|
23
|
+
break # no people included on that page, thus no more people total
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Highrise
|
2
|
+
class Person < Subject
|
3
|
+
include Pagination
|
4
|
+
include Taggable
|
5
|
+
|
6
|
+
def self.find_all_across_pages_since(time)
|
7
|
+
find_all_across_pages(:params => { :since => time.utc.to_s(:db).gsub(/[^\d]/, '') })
|
8
|
+
end
|
9
|
+
|
10
|
+
def company
|
11
|
+
Company.find(company_id) if company_id
|
12
|
+
end
|
13
|
+
|
14
|
+
def name
|
15
|
+
"#{first_name rescue ''} #{last_name rescue ''}".strip
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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 emails
|
8
|
+
Email.find_all_across_pages(:from => "/#{self.class.collection_name}/#{id}/emails.xml")
|
9
|
+
end
|
10
|
+
|
11
|
+
def upcoming_tasks
|
12
|
+
Task.find(:all, :from => "/#{self.class.collection_name}/#{id}/tasks.xml")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/highrise/tag.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Highrise
|
2
|
+
module Taggable
|
3
|
+
|
4
|
+
# thanks for the user Inka, http://forum.37signals.com/highrise/forums/15/topics/1312?page=2
|
5
|
+
|
6
|
+
def tag!(tag_name)
|
7
|
+
self.post(:tags, :name => tag_name) unless tag_name.blank?
|
8
|
+
end
|
9
|
+
|
10
|
+
def untag!(tag_name)
|
11
|
+
to_delete = self.tags.find{|t| t.name==tag_name} unless tag_name.blank?
|
12
|
+
self.delete("tags/#{to_delete.id}") unless to_delete.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def tags
|
16
|
+
tags = []
|
17
|
+
get_document.search("#show_tags a").each{ |a|
|
18
|
+
tags << Highrise::Tag.new(:id => a['href'].gsub(/.*\//, ''), :name => a.inner_html) if a['class'] == "grey tag"
|
19
|
+
}
|
20
|
+
tags
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_document
|
24
|
+
@curl_helper ||= CurlHelper.new
|
25
|
+
@doc = @curl_helper.get_document_from_id("#{self.class.collection_name}/#{self.id}")
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/highrise.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_resource'
|
3
|
+
require 'uri'
|
4
|
+
require 'curb'
|
5
|
+
gem 'activesupport', '>= 2.1'
|
6
|
+
require 'active_support/basic_object'
|
7
|
+
require 'hpricot'
|
8
|
+
require 'iconv'
|
9
|
+
|
10
|
+
require File.dirname(__FILE__) + '/highrise/pagination'
|
11
|
+
require File.dirname(__FILE__) + '/highrise/curly'
|
12
|
+
require File.dirname(__FILE__) + '/highrise/curlhelper'
|
13
|
+
require File.dirname(__FILE__) + '/highrise/taggable'
|
14
|
+
require File.dirname(__FILE__) + '/highrise/base'
|
15
|
+
require File.dirname(__FILE__) + '/highrise/subject'
|
16
|
+
require File.dirname(__FILE__) + '/highrise/comment'
|
17
|
+
require File.dirname(__FILE__) + '/highrise/company'
|
18
|
+
require File.dirname(__FILE__) + '/highrise/email'
|
19
|
+
require File.dirname(__FILE__) + '/highrise/group'
|
20
|
+
require File.dirname(__FILE__) + '/highrise/kase'
|
21
|
+
require File.dirname(__FILE__) + '/highrise/membership'
|
22
|
+
require File.dirname(__FILE__) + '/highrise/note'
|
23
|
+
require File.dirname(__FILE__) + '/highrise/person'
|
24
|
+
require File.dirname(__FILE__) + '/highrise/task'
|
25
|
+
require File.dirname(__FILE__) + '/highrise/user'
|
26
|
+
require File.dirname(__FILE__) + '/highrise/tag'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Highrise::Base do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@base = Highrise::Base.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be instance of ActiveResource::Base" do
|
10
|
+
@base.kind_of?(ActiveResource::Base).should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Highrise::Comment do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@comment = Highrise::Comment.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be instance of Highrise::Base" do
|
10
|
+
@comment.kind_of?(Highrise::Base).should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
end
|