cybercoach 0.2.0 → 0.3.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +45 -0
  3. data/.rspec +2 -0
  4. data/CHANGELOG.md +8 -0
  5. data/Gemfile +23 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +31 -0
  8. data/Rakefile +2 -0
  9. data/cybercoach.gemspec +27 -0
  10. data/lib/cybercoach/abstract_resource.rb +162 -0
  11. data/lib/cybercoach/entry.rb +166 -0
  12. data/lib/cybercoach/format_not_supported_error.rb +7 -0
  13. data/lib/cybercoach/http_error.rb +27 -0
  14. data/lib/cybercoach/pageable.rb +38 -0
  15. data/lib/cybercoach/partnership.rb +151 -0
  16. data/lib/cybercoach/post_createable.rb +49 -0
  17. data/lib/cybercoach/privacy_level.rb +21 -0
  18. data/lib/cybercoach/put_createable.rb +48 -0
  19. data/lib/cybercoach/resource.rb +94 -0
  20. data/lib/cybercoach/resource_page.rb +191 -0
  21. data/lib/cybercoach/settings.rb +16 -0
  22. data/lib/cybercoach/sport.rb +104 -0
  23. data/lib/cybercoach/subclass_responsibility_error.rb +7 -0
  24. data/lib/cybercoach/subscription.rb +145 -0
  25. data/lib/cybercoach/user.rb +159 -0
  26. data/lib/cybercoach/version.rb +10 -0
  27. data/lib/cybercoach.rb +19 -0
  28. data/spec/lib/cybercoach/entry_spec.rb +95 -0
  29. data/spec/lib/cybercoach/partnership_spec.rb +79 -0
  30. data/spec/lib/cybercoach/privacy_level_spec.rb +15 -0
  31. data/spec/lib/cybercoach/resource_helper.rb +11 -0
  32. data/spec/lib/cybercoach/resource_page_spec.rb +44 -0
  33. data/spec/lib/cybercoach/settings_spec.rb +10 -0
  34. data/spec/lib/cybercoach/sport_spec.rb +29 -0
  35. data/spec/lib/cybercoach/subscription_spec.rb +129 -0
  36. data/spec/lib/cybercoach/user_helper.rb +22 -0
  37. data/spec/lib/cybercoach/user_spec.rb +82 -0
  38. data/spec/lib/cybercoach_helper.rb +2 -0
  39. data/spec/lib/integration_spec.rb +56 -0
  40. data/spec/spec_helper.rb +19 -0
  41. metadata +56 -4
@@ -0,0 +1,145 @@
1
+ module CyberCoach
2
+ #
3
+ # A Subscription to a Sport is placed by a User or a Partnership and contains
4
+ # Entries.
5
+ #
6
+ class Subscription < Resource
7
+ #
8
+ # It is creatable by PUT.
9
+ #
10
+ include PutCreateable
11
+
12
+ #
13
+ # :attr: subscriber
14
+ # Either a User or a Partnership, which places Entries to it.
15
+ #
16
+
17
+ #
18
+ # :attr: sport
19
+ # The Sport.
20
+ #
21
+
22
+ #
23
+ # :attr: entries
24
+ # The Entries already placed by the subscriber.
25
+ #
26
+
27
+ #
28
+ # :attr: privacy_level
29
+ # The privacy level, see PrivacyLevel constants.
30
+ #
31
+
32
+ #
33
+ # :attr: date_created
34
+ # The date it was created.
35
+ #
36
+
37
+ attr_accessor :subscriber, :sport, :entries, :privacy_level, :date_created
38
+
39
+ #
40
+ # :category: Serialization
41
+ #
42
+ # Creates itself from a serializable representation, which only contains
43
+ # simple data types.
44
+ # serializable:: A hash with the keys:
45
+ # * uri:: The URI.
46
+ # * id:: The identifier.
47
+ # * user|partnership:: A User or Partnership serializable of the subscriber.
48
+ # * sport:: A Sport serializable.
49
+ # * entries:: Entry serializables.
50
+ # * publicvisible:: The privacy level, see PrivacyLevel constants.
51
+ # * datesubscribed:: The date it was created.
52
+ #
53
+ def from_serializable(serializable)
54
+ super(serializable)
55
+ @subscriber = nil
56
+ unless serializable['user'].nil?
57
+ @subscriber = User.new
58
+ @subscriber.from_serializable(serializable['user'])
59
+ end
60
+ unless serializable['partnership'].nil?
61
+ @subscriber = Partnership.new
62
+ @subscriber.from_serializable(serializable['partnership'])
63
+ end
64
+ @sport = nil
65
+ unless serializable['sport'].nil?
66
+ @sport = Sport.new
67
+ @sport.from_serializable(serializable['sport'])
68
+ end
69
+ @entries = []
70
+ unless serializable['entries'].nil?
71
+ @entries = serializable['entries'].map do |entry_serializable|
72
+ entry = Entry.new
73
+ entry.from_serializable(entry_serializable)
74
+ entry
75
+ end
76
+ end
77
+ @privacy_level = serializable['publicvisible']
78
+ @date_created = nil
79
+ unless serializable['datesubscribed'].nil?
80
+ @date_created = Time.at(serializable['datesubscribed']).to_datetime
81
+ end
82
+ end
83
+
84
+ #
85
+ # :category: Serialization
86
+ #
87
+ # Returns a serializable representation, which only contains simple data
88
+ # types.
89
+ # The hash has the keys:
90
+ # * uri:: The URI.
91
+ # * id:: The identifier.
92
+ # * user|partnership:: A User or Partnership serializable of the subscriber.
93
+ # * sport:: A Sport serializable.
94
+ # * publicvisible:: The privacy level, see PrivacyLevel constants.
95
+ #
96
+ def to_serializable
97
+ serializable = super
98
+ serializable[@subscriber.singular_name] = @subscriber.to_serializable
99
+ serializable['sport'] = @sport.to_serializable
100
+ serializable['publicvisible'] = @privacy_level
101
+ serializable
102
+ end
103
+
104
+ #
105
+ # :category: Configuration
106
+ #
107
+ # Returns 'subscription'.
108
+ #
109
+ def singular_name
110
+ 'subscription'
111
+ end
112
+
113
+ #
114
+ # :category: Configuration
115
+ #
116
+ # Returns 'subscriptions'.
117
+ #
118
+ def plural_name
119
+ 'subscriptions'
120
+ end
121
+
122
+ #
123
+ # :category: Configuration
124
+ #
125
+ # Return the URI of its subscriber and sport.
126
+ #
127
+ def resource_base_uri
128
+ "#{@subscriber.uri}#{@sport.name}/"
129
+ end
130
+
131
+ protected
132
+
133
+ #
134
+ # :category: Invalidation
135
+ #
136
+ # Sets the uri to the base uri if neither the subscriber, nor the sport is
137
+ # nil.
138
+ #
139
+ def invalidate_uri
140
+ unless @subscriber.nil? || @sport.nil?
141
+ @uri = resource_base_uri
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,159 @@
1
+ module CyberCoach
2
+ #
3
+ # A User is needed to participate in Partnerships and Subscriptions, to which
4
+ # Entries are submitted.
5
+ #
6
+ class User < Resource
7
+ #
8
+ # It is pageable.
9
+ #
10
+ include Pageable
11
+
12
+ #
13
+ # It is creatable by PUT.
14
+ #
15
+ include PutCreateable
16
+
17
+ #
18
+ # :attr: username
19
+ # The username.
20
+ #
21
+
22
+ #
23
+ # :attr: email
24
+ # The email address.
25
+ #
26
+
27
+ #
28
+ # :attr: password
29
+ # The password, which is never received from the server.
30
+ #
31
+
32
+ #
33
+ # :attr: real_name
34
+ # The real name.
35
+ #
36
+
37
+ #
38
+ # :attr: privacy_level
39
+ # The privacy level, see PrivacyLevel constants.
40
+ #
41
+
42
+ #
43
+ # :attr: date_created
44
+ # The date it was created.
45
+ #
46
+
47
+ attr_accessor :username,
48
+ :email,
49
+ :password,
50
+ :real_name,
51
+ :privacy_level,
52
+ :date_created
53
+
54
+ #
55
+ # :category: Serialization
56
+ #
57
+ # Creates itself from a serializable representation, which only contains
58
+ # simple data types.
59
+ # serializable:: A hash with the keys:
60
+ # * uri:: The URI.
61
+ # * id:: The identifier.
62
+ # * username:: The username.
63
+ # * email:: The email address.
64
+ # * realname:: The real name.
65
+ # * publicvisible:: The privacy level, see PrivacyLevel constants.
66
+ # * datecreated:: The date it was created.
67
+ #
68
+ def from_serializable(serializable)
69
+ super(serializable)
70
+ @username = serializable['username']
71
+ @email = serializable['email']
72
+ # the password is never received from the server, so don't set it
73
+ @real_name = serializable['realname']
74
+ @privacy_level = serializable['publicvisible']
75
+ @date_created = nil
76
+ unless serializable['datecreated'].nil?
77
+ @date_created = Time.at(serializable['datecreated']).to_datetime
78
+ end
79
+ end
80
+
81
+ #
82
+ # :category: Serialization
83
+ #
84
+ # Returns a serializable representation, which only contains simple data
85
+ # types.
86
+ # The hash has the keys:
87
+ # * uri:: The URI.
88
+ # * id:: The identifier.
89
+ # * username:: The username.
90
+ # * email:: The email address.
91
+ # * realname:: The real name.
92
+ # * publicvisible:: The privacy level, see PrivacyLevel constants.
93
+ # * datecreated:: The date it was created.
94
+ #
95
+ def to_serializable
96
+ serializable = super
97
+ serializable['username'] = @username
98
+ serializable['email'] = @email
99
+ serializable['password'] = @password
100
+ serializable['realname'] = @real_name
101
+ serializable['publicvisible'] = @privacy_level
102
+ serializable
103
+ end
104
+
105
+ #
106
+ # Returns the authentication options for basic auth, to pass in CRUD methods
107
+ # of other resources.
108
+ #
109
+ def authentication
110
+ {
111
+ basic_auth: {
112
+ username: @username,
113
+ password: @password
114
+ }
115
+ }
116
+ end
117
+
118
+ #
119
+ # :category: Configuration
120
+ #
121
+ # Returns 'user'.
122
+ #
123
+ def singular_name
124
+ 'user'
125
+ end
126
+
127
+ #
128
+ # :category: Configuration
129
+ #
130
+ # Returns 'users'.
131
+ #
132
+ def plural_name
133
+ 'users'
134
+ end
135
+
136
+ protected
137
+
138
+ #
139
+ # :category: Invalidation
140
+ #
141
+ # Sets the uri to the base uri and the username, if it is not nil.
142
+ #
143
+ def invalidate_uri
144
+ unless @username.nil?
145
+ @uri = "#{resource_base_uri}#{@username}/"
146
+ end
147
+ end
148
+
149
+ #
150
+ # :category: Invalidation
151
+ #
152
+ # Sets the basic auth token to the login, so it can be updated and deleted
153
+ # without explicitly specifying the token.
154
+ #
155
+ def invalidate_options
156
+ @options = @options.merge(authentication)
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,10 @@
1
+ #
2
+ # Provides a proxy to CyberCoach resources.
3
+ # Enables to make CRUD calls to them.
4
+ #
5
+ module CyberCoach
6
+ #
7
+ # The current version of the gem.
8
+ #
9
+ VERSION = '0.3.0'
10
+ end
data/lib/cybercoach.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'httparty'
2
+
3
+ require 'cybercoach/version'
4
+ require 'cybercoach/privacy_level'
5
+ require 'cybercoach/settings'
6
+ require 'cybercoach/format_not_supported_error'
7
+ require 'cybercoach/http_error'
8
+ require 'cybercoach/subclass_responsibility_error'
9
+ require 'cybercoach/abstract_resource'
10
+ require 'cybercoach/resource'
11
+ require 'cybercoach/resource_page'
12
+ require 'cybercoach/pageable'
13
+ require 'cybercoach/post_createable'
14
+ require 'cybercoach/put_createable'
15
+ require 'cybercoach/sport'
16
+ require 'cybercoach/user'
17
+ require 'cybercoach/partnership'
18
+ require 'cybercoach/subscription'
19
+ require 'cybercoach/entry'
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Entry' do
4
+ before(:context) do
5
+ @proposer = UserHelper.make(6)
6
+ @proposed = UserHelper.make(7)
7
+ ResourceHelper.safe_delete(@proposer)
8
+ ResourceHelper.safe_delete(@proposed)
9
+ @proposer.create
10
+ @proposed.create
11
+ @partnership = CyberCoach::Partnership.new
12
+ @partnership.proposer = @proposer
13
+ @partnership.proposed = @proposed
14
+ @partnership.privacy_level = CyberCoach::PrivacyLevel::REGISTERED_USER
15
+ ResourceHelper.safe_delete(@partnership, UserHelper.options(@proposer))
16
+ ResourceHelper.safe_delete(@partnership, UserHelper.options(@proposed))
17
+ @partnership.create(UserHelper.options(@proposer))
18
+ @partnership.update(UserHelper.options(@proposed))
19
+ @sport = CyberCoach::Sport.new
20
+ @sport.name = 'Running'
21
+ @sport.read
22
+ @subscription = CyberCoach::Subscription.new
23
+ @subscription.subscriber = @partnership
24
+ @subscription.sport = @sport
25
+ @subscription.privacy_level = CyberCoach::PrivacyLevel::REGISTERED_USER
26
+ @subscription.create(UserHelper.options(@proposer))
27
+ end
28
+
29
+ after(:context) do
30
+ ResourceHelper.safe_delete(@subscription, UserHelper.options(@proposer))
31
+ ResourceHelper.safe_delete(@partnership, UserHelper.options(@proposer))
32
+ ResourceHelper.safe_delete(@partnership, UserHelper.options(@proposed))
33
+ ResourceHelper.safe_delete(@proposer)
34
+ ResourceHelper.safe_delete(@proposed)
35
+ end
36
+
37
+ before(:example) do
38
+ @entry = CyberCoach::Entry.new
39
+ @entry.subscription = @subscription
40
+ @entry.comment = 'I like pants'
41
+ @entry.location = 'In your pants'
42
+ @entry.duration = 1
43
+ @entry.privacy_level = CyberCoach::PrivacyLevel::REGISTERED_USER
44
+ end
45
+
46
+ it 'should raise an error if it does not exist' do
47
+ @entry.id = 1
48
+ expect { @entry.read(UserHelper.options(@proposer)) }.to raise_error(CyberCoach::HttpError)
49
+ end
50
+
51
+ describe 'crud' do
52
+ before(:example) do
53
+ ResourceHelper.safe_delete(@entry, UserHelper.options(@proposer))
54
+ end
55
+
56
+ after(:example) do
57
+ ResourceHelper.safe_delete(@entry, UserHelper.options(@proposer))
58
+ end
59
+
60
+ it 'should create itself' do
61
+ @entry.create(UserHelper.options(@proposer))
62
+ expect(@entry.id).not_to be_nil
63
+ end
64
+
65
+ it 'should read itself' do
66
+ @entry.create(UserHelper.options(@proposer))
67
+ @entry.read(UserHelper.options(@proposer))
68
+ expect(@entry.id).not_to be_nil
69
+ expect(@entry.uri).not_to be_nil
70
+ expect(@entry.subscription.uri).to eq(@subscription.uri)
71
+ expect(@entry.comment).not_to be_nil
72
+ expect(@entry.location).not_to be_nil
73
+ expect(@entry.duration).not_to be_nil
74
+ expect(@entry.privacy_level).not_to be_nil
75
+ expect(@entry.date_created).not_to be_nil
76
+ expect(@entry.date_modified).not_to be_nil
77
+ end
78
+
79
+ it 'should update itself' do
80
+ @entry.create(UserHelper.options(@proposer))
81
+ old_privacy_level = @entry.privacy_level
82
+ new_privacy_level = CyberCoach::PrivacyLevel::EVERYBODY
83
+ @entry.privacy_level = new_privacy_level
84
+ @entry.update(UserHelper.options(@proposer))
85
+ expect(@entry.privacy_level).not_to eq(old_privacy_level)
86
+ expect(@entry.privacy_level).to eq(new_privacy_level)
87
+ end
88
+
89
+ it 'should delete itself' do
90
+ @entry.create(UserHelper.options(@proposer))
91
+ @entry.delete(UserHelper.options(@proposer))
92
+ expect { @entry.read(UserHelper.options(@proposer)) }.to raise_error(CyberCoach::HttpError)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Partnership' do
4
+ before(:context) do
5
+ @proposer = UserHelper.make(6)
6
+ @proposed = UserHelper.make(7)
7
+ ResourceHelper.safe_delete(@proposer)
8
+ ResourceHelper.safe_delete(@proposed)
9
+ @proposer.create
10
+ @proposed.create
11
+ end
12
+
13
+ after(:context) do
14
+ ResourceHelper.safe_delete(@proposer)
15
+ ResourceHelper.safe_delete(@proposed)
16
+ end
17
+
18
+ before(:example) do
19
+ @partnership = CyberCoach::Partnership.new
20
+ @partnership.proposer = @proposer
21
+ @partnership.proposed = @proposed
22
+ @partnership.privacy_level = CyberCoach::PrivacyLevel::REGISTERED_USER
23
+ end
24
+
25
+ it 'should raise an error if it does not exist' do
26
+ expect { @partnership.read(UserHelper.options(@proposer)) }.to raise_error(CyberCoach::HttpError)
27
+ end
28
+
29
+ it 'should read all' do
30
+ partnerships = CyberCoach::Partnership.read_all
31
+ expect(partnerships.resources).not_to be_empty
32
+ expect(partnerships.next).not_to be_nil
33
+ expect { partnerships.previous }.to raise_error(CyberCoach::ResourcePage::NoPreviousPageError)
34
+ end
35
+
36
+ describe 'crud' do
37
+ before(:example) do
38
+ ResourceHelper.safe_delete(@partnership, UserHelper.options(@proposer))
39
+ end
40
+
41
+ after(:example) do
42
+ ResourceHelper.safe_delete(@partnership, UserHelper.options(@proposer))
43
+ end
44
+
45
+ it 'should create itself' do
46
+ @partnership.create(UserHelper.options(@proposer))
47
+ expect(@partnership.id).not_to be_nil
48
+ end
49
+
50
+ it 'should read itself' do
51
+ @partnership.create(UserHelper.options(@proposer))
52
+ @partnership.read(UserHelper.options(@proposer))
53
+ expect(@partnership.id).not_to be_nil
54
+ expect(@partnership.uri).not_to be_nil
55
+ expect(@partnership.proposer.uri).to eq(@proposer.uri)
56
+ expect(@partnership.proposed.uri).to eq(@proposed.uri)
57
+ expect(@partnership.confirmed_by_proposer).to be_truthy
58
+ expect(@partnership.confirmed_by_proposed).to be_falsy
59
+ expect(@partnership.privacy_level).not_to be_nil
60
+ expect(@partnership.subscriptions).to be_empty
61
+ end
62
+
63
+ it 'should update itself' do
64
+ @partnership.create(UserHelper.options(@proposer))
65
+ old_privacy_level = @partnership.privacy_level
66
+ new_privacy_level = CyberCoach::PrivacyLevel::EVERYBODY
67
+ @partnership.privacy_level = new_privacy_level
68
+ @partnership.update(UserHelper.options(@proposer))
69
+ expect(@partnership.privacy_level).not_to eq(old_privacy_level)
70
+ expect(@partnership.privacy_level).to eq(new_privacy_level)
71
+ end
72
+
73
+ it 'should delete itself' do
74
+ @partnership.create(UserHelper.options(@proposer))
75
+ @partnership.delete(UserHelper.options(@proposer))
76
+ expect { @partnership.read(UserHelper.options(@proposer)) }.to raise_error(CyberCoach::HttpError)
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'PrivacyLevel' do
4
+ it 'should have an OWNER level' do
5
+ expect(CyberCoach::PrivacyLevel::OWNER).to eq(0)
6
+ end
7
+
8
+ it 'should have an REGISTERED_USER level' do
9
+ expect(CyberCoach::PrivacyLevel::REGISTERED_USER).to eq(1)
10
+ end
11
+
12
+ it 'should have an EVERYBODY level' do
13
+ expect(CyberCoach::PrivacyLevel::EVERYBODY).to eq(2)
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ require 'cybercoach'
2
+
3
+ class ResourceHelper
4
+ def self.safe_delete(resource, options={})
5
+ begin
6
+ resource.delete(options)
7
+ rescue => error
8
+ $stderr.puts error
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ResourcePage' do
4
+ before(:example) do
5
+ @page = CyberCoach::User.read_all
6
+ end
7
+
8
+ it 'should have meta data' do
9
+ expect(@page.resources.size).to eq(5)
10
+ expect(@page.start).to eq(0)
11
+ expect(@page.end).to eq(5)
12
+ expect(@page.available).to be > 5
13
+ expect(@page.type).to eq(CyberCoach::User)
14
+ end
15
+
16
+ it 'should have resources of its type' do
17
+ type = @page.type
18
+ @page.resources.each do |item|
19
+ expect(item).to be_a_kind_of(type)
20
+ end
21
+ end
22
+
23
+ it 'should read itself' do
24
+ @page.start = 1
25
+ @page.size = 2
26
+ @page.read
27
+ expect(@page.resources.size).to eq(2)
28
+ expect(@page.start).to eq(1)
29
+ expect(@page.end).to eq(3)
30
+ end
31
+
32
+ it 'should be able to navigate between pages' do
33
+ expect{@page.previous}.to raise_error(CyberCoach::ResourcePage::NoPreviousPageError)
34
+ next_page = @page.next
35
+ expect(next_page.resources).not_to be_empty
36
+ expect(next_page.start).to eq(@page.end)
37
+ expect(next_page.end).to eq(next_page.start + 5)
38
+ expect(next_page.available).to eq(@page.available)
39
+ expect(next_page.type).to eq(@page.type)
40
+ expect(next_page.resources[0].uri).not_to eq(@page.resources[0].uri)
41
+ next_previous_page = next_page.previous
42
+ expect(next_previous_page.resources[0].uri).to eq(@page.resources[0].uri)
43
+ end
44
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Settings' do
4
+ it 'should have a base URI' do
5
+ expect(CyberCoach::Settings::BASE_URI).not_to be_nil
6
+ end
7
+ it 'should have a server URI' do
8
+ expect(CyberCoach::Settings::SERVER_URI).not_to be_nil
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Sport' do
4
+ before(:example) do
5
+ @sport = CyberCoach::Sport.new
6
+ end
7
+
8
+ it 'should read itself' do
9
+ @sport.name = 'Running'
10
+ @sport.read
11
+ expect(@sport.id).not_to be_nil
12
+ expect(@sport.uri).not_to be_nil
13
+ expect(@sport.name).not_to be_nil
14
+ expect(@sport.description).not_to be_nil
15
+ expect(@sport.subscriptions).not_to be_empty
16
+ end
17
+
18
+ it 'should raise an error if it does not exist' do
19
+ @sport.name = 'Pants'
20
+ expect{@sport.read}.to raise_error(CyberCoach::HttpError)
21
+ end
22
+
23
+ it 'should read all' do
24
+ sports = CyberCoach::Sport.read_all
25
+ expect(sports.resources.size).to eq(4)
26
+ expect{sports.next}.to raise_error(CyberCoach::ResourcePage::NoNextPageError)
27
+ expect{sports.previous}.to raise_error(CyberCoach::ResourcePage::NoPreviousPageError)
28
+ end
29
+ end