coach_client 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+