taskmapper-bcx 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 76364ca93d18edf8820a34fbb399c801b7baecc1
4
+ data.tar.gz: 43a7fa1e2daa97823e37ff1a341cd7f516938eeb
5
+ SHA512:
6
+ metadata.gz: 59a4f1ce9de5e0f4ad3269de65b8657503704a441197474f7e7396f7622de4dd3dba0c855f4f73bb8592854d73108db46858c6577194eff66f3c96c1625f1f8b
7
+ data.tar.gz: 24ef5d1916a8229e4ecb402aecad85331fd1efab7f178313eba5d06e5faeaa9d7ed9988c1b562124d53bf5c0e34f3ea407a04ecd59892016a7ad55a3403e5d8c
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andrew Stewart
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,104 @@
1
+ # taskmapper-bcx
2
+
3
+ This is the [TaskMapper][] adapter for interaction with [Basecamp Next][]
4
+
5
+ ## Usage
6
+
7
+ Initialize the taskmapper-bcx instance using your username, password, and
8
+ account ID:
9
+
10
+ ```ruby
11
+ bcx = TaskMapper.new(
12
+ :bcx,
13
+ :account_id => "123456789",
14
+ :username => "YOUR_USERNAME",
15
+ :username => "YOUR_PASSWORD",
16
+ )
17
+ ```
18
+
19
+ ## Finding Projects
20
+
21
+ You can find your own projects by using:
22
+
23
+ ```ruby
24
+ projects = bcx.projects # will return all projects
25
+ projects = bcx.projects ["project_id", "another_project_id"]
26
+ project = bcx.projects.find :first, "project_id"
27
+ projects = bcx.projects.find :all, ["project_id", "another_project_id"]
28
+ ```
29
+
30
+ ## Finding Tickets
31
+
32
+ ```ruby
33
+ tickets = project.tickets # All open tickets
34
+ tickets = project.tickets :all, :status => 'closed' # all closed tickets
35
+ ticket = project.ticket 981234
36
+ ```
37
+
38
+ ## Opening A Ticket
39
+
40
+ ```ruby
41
+ ticket = project.ticket!(
42
+ :description => "Content of the new ticket."
43
+ )
44
+ ```
45
+
46
+ ## Closing Tickets
47
+
48
+ ```ruby
49
+ ticket.close
50
+ ```
51
+
52
+ ## Reopening Tickets
53
+
54
+ ```ruby
55
+ ticket.reopen
56
+ ```
57
+
58
+ ## Updating Tickets
59
+
60
+ ```ruby
61
+ ticket.description = "New description"
62
+ ticket.save
63
+ ```
64
+
65
+ ## Finding Comments
66
+
67
+ ```ruby
68
+ ticket.comments # all comments for a ticket
69
+ ticket.comments 90210
70
+ ```
71
+
72
+ ## Creating a Comment
73
+
74
+ ```ruby
75
+ ticket.comment! :body => "New Comment!"
76
+ ```
77
+
78
+ ## Dependencies
79
+
80
+ - rubygems
81
+ - [taskmapper][]
82
+ - [httparty][]
83
+
84
+ ## Contributing
85
+
86
+ The main way you can contribute is with some code! Here's how:
87
+
88
+ - Fork `taskmapper-bcx`
89
+ - Create a topic branch: git checkout -b my_awesome_feature
90
+ - Push to your branch - git push origin my_awesome_feature
91
+ - Create a Pull Request from your branch
92
+ - That's it!
93
+
94
+ We use RSpec for testing. Please include tests with your pull request. A simple
95
+ `bundle exec rake` will run the suite. Also, please try to TomDoc your methods,
96
+ it makes it easier to see what the code does and makes it easier for future
97
+ contributors to get started.
98
+
99
+ (c) 2013 The Hybrid Group
100
+
101
+
102
+ [taskmapper]: http://ticketrb.com
103
+ [basecamp next]: https://basecamp.com
104
+ [httparty]: https://github.com/jnunemaker/httparty
@@ -0,0 +1,7 @@
1
+ require "bundler"
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :default => :spec
5
+
6
+ Bundler::GemHelper.install_tasks
7
+ RSpec::Core::RakeTask.new :spec
@@ -0,0 +1,26 @@
1
+ require 'httparty'
2
+
3
+ module TaskMapper::Provider
4
+ module Bcx
5
+ class API
6
+ include HTTParty
7
+
8
+ attr_reader :account_id, :username, :password
9
+
10
+ headers "Content-Type" => "Content-Type: application/json; charset=utf-8"
11
+
12
+ def initialize(account_id, username, password)
13
+ @username = username
14
+ @password = password
15
+ @account_id = account_id
16
+ self.class.base_uri "https://basecamp.com/#{account_id}/api/v1"
17
+ self.class.basic_auth username, password
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ require 'provider/api/auth'
24
+ require 'provider/api/projects'
25
+ require 'provider/api/todos'
26
+ require 'provider/api/comments'
@@ -0,0 +1,12 @@
1
+ module TaskMapper::Provider
2
+ module Bcx
3
+ class API
4
+ def authenticated?
5
+ @auth ||= begin
6
+ me = self.class.get "/people/me.json"
7
+ me.is_a?(Hash) && !me['id'].nil?
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module TaskMapper::Provider
2
+ module Bcx
3
+ class API
4
+ def create_comment(attributes)
5
+ project = attributes.delete(:project_id)
6
+ todo = attributes.delete(:ticket_id)
7
+ body = { "content" => attributes[:body] }
8
+
9
+ url = "/projects#{project}/todos/#{todo}/comments.json"
10
+ self.class.post url, :body => body.to_json
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module TaskMapper::Provider
2
+ module Bcx
3
+ class API
4
+ def projects
5
+ self.class.get "/projects.json"
6
+ end
7
+
8
+ def project(id)
9
+ self.class.get "/projects/#{id}.json"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,61 @@
1
+ module TaskMapper::Provider
2
+ module Bcx
3
+ class API
4
+ def todos(project_id)
5
+ ids = get_todolist_ids project_id
6
+ todo_ids = ids.collect do |id|
7
+ get_todo_ids_from_list project_id, id
8
+ end.flatten
9
+
10
+ todos = []
11
+ todo_ids.each do |id|
12
+ todo = self.class.get "/projects/#{project_id}/todos/#{id}.json"
13
+ todos << Hash[todo]
14
+ end
15
+ todos.flatten
16
+ end
17
+
18
+ def todo(project_id, todo_id)
19
+ self.class.get "/projects/#{project_id}/todos/#{todo_id}.json"
20
+ end
21
+
22
+ def create_todo(attributes)
23
+ project = attributes.delete(:project_id)
24
+ todolist = attributes.delete(:todolist_id)
25
+ due_at = attributes.delete(:due_at)
26
+
27
+ body = { "content" => attributes[:description] }
28
+ body.merge({ "due_at" => due_at.utc.iso8601 }) if due_at
29
+
30
+ url = "/projects/#{project}/todolists/#{todolist}/todos.json"
31
+ self.class.post url, :body => body.to_json
32
+ end
33
+
34
+ def update_todo(todo)
35
+ body = {
36
+ :content => todo['content'],
37
+ :due_at => todo['due_at'],
38
+ :completed => todo['completed']
39
+ }
40
+
41
+ url = "/projects/#{todo['project_id']}/todos/#{todo['id']}.json"
42
+ self.class.put url, :body => body.to_json
43
+ end
44
+
45
+ private
46
+ def get_todolist_ids(project_id)
47
+ lists = self.class.get "/projects/#{project_id}/todolists.json"
48
+ lists.collect { |t| t['id'] }
49
+ end
50
+
51
+ def get_todo_ids_from_list(project_id, list)
52
+ list = self.class.get "/projects/#{project_id}/todolists/#{list}.json"
53
+ return [] if !list.is_a?(Hash) || list["todos"].nil?
54
+ ids = []
55
+ ids << list["todos"]["remaining"].map { |t| t['id'] }
56
+ ids << list["todos"]["completed"].map { |t| t['id'] }
57
+ ids.flatten
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,44 @@
1
+ module TaskMapper::Provider
2
+ module Bcx
3
+ include TaskMapper::Provider::Base
4
+
5
+ class << self
6
+ attr_accessor :username, :password, :account_id, :api
7
+
8
+ def new(auth = {})
9
+ TaskMapper.new(:bcx, auth)
10
+ end
11
+ end
12
+
13
+ def provider
14
+ TaskMapper::Provider::Bcx
15
+ end
16
+
17
+ def authorize(auth = {})
18
+ @authenticator ||= TaskMapper::Authenticator.new(auth)
19
+
20
+ unless auth[:username] && auth[:password]
21
+ message = "Please provide a username and password."
22
+ raise TaskMapper::Exception.new message
23
+ end
24
+
25
+ unless auth[:account_id]
26
+ message = "Please provide a Basecamp account_id"
27
+ raise TaskMapper::Exception.new message
28
+ end
29
+
30
+ provider.username = auth[:username]
31
+ provider.password = auth[:password]
32
+ provider.account_id = auth[:account_id]
33
+ configure auth
34
+ end
35
+
36
+ def configure(auth)
37
+ provider.api = API.new auth[:account_id], auth[:username], auth[:password]
38
+ end
39
+
40
+ def valid?
41
+ provider.api.authenticated?
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,78 @@
1
+ module TaskMapper::Provider
2
+ module Bcx
3
+ class Comment < TaskMapper::Provider::Base::Comment
4
+ def initialize(*object)
5
+ object = object.first if object.is_a?(Array)
6
+ super object if object.is_a?(Hash)
7
+ end
8
+
9
+ def body
10
+ self[:content]
11
+ end
12
+
13
+ def updated_at
14
+ begin
15
+ Time.parse(self[:updated_at])
16
+ rescue
17
+ self[:updated_at]
18
+ end
19
+ end
20
+
21
+ def created_at
22
+ begin
23
+ Time.parse(self[:created_at])
24
+ rescue
25
+ self[:created_at]
26
+ end
27
+ end
28
+
29
+ class << self
30
+ def find_by_attributes(project_id, ticket_id, attributes = {})
31
+ search_by_attribute(self.find_all(project_id, ticket_id), attributes)
32
+ end
33
+
34
+ def find_by_id(project_id, ticket_id, comment_id)
35
+ ticket = Ticket.find_by_id project_id, ticket_id
36
+ if comment = ticket[:comments].find { |c| c[:id] == comment_id }
37
+ comment = comment.merge({
38
+ :ticket_id => ticket_id,
39
+ :project_id => project_id
40
+ })
41
+ return self.new comment
42
+ else
43
+ return false
44
+ end
45
+ end
46
+
47
+ def find_all(project_id, ticket_id)
48
+ ticket = Ticket.find_by_id project_id, ticket_id
49
+ ticket[:comments].collect do |comment|
50
+ comment = comment.merge({
51
+ :ticket_id => ticket_id,
52
+ :project_id => project_id
53
+ })
54
+ self.new comment
55
+ end
56
+ end
57
+
58
+ def create(attributes)
59
+ project = attributes[:project_id]
60
+ ticket = attributes[:ticket_id]
61
+
62
+ comment = api.create_comment attributes
63
+ comment = comment.merge({
64
+ :project_id => project,
65
+ :ticket_id => ticket
66
+ })
67
+
68
+ self.new comment
69
+ end
70
+
71
+ private
72
+ def api
73
+ TaskMapper::Provider::Bcx.api
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,48 @@
1
+ module TaskMapper::Provider
2
+ module Bcx
3
+ class Project < TaskMapper::Provider::Base::Project
4
+ def initialize(*object)
5
+ object = object.first if object.is_a?(Array)
6
+ super object if object.is_a?(Hash)
7
+ end
8
+
9
+ def updated_at
10
+ begin
11
+ Time.parse(self[:updated_at])
12
+ rescue
13
+ self[:updated_at]
14
+ end
15
+ end
16
+
17
+ def created_at
18
+ begin
19
+ Time.parse(self[:created_at])
20
+ rescue
21
+ self[:created_at]
22
+ end
23
+ end
24
+
25
+ class << self
26
+ def find_by_attributes(attributes = {})
27
+ search_by_attribute(self.find_all, attributes)
28
+ end
29
+
30
+ def find_all
31
+ projects = api.projects
32
+ projects = projects.select { |project| project.is_a?(Hash) }
33
+ projects.collect { |project| self.new project }
34
+ end
35
+
36
+ def find_by_id(id)
37
+ project = api.project(id)
38
+ self.new Hash[project]
39
+ end
40
+
41
+ private
42
+ def api
43
+ TaskMapper::Provider::Bcx.api
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end