coach_client 0.1.1

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.
@@ -0,0 +1,248 @@
1
+ module CoachClient
2
+ # A entry resource of the CyberCoach serivce.
3
+ class Entry < CoachClient::Resource
4
+ # @return [Integer]
5
+ attr_reader :id, :datecreated, :datemodified
6
+
7
+ # @return [Integer]
8
+ attr_accessor :publicvisible, :entryduration
9
+
10
+ # @return [Date]
11
+ attr_accessor :entrydate
12
+
13
+ # @return [CoachClient::Subscription]
14
+ attr_accessor :subscription
15
+
16
+ # @return [String]
17
+ attr_accessor :comment, :entrylocation
18
+
19
+ # For every sport but soccer.
20
+ #
21
+ # @return [Integer]
22
+ attr_accessor :numberofrounds
23
+
24
+ # For boxing.
25
+ #
26
+ # @return [Integer]
27
+ attr_accessor :roundduration
28
+
29
+ # For cycling and running.
30
+ #
31
+ # @return [Integer]
32
+ attr_accessor :courselength
33
+
34
+ # For cycling and running.
35
+ #
36
+ # @return [String]
37
+ attr_accessor :coursetype, :track
38
+
39
+ # For cycling.
40
+ #
41
+ # @return [String]
42
+ attr_accessor :bicycletype
43
+
44
+ # Extracts the entry id from the URI
45
+ #
46
+ # @param [String] uri
47
+ # @return [String] the entry id
48
+ def self.extract_id_from_uri(uri)
49
+ match = uri.match(/\/(\d+)\/\z/)
50
+ match.captures.first
51
+ end
52
+
53
+ # Creates a new entry.
54
+ #
55
+ # @param [CoachClient::Client] client
56
+ # @param [CoachClient::Subscription] subscription
57
+ # @param [Hash] info
58
+ # @option info [Integer] :id
59
+ # @option info [Integer] :publicvisible
60
+ # @option info [String] :comment
61
+ # @option info [Date] :entrydate
62
+ # @option info [Integer] :entryduration
63
+ # @option info [String] :entrylocation
64
+ # @return [CoachClient::Entry]
65
+ def initialize(client, subscription, info = {})
66
+ super(client)
67
+ @subscription = subscription
68
+ @id = info[:id]
69
+ @publicvisible = info[:publicvisible]
70
+ @comment = info[:comment]
71
+ @entrydate = info[:entrydate]
72
+ @entryduration = info[:entryduration]
73
+ @entrylocation = info[:entrylocation]
74
+ unless subscription.sport.sport == :soccer
75
+ @numberofrounds = info[:numberofrounds]
76
+ end
77
+ if subscription.sport.sport == :boxing
78
+ @roundduration = info[:roundduration]
79
+ end
80
+ if subscription.sport.sport == :cycling || subscription.sport.sport == :running
81
+ @courselength = info[:courselength]
82
+ @coursetype = info[:coursetype]
83
+ @track = info[:track]
84
+ end
85
+ @bicycletype = info[:bicycletype] if subscription.sport.sport == :cycling
86
+ end
87
+
88
+ # Updates the entry with the data from the CyberCoach service.
89
+ #
90
+ # @raise [CoachClient::NotFound] if the entry does not exist
91
+ # @return [CoachClient::User] the updated user
92
+ def update
93
+ raise CoachClient::NotFound, 'Entry not found' unless exist?
94
+ response = if user.authenticated?
95
+ CoachClient::Request.get(url, username: user.username,
96
+ password: user.password)
97
+ else
98
+ CoachClient::Request.get(url)
99
+ end
100
+ tag = "entry#{@subscription.sport}"
101
+ response = response.to_h[tag.to_sym]
102
+ @datecreated = response[:datecreated]
103
+ @datemodified = response[:datemodified]
104
+ @publicvisible = response[:publicvisible]
105
+ @comment = response[:comment]
106
+ @entrydate = response[:entrydate]
107
+ @entryduration = response[:entryduration]
108
+ @entrylocation = response[:entrylocation]
109
+ unless @subscription.sport.sport == :soccer
110
+ @numberofrounds = response[:numberofrounds]
111
+ end
112
+ if @subscription.sport.sport == :boxing
113
+ @roundduration = response[:roundduration]
114
+ end
115
+ if @subscription.sport.sport == :cycling || @subscription.sport.sport == :running
116
+ @courselength = response[:courselength]
117
+ @coursetype = response[:coursetype]
118
+ @track = response[:track]
119
+ end
120
+ @bicycletype = response[:bicycletype] if @subscription.sport.sport == :cycling
121
+ self
122
+ end
123
+
124
+ # Creates the entry on the CyberCoach service.
125
+ #
126
+ # @raise [CoachClient::Unauthorized] if not authorized
127
+ # @raise [CoachClient::IncompleteInformation] if not all needed information
128
+ # is given
129
+ # @raise [CoachClient::NotSaved] if the entry could not be saved
130
+ # @return [CoachClient::Entry] the created entry
131
+ def create
132
+ unless user.authenticated?
133
+ raise CoachClient::Unauthorized.new(user), 'Unauthorized'
134
+ end
135
+ begin
136
+ response = CoachClient::Request.post(@subscription.url,
137
+ username: user.username,
138
+ password: user.password,
139
+ payload: payload,
140
+ content_type: :xml)
141
+ rescue RestClient::Conflict
142
+ raise CoachClient::IncompleteInformation.new(self), 'Incomplete information'
143
+ end
144
+ unless response.code == 200 || response.code == 201
145
+ raise CoachClient::NotSaved.new(self), 'Could not create entry'
146
+ end
147
+ @id = self.class.extract_id_from_uri(response.header[:location])
148
+ self
149
+ end
150
+
151
+ # Saves the entry to the CyberCoach service.
152
+ #
153
+ # The entry is created if it does not exist on the CyberCoach service,
154
+ # otherwise it tries to overwrite it.
155
+ #
156
+ # @raise [CoachClient::Unauthorized] if not authorized
157
+ # @raise [CoachClient::IncompleteInformation] if not all needed information
158
+ # is given
159
+ # @raise [CoachClient::NotSaved] if the entry could not be saved
160
+ # @return [CoachClient::Entry] the created entry
161
+ def save
162
+ return create unless @id
163
+ unless user.authenticated?
164
+ raise CoachClient::Unauthorized.new(user), 'Unauthorized'
165
+ end
166
+ begin
167
+ response = CoachClient::Request.put(url, username: user.username,
168
+ password: user.password,
169
+ payload: payload,
170
+ content_type: :xml)
171
+ rescue RestClient::Conflict
172
+ raise CoachClient::IncompleteInformation.new(self), 'Incomplete information'
173
+ end
174
+ unless response.code == 200 || response.code == 201
175
+ raise CoachClient::NotSaved.new(self), 'Could not save entry'
176
+ end
177
+ self
178
+ end
179
+
180
+ # Returns the user that is used for the authentication.
181
+ #
182
+ # @return [CoachClient::User]
183
+ def user
184
+ if @subscription.is_a?(CoachClient::PartnershipSubscription)
185
+ partnership = @subscription.partnership
186
+ if partnership.user1.authenticated?
187
+ partnership.user1
188
+ else
189
+ partnership.user2
190
+ end
191
+ else
192
+ @subscription.user
193
+ end
194
+ end
195
+
196
+ # Deletes the entry on the CyberCoach service.
197
+ #
198
+ # @raise [CoachClient::NotFound] if the entry does not exist
199
+ # @raise [CoachClient::Unauthorized] if not authorized
200
+ # @return [true]
201
+ def delete
202
+ raise CoachClient::NotFound.new(self), 'Entry not found' unless exist?
203
+ unless user.authenticated?
204
+ raise CoachClient::Unauthorized.new(user), 'Unauthorized'
205
+ end
206
+ CoachClient::Request.delete(url, username: user.username,
207
+ password: user.password)
208
+ true
209
+ end
210
+
211
+ # Returns whether the resource exists on the CyberCoach service.
212
+ #
213
+ # @return [Boolean]
214
+ def exist?
215
+ return false unless @id
216
+ if user.authenticated?
217
+ super(username: user.username, password: user.password)
218
+ else
219
+ super
220
+ end
221
+ end
222
+
223
+ # Returns the URL of the entry.
224
+ #
225
+ # @return [String] the url of the entry
226
+ def url
227
+ "#{@subscription.url}/#{@id}"
228
+ end
229
+
230
+ # Returns the string representation of the entry.
231
+ #
232
+ # @return [String]
233
+ def to_s
234
+ @id.to_s
235
+ end
236
+
237
+ private
238
+
239
+ def payload
240
+ vals = self.to_h
241
+ vals.delete(:subscription)
242
+ vals.delete_if { |_k, v| v.nil? || v.to_s.empty? }
243
+ tag = "entry#{@subscription.sport}"
244
+ Gyoku.xml(tag.to_sym => vals)
245
+ end
246
+ end
247
+ end
248
+
@@ -0,0 +1,78 @@
1
+ module CoachClient
2
+ # The standard exception for CoachClient errors.
3
+ class Exception < StandardError; end
4
+
5
+ # The error when the resource could not be found on the CyberCoach service.
6
+ class NotFound < CoachClient::Exception; end
7
+
8
+ # The error for resources that could not have been saved.
9
+ class NotSaved < CoachClient::Exception
10
+ # Returns the resource that encountered the error.
11
+ #
12
+ # @return [CoachClient::Resource]
13
+ attr_reader :resource
14
+
15
+ # @param [CoachClient::Resource] resource
16
+ # @return [CoachClient::NotSaved]
17
+ def initialize(resource)
18
+ @resource = resource
19
+ end
20
+ end
21
+
22
+ # Returns the error for partnerships that could not be confirmed.
23
+ class NotConfirmed < CoachClient::Exception
24
+ # Returns the partnership that encountered the error.
25
+ #
26
+ # @return [CoachClient::Partnership]
27
+ attr_reader :partnership
28
+
29
+ # @param [CoachClient::Partnership] partnership
30
+ # @return [CoachClient::NotConfirmed]
31
+ def initialize(partnership)
32
+ @partnership = partnership
33
+ end
34
+ end
35
+
36
+ # The error for partnerships that could not be proposed.
37
+ class NotProposed < CoachClient::Exception
38
+ # Returns the partnership that encountered the error.
39
+ #
40
+ # @return [CoachClient::Partnership]
41
+ attr_reader :partnership
42
+
43
+ # @param [CoachClient::Partnership] partnership
44
+ # @return [CoachClient::NotProposed]
45
+ def initialize(partnership)
46
+ @partnership = partnership
47
+ end
48
+ end
49
+
50
+ # The error that the user is not authorized to see the resource.
51
+ class Unauthorized < CoachClient::Exception
52
+ # Returns the user that encountered the error.
53
+ #
54
+ # @return [CoachClient::User]
55
+ attr_reader :user
56
+
57
+ # @param [CoachClient::User] user
58
+ # @return [CoachClient::Unauthorized]
59
+ def initialize(user = nil)
60
+ @user = user
61
+ end
62
+ end
63
+
64
+ # The error for missing informations of a resource.
65
+ class IncompleteInformation < CoachClient::Exception
66
+ # Returns the resource that encountered the error.
67
+ #
68
+ # @return [CoachClient::Resource]
69
+ attr_reader :resource
70
+
71
+ # @param [CoachClient::Resource] resource
72
+ # @return [CoachClient::IncompleteInformation]
73
+ def initialize(resource)
74
+ @resource = resource
75
+ end
76
+ end
77
+ end
78
+
@@ -0,0 +1,294 @@
1
+ module CoachClient
2
+ # A partnership resource of the CyberCoach service.
3
+ class Partnership < CoachClient::Resource
4
+ # The size of the requests for the {.list} with all = true
5
+ LIST_ALL_SIZE = 1000
6
+
7
+ # @return [Integer]
8
+ attr_reader :id, :datecreated
9
+
10
+ # @return [Boolean]
11
+ attr_reader :user1_confirmed, :user2_confirmed
12
+
13
+ # @return [Array<CoachClient::Subscription>]
14
+ attr_reader :subscriptions
15
+
16
+ # @return [CoachClient::User]
17
+ attr_accessor :user1, :user2
18
+
19
+ # @return [Integer]
20
+ attr_accessor :publicvisible
21
+
22
+ # Returns the relative path to the partnership resource.
23
+ #
24
+ # @return [String] the relative path
25
+ def self.path
26
+ 'partnerships/'
27
+ end
28
+
29
+ # Extracts the usernames from the partnership URI
30
+ #
31
+ # @param [String] uri
32
+ # @return [Array<String>] the usernames
33
+ def self.extract_users_from_uri(uri)
34
+ match = uri.match(/partnerships\/(\w+);(\w+)\//)
35
+ match.captures
36
+ end
37
+
38
+ # Returns the total number of partnerships present on the CyberCoach service.
39
+ #
40
+ # @param [CoachClient::Client] client
41
+ # @return [Integer] the total number of partnerships
42
+ def self.total(client)
43
+ response = CoachClient::Request.get(client.url + path,
44
+ params: { size: 0 })
45
+ response.to_h[:available]
46
+ end
47
+
48
+ # Returns a list of partnerships from the CyberCoach service for which the
49
+ # given block returns a true value.
50
+ #
51
+ # If no block is given, the whole list is returned.
52
+ #
53
+ # @param [CoachClient::Client] client
54
+ # @param [Integer] size
55
+ # @param [Integer] start
56
+ # @param [Boolean] all
57
+ # @yieldparam [CoachClient::Partnership] partnership the partnership
58
+ # @yieldreturn [Boolean] whether the partnership should be added to the list
59
+ # @return [Array<CoachClient::Partnership>] the list of partnerships
60
+ def self.list(client, size: 20, start: 0, all: false)
61
+ list = []
62
+ if all
63
+ total = self.total(client)
64
+ start = 0
65
+ size = LIST_ALL_SIZE
66
+ end
67
+ loop do
68
+ response = CoachClient::Request.get(client.url + path,
69
+ params: { start: start, size: size })
70
+ response.to_h[:partnerships].each do |p|
71
+ user1, user2 = extract_users_from_uri(p[:uri])
72
+ partnership = self.new(client, user1, user2)
73
+ list << partnership if !block_given? || yield(partnership)
74
+ end
75
+ break unless all
76
+ start += size
77
+ break if start >= total
78
+ end
79
+ list
80
+ end
81
+
82
+ # Creates a new partnership.
83
+ #
84
+ # @param [CoachClient::Client] client
85
+ # @param [String, CoachClient::User] user1
86
+ # @param [String, CoachClient::User] user2
87
+ # @param [Integer] publicvisible
88
+ # @return [CoachClient::Partnership]
89
+ def initialize(client, user1, user2, publicvisible: nil)
90
+ super(client)
91
+ @user1 = if user1.is_a?(CoachClient::User)
92
+ user1
93
+ else
94
+ CoachClient::User.new(client, user1)
95
+ end
96
+ @user2 = if user2.is_a?(CoachClient::User)
97
+ user2
98
+ else
99
+ CoachClient::User.new(client, user2)
100
+ end
101
+ @publicvisible = publicvisible
102
+ end
103
+
104
+ # Updates the partnership with the data from the CyberCoach service.
105
+ #
106
+ # @raise [CoachClient::NotFound] if the partnership does not exist
107
+ # @return [CoachClient::Partnership] the updated partnership
108
+ def update
109
+ raise CoachClient::NotFound.new(self), 'Partnership not found' unless exist?
110
+ response = if @user1.authenticated?
111
+ CoachClient::Request.get(url, username: @user1.username,
112
+ password: @user1.password)
113
+ elsif @user2.authenticated?
114
+ CoachClient::Request.get(url, username:@user2.username,
115
+ password: @user2.password)
116
+ else
117
+ CoachClient::Request.get(url)
118
+ end
119
+ response = response.to_h
120
+ @id = response[:id]
121
+ @datecreated = response[:datecreated]
122
+ @publicvisible = response[:publicvisible]
123
+ @user1_confirmed = response[:userconfirmed1]
124
+ @user2_confirmed = response[:userconfirmed2]
125
+ @subscriptions = []
126
+ unless response[:subscriptions].nil?
127
+ response[:subscriptions].each do |s|
128
+ sport = s[:uri].match(/\/(\w+)\/\z/).captures.first
129
+ @subscriptions << CoachClient::PartnershipSubscription.new(client, self,
130
+ sport)
131
+ end
132
+ end
133
+ self
134
+ end
135
+
136
+ # Saves the partnership to the CyberCoach service.
137
+ #
138
+ # The partnership is created if it does not exist on the CyberCoach service,
139
+ # otherwise it tries to overwrite it.
140
+ #
141
+ # @raise [CoachClient::Unauthorized] if not authorized
142
+ # @raise [CoachClient::IncompleteInformation] if not all needed information
143
+ # is given
144
+ # @raise [CoachClient::NotSaved] if the partnership could not be saved
145
+ # @return [CoachClient::Partnership] the saved partnership
146
+ def save
147
+ unless operational?
148
+ propose unless @user1_confirmed
149
+ return confirm
150
+ end
151
+ user1 = @user1.authenticated?
152
+ user2 = @user2.authenticated? unless user1
153
+ unless user1 || user2
154
+ raise CoachClient::Unauthorized.new(@user2), 'Unauthorized'
155
+ end
156
+ begin
157
+ response = if user1
158
+ CoachClient::Request.put(url, username: @user1.username,
159
+ password: @user1.password,
160
+ payload: payload,
161
+ content_type: :xml)
162
+ else
163
+ CoachClient::Request.put(url, username: @user2.username,
164
+ password: @user2.password,
165
+ payload: payload,
166
+ content_type: :xml)
167
+ end
168
+ rescue RestClient::Conflict
169
+ raise CoachClient::IncompleteInformation.new(self), 'Incomplete information'
170
+ end
171
+ unless response.code == 200 || response.code == 201
172
+ raise CoachClient::NotSaved.new(self), 'Could not save partnership'
173
+ end
174
+ self
175
+ end
176
+
177
+ # Proposes the partnership on the CyberCoach service.
178
+ #
179
+ # @raise [CoachClient::Unauthorized] if not authorized
180
+ # @raise [CoachClient::IncompleteInformation] if not all needed information
181
+ # is given
182
+ # @raise [CoachClient::NotProposed] if the partnership could not be proposed
183
+ # @return [CoachClient::Partnership] the proposed partnership
184
+ def propose
185
+ unless @user1.authenticated?
186
+ raise CoachClient::Unauthorized.new(@user1), 'Unauthorized'
187
+ end
188
+ begin
189
+ response = CoachClient::Request.put(url, username: @user1.username,
190
+ password: @user1.password,
191
+ payload: payload,
192
+ content_type: :xml)
193
+ rescue RestClient::Conflict
194
+ raise CoachClient::IncompleteInformation.new(self), 'Incomplete information'
195
+ end
196
+ unless response.code == 200 || response.code == 201
197
+ raise CoachClient::NotProposed.new(self), 'Could not propose partnership'
198
+ end
199
+ @user1_confirmed = true
200
+ self
201
+ end
202
+
203
+ # Confirms the partnership on the CyberCoach service.
204
+ #
205
+ # @raise [CoachClient::Unauthorized] if not authorized
206
+ # @raise [CoachClient::IncompleteInformation] if not all needed information
207
+ # is given
208
+ # @raise [CoachClient::NotConfirmed] if the partnership could not be proposed
209
+ # @return [CoachClient::Partnership] the confirmed partnership
210
+ def confirm
211
+ unless @user2.authenticated?
212
+ raise CoachClient::Unauthorized.new(@user2), 'Unauthorized'
213
+ end
214
+ begin
215
+ response = CoachClient::Request.put(url, username: @user2.username,
216
+ password: @user2.password,
217
+ payload: payload,
218
+ content_type: :xml)
219
+ rescue RestClient::Conflict
220
+ raise CoachClient::IncompleteInformation.new(self), 'Incomplete information'
221
+ end
222
+ unless response.code == 200 || response.code == 201
223
+ raise CoachClient::NotConfirmed.new(self), 'Could not confirm partnership'
224
+ end
225
+ @user2_confirmed = true
226
+ self
227
+ end
228
+
229
+ # Invalidates the partnership on the CyberCoach service.
230
+ #
231
+ # @raise [CoachClient::Unauthorized] if not authorized
232
+ # @return [CoachClient::Partnership] the invalidated partnership
233
+ def invalidate
234
+ unless @user2.authenticated?
235
+ raise CoachClient::Unauthorized.new(@user2), 'Unauthorized'
236
+ end
237
+ CoachClient::Request.delete(url, username: @user2.username,
238
+ password: @user2.password)
239
+ @user2_confirmed = false
240
+ self
241
+ end
242
+
243
+ # Deletes the partnership on the CyberCoach service.
244
+ #
245
+ # @raise [CoachClient::NotFound] if the partnership does not exist
246
+ # @raise [CoachClient::Unauthorized] if not authorized
247
+ # @return [true]
248
+ def delete
249
+ raise CoachClient::NotFound unless exist?
250
+ invalidate if user2_confirmed
251
+ if user1_confirmed
252
+ unless @user1.authenticated?
253
+ raise CoachClient::Unauthorized.new(@user1), 'Unauthorized'
254
+ end
255
+ CoachClient::Request.delete(url, username: @user1.username,
256
+ password: @user1.password)
257
+ end
258
+ @user1_confirmed = false
259
+ true
260
+ end
261
+
262
+ # Returns whether the partnership is operational.
263
+ #
264
+ # @return [Boolean]
265
+ def operational?
266
+ @user1_confirmed && @user2_confirmed
267
+ end
268
+
269
+ # Returns the URL of the partnership.
270
+ #
271
+ # @return [String] the url of the partnership
272
+ def url
273
+ "#{@client.url}#{self.class.path}#{@user1.username};#{@user2.username}"
274
+ end
275
+
276
+ # Returns the string representation of the user.
277
+ #
278
+ # @return [String]
279
+ def to_s
280
+ "#{@user1.username};#{@user2.username}"
281
+ end
282
+
283
+ private
284
+
285
+ def payload
286
+ vals = self.to_h
287
+ vals.delete(:user1)
288
+ vals.delete(:user2)
289
+ vals.delete_if { |_k, v| v.nil? || v.to_s.empty? }
290
+ Gyoku.xml(partnership: vals)
291
+ end
292
+ end
293
+ end
294
+