cybercoach 0.2.0 → 0.3.0

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