moco-ruby 0.1.2 → 1.0.0.alpha

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/lib/moco/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MOCO
4
- VERSION = "0.1.2"
4
+ VERSION = "1.0.0.alpha"
5
5
  end
data/lib/moco.rb CHANGED
@@ -1,8 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support"
4
+ require "active_support/core_ext"
5
+ require "active_support/inflector"
6
+
3
7
  require_relative "moco/version"
4
- require_relative "moco/entities"
5
- require_relative "moco/api"
8
+
9
+ # New API (v2)
10
+ require_relative "moco/entities/base_entity"
11
+ require_relative "moco/entities/project"
12
+ require_relative "moco/entities/activity"
13
+ require_relative "moco/entities/user"
14
+ require_relative "moco/entities/company"
15
+ require_relative "moco/entities/task"
16
+ require_relative "moco/entities/invoice"
17
+ require_relative "moco/entities/deal"
18
+ require_relative "moco/entities/expense"
19
+ require_relative "moco/entities/web_hook"
20
+ require_relative "moco/entities/schedule"
21
+ require_relative "moco/entities/presence"
22
+ require_relative "moco/entities/holiday"
23
+ require_relative "moco/entities/planning_entry"
24
+ require_relative "moco/client"
25
+ require_relative "moco/connection"
26
+ require_relative "moco/collection_proxy"
27
+ require_relative "moco/nested_collection_proxy"
28
+ require_relative "moco/entity_collection"
29
+
6
30
  require_relative "moco/sync"
7
31
 
8
32
  module MOCO
data/mocurl.rb CHANGED
@@ -58,42 +58,59 @@ end
58
58
 
59
59
  # Load default API key from config
60
60
  config = YAML.load_file("config.yml")
61
- options[:api_key] ||= config["instances"].fetch(subdomain, nil)&.fetch("api_key", nil)
61
+ options[:api_key] ||= config["instances"].dig(subdomain, "api_key")
62
62
 
63
63
  warn "Error: No API key found for `#{subdomain}' and none given, continuing without" if options[:api_key].nil?
64
64
 
65
- api = MOCO::API.new(subdomain, options[:api_key])
66
-
67
- case options[:method]
68
- when "GET"
69
- result = api.get(url)
70
- when "DELETE"
71
- result = api.delete(url)
72
- when "POST"
73
- result = api.post(url, options[:data])
74
- when "PUT"
75
- result = api.put(url, options[:data])
76
- when "PATCH"
77
- result = api.patch(url, options[:data])
78
- else
79
- puts "Error: Invalid HTTP Method: #{options[:method]}"
80
- exit 1
81
- end
65
+ client = MOCO::Client.new(subdomain: subdomain, api_key: options[:api_key])
66
+
67
+ # Extract path from URL
68
+ path = url.gsub(%r{https?://#{subdomain}\.mocoapp\.com/api/v1/}, "")
69
+
70
+ begin
71
+ # Make request using the client's connection directly
72
+ result = case options[:method]
73
+ when "GET"
74
+ client.connection.get(path)
75
+ when "DELETE"
76
+ client.connection.delete(path)
77
+ when "POST"
78
+ client.connection.post(path, options[:data])
79
+ when "PUT"
80
+ client.connection.put(path, options[:data])
81
+ when "PATCH"
82
+ client.connection.patch(path, options[:data])
83
+ else
84
+ puts "Error: Invalid HTTP Method: #{options[:method]}"
85
+ exit 1
86
+ end
87
+
88
+ if options[:verbose]
89
+ puts "> #{options[:method]} #{url}"
90
+ # Print request details if available
91
+ if result.env&.request_headers
92
+ puts(result.env.request_headers.map do |k, v|
93
+ "> #{k}: #{k == "Authorization" ? "#{v[0...16]}<REDACTED>#{v[-4..]}" : v}"
94
+ end)
95
+ puts ">"
96
+ puts result.env.request_body.split.map { |l| "> #{l}" }.join if result.env.request_body
97
+ puts "---"
98
+ puts "< #{result.status} #{result.reason_phrase}"
99
+ puts(result.headers.map { |k, v| "< #{k}: #{v}" })
100
+ else
101
+ puts "> Request details not available in this response format"
102
+ end
103
+ puts ""
104
+ end
82
105
 
83
- if options[:verbose]
84
- puts "> #{options[:method]} #{result.env.url}"
85
- puts(result.env.request_headers.map do |k, v|
86
- "> #{k}: #{k == "Authorization" ? "#{v[0...16]}<REDACTED>#{v[-4..]}" : v}"
87
- end)
88
- puts ">"
89
- puts result.env.request_body.split.map { |l| "> #{l}" }.join if result.env.request_body
90
- puts "---"
91
- puts "< #{result.status} #{result.reason_phrase}"
92
- puts(result.headers.map { |k, v| "< #{k}: #{v}" })
93
- puts ""
94
- end
95
- if options[:no_format]
96
- puts result.body.to_json
97
- else
98
- puts JSON.pretty_generate(result.body)
106
+ # Format the response
107
+ response_data = result.body
108
+ if options[:no_format]
109
+ puts response_data.to_json
110
+ else
111
+ puts JSON.pretty_generate(response_data)
112
+ end
113
+ rescue StandardError => e
114
+ puts "Error: #{e.message}"
115
+ exit 1
99
116
  end
data/sync_activity.rb CHANGED
@@ -64,12 +64,12 @@ config = YAML.load_file("config.yml")
64
64
  source_config = config["instances"].fetch(source_instance, nil)
65
65
  target_config = config["instances"].fetch(target_instance, nil)
66
66
 
67
- source_api = MOCO::API.new(source_instance, source_config["api_key"])
68
- target_api = MOCO::API.new(target_instance, target_config["api_key"])
67
+ source_client = MOCO::Client.new(subdomain: source_instance, api_key: source_config["api_key"])
68
+ target_client = MOCO::Client.new(subdomain: target_instance, api_key: target_config["api_key"])
69
69
 
70
70
  syncer = MOCO::Sync.new(
71
- source_api,
72
- target_api,
71
+ source_client,
72
+ target_client,
73
73
  project_match_threshold: options[:match_project_threshold],
74
74
  task_match_threshold: options[:match_task_threshold],
75
75
  filters: {
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moco-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 1.0.0.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Teal Bauer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-04-02 00:00:00.000000000 Z
11
+ date: 2025-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: faraday
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -55,21 +69,40 @@ files:
55
69
  - README.md
56
70
  - Rakefile
57
71
  - config.yml.sample
72
+ - examples/v2_api_example.rb
58
73
  - lib/moco.rb
59
- - lib/moco/api.rb
74
+ - lib/moco/client.rb
75
+ - lib/moco/collection_proxy.rb
76
+ - lib/moco/connection.rb
60
77
  - lib/moco/entities.rb
78
+ - lib/moco/entities/activity.rb
79
+ - lib/moco/entities/base_entity.rb
80
+ - lib/moco/entities/company.rb
81
+ - lib/moco/entities/deal.rb
82
+ - lib/moco/entities/expense.rb
83
+ - lib/moco/entities/holiday.rb
84
+ - lib/moco/entities/invoice.rb
85
+ - lib/moco/entities/planning_entry.rb
86
+ - lib/moco/entities/presence.rb
87
+ - lib/moco/entities/project.rb
88
+ - lib/moco/entities/schedule.rb
89
+ - lib/moco/entities/task.rb
90
+ - lib/moco/entities/user.rb
91
+ - lib/moco/entities/web_hook.rb
92
+ - lib/moco/entity_collection.rb
61
93
  - lib/moco/helpers.rb
94
+ - lib/moco/nested_collection_proxy.rb
62
95
  - lib/moco/sync.rb
63
96
  - lib/moco/version.rb
64
97
  - mocurl.rb
65
98
  - sync_activity.rb
66
- homepage: https://github.com/moeffju/moco-ruby
99
+ homepage: https://github.com/starsong-consulting/moco-ruby
67
100
  licenses:
68
101
  - Apache-2.0
69
102
  metadata:
70
- homepage_uri: https://github.com/moeffju/moco-ruby
71
- source_code_uri: https://github.com/moeffju/moco-ruby
72
- changelog_uri: https://github.com/moeffju/moco-ruby/blob/main/CHANGELOG.md
103
+ homepage_uri: https://github.com/starsong-consulting/moco-ruby
104
+ source_code_uri: https://github.com/starsong-consulting/moco-ruby
105
+ changelog_uri: https://github.com/starsong-consulting/moco-ruby/blob/main/CHANGELOG.md
73
106
  rubygems_mfa_required: 'true'
74
107
  post_install_message:
75
108
  rdoc_options: []
@@ -79,12 +112,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
112
  requirements:
80
113
  - - ">="
81
114
  - !ruby/object:Gem::Version
82
- version: 2.6.0
115
+ version: 3.2.0
83
116
  required_rubygems_version: !ruby/object:Gem::Requirement
84
117
  requirements:
85
- - - ">="
118
+ - - ">"
86
119
  - !ruby/object:Gem::Version
87
- version: '0'
120
+ version: 1.3.1
88
121
  requirements: []
89
122
  rubygems_version: 3.4.1
90
123
  signing_key:
data/lib/moco/api.rb DELETED
@@ -1,194 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "faraday"
4
- require_relative "entities"
5
-
6
- module MOCO
7
- # MOCO::API abstracts access to the MOCO API and its entities
8
- class API
9
- def initialize(subdomain, api_key)
10
- @subdomain = subdomain
11
- @api_key = api_key
12
- @conn = Faraday.new do |f|
13
- f.request :json
14
- f.response :json
15
- f.request :authorization, "Token", "token=#{@api_key}" if @api_key
16
- f.url_prefix = "https://#{@subdomain}.mocoapp.com/api/v1"
17
- end
18
- end
19
-
20
- %w[get post put patch delete].each do |method|
21
- define_method(method) do |path, *args|
22
- @conn.send(method, path, *args)
23
- end
24
- end
25
-
26
- def get_projects(**args)
27
- response = @conn.get("projects?#{Faraday::Utils.build_query(args)}")
28
- parse_projects_response(response.body)
29
- end
30
-
31
- def get_assigned_projects(**args)
32
- response = @conn.get("projects/assigned?#{Faraday::Utils.build_query(args)}")
33
- parse_projects_response(response.body)
34
- end
35
-
36
- def get_activities(filters = {})
37
- response = @conn.get("activities?#{Faraday::Utils.build_query(filters)}")
38
- parse_activities_response(response.body)
39
- end
40
-
41
- def get_activity(id)
42
- response = @conn.get("activities/#{id}")
43
- parse_activities_response([response.body]).first
44
- end
45
-
46
- def create_activities_bulk(activities)
47
- api_entities = activities.map do |activity|
48
- activity.to_h.except(:id, :project, :user, :customer).tap do |h|
49
- h[:project_id] = activity.project.id
50
- h[:task_id] = activity.task.id
51
- end
52
- end
53
- @conn.post("activities/bulk", { activities: api_entities })
54
- end
55
-
56
- def create_activity(activity)
57
- api_entity = activity.to_h.except(:id, :project, :user, :customer).tap do |h|
58
- h[:project_id] = activity.project.id
59
- h[:task_id] = activity.task.id
60
- end
61
- @conn.post("activities", api_entity)
62
- end
63
-
64
- def update_activity(activity)
65
- api_entity = activity.to_h.except(:project, :user, :customer).tap do |h|
66
- h[:project_id] = activity.project.id
67
- h[:task_id] = activity.task.id
68
- end
69
- @conn.put("activities/#{activity.id}", api_entity)
70
- end
71
-
72
- def start_activity_timer(activity_id)
73
- @conn.patch("activities/#{activity_id}/start_timer")
74
- end
75
-
76
- def stop_activity_timer(activity_id)
77
- @conn.patch("activities/#{activity_id}/stop_timer")
78
- end
79
-
80
- def disregard_activities(reason:, activity_ids:, company_id:, project_id: nil)
81
- payload = {
82
- reason: reason,
83
- activity_ids: activity_ids,
84
- company_id: company_id
85
- }
86
- payload[:project_id] = project_id if project_id
87
- @conn.post("activities/disregard", payload)
88
- end
89
-
90
- def delete_activity(activity_id)
91
- @conn.delete("activities/#{activity_id}")
92
- end
93
-
94
- def archive_project(project_id)
95
- @conn.put("projects/#{project_id}/archive")
96
- end
97
-
98
- def unarchive_project(project_id)
99
- @conn.put("projects/#{project_id}/unarchive")
100
- end
101
-
102
- def get_project_report(project_id)
103
- @conn.get("projects/#{project_id}/report")
104
- end
105
-
106
- def share_project_report(project_id)
107
- @conn.put("projects/#{project_id}/share")
108
- end
109
-
110
- def disable_project_report_sharing(project_id)
111
- @conn.put("projects/#{project_id}/disable_share")
112
- end
113
-
114
- def assign_project_to_group(project_id, project_group_id)
115
- @conn.put("projects/#{project_id}/assign_project_group", { project_group_id: project_group_id })
116
- end
117
-
118
- def unassign_project_from_group(project_id)
119
- @conn.put("projects/#{project_id}/unassign_project_group")
120
- end
121
-
122
- private
123
-
124
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
125
- def parse_projects_response(data)
126
- data.map do |project_data|
127
- Project.new.tap do |project|
128
- project.id = project_data["id"]
129
- project.name = project_data["name"]
130
- project.customer = parse_customer_reference(project_data["customer"])
131
- project.tasks = project_data["tasks"].map do |task_data|
132
- Task.new.tap do |task|
133
- task.id = task_data["id"]
134
- task.name = task_data["name"]
135
- task.project_id = task_data["project_id"]
136
- task.billable = task_data["billable"]
137
- end
138
- end
139
- end
140
- end
141
- end
142
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
143
-
144
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
145
- def parse_activities_response(data)
146
- data.map do |activity_data|
147
- Activity.new.tap do |activity|
148
- activity.id = activity_data["id"]
149
- activity.date = activity_data["date"]
150
- activity.description = activity_data["description"]
151
- activity.user = parse_user_reference(activity_data["user"])
152
- activity.customer = parse_customer_reference(activity_data["customer"])
153
- activity.project = parse_project_reference(activity_data["project"])
154
- activity.task = parse_task_reference(activity_data["task"])
155
- activity.hours = activity_data["hours"]
156
- activity.seconds = activity_data["seconds"]
157
- activity.billable = activity_data["billable"]
158
- activity.billed = activity_data["billed"]
159
- activity.tag = activity_data["tag"]
160
- end
161
- end
162
- end
163
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
164
-
165
- def parse_project_reference(project_data)
166
- Project.new.tap do |project|
167
- project.id = project_data["id"]
168
- project.name = project_data["name"]
169
- end
170
- end
171
-
172
- def parse_task_reference(task_data)
173
- Task.new.tap do |task|
174
- task.id = task_data["id"]
175
- task.name = task_data["name"]
176
- end
177
- end
178
-
179
- def parse_user_reference(user_data)
180
- User.new.tap do |user|
181
- user.id = user_data["id"]
182
- user.firstname = user_data["firstname"]
183
- user.lastname = user_data["lastname"]
184
- end
185
- end
186
-
187
- def parse_customer_reference(customer_data)
188
- Customer.new.tap do |customer|
189
- customer.id = customer_data["id"]
190
- customer.name = customer_data["name"]
191
- end
192
- end
193
- end
194
- end