ctws 0.1.5.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.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +295 -0
  4. data/Rakefile +21 -0
  5. data/app/auth/ctws/authenticate_user.rb +36 -0
  6. data/app/auth/ctws/authorize_api_request.rb +44 -0
  7. data/app/controllers/concerns/ctws/exception_handler.rb +58 -0
  8. data/app/controllers/concerns/ctws/response.rb +25 -0
  9. data/app/controllers/concerns/ctws/v1/exception_handler.rb +6 -0
  10. data/app/controllers/concerns/ctws/v1/response.rb +6 -0
  11. data/app/controllers/ctws/application_controller.rb +5 -0
  12. data/app/controllers/ctws/authentication_controller.rb +28 -0
  13. data/app/controllers/ctws/ctws_controller.rb +24 -0
  14. data/app/controllers/ctws/min_app_versions_controller.rb +55 -0
  15. data/app/controllers/ctws/users_controller.rb +39 -0
  16. data/app/controllers/ctws/v1/authentication_controller.rb +6 -0
  17. data/app/controllers/ctws/v1/ctws_controller.rb +9 -0
  18. data/app/controllers/ctws/v1/min_app_versions_controller.rb +6 -0
  19. data/app/controllers/ctws/v1/users_controller.rb +6 -0
  20. data/app/controllers/ctws/v2/ctws_controller.rb +9 -0
  21. data/app/controllers/ctws/v2/min_app_versions_controller.rb +6 -0
  22. data/app/jobs/ctws/application_job.rb +4 -0
  23. data/app/lib/ctws/json_web_token.rb +25 -0
  24. data/app/lib/ctws/message.rb +43 -0
  25. data/app/mailers/ctws/application_mailer.rb +6 -0
  26. data/app/models/ctws/application_record.rb +5 -0
  27. data/app/models/ctws/min_app_version.rb +22 -0
  28. data/config/initializers/ctws.rb +5 -0
  29. data/config/initializers/mime_types.rb +1 -0
  30. data/config/routes.rb +18 -0
  31. data/db/migrate/20170425110839_create_ctws_min_app_versions.rb +13 -0
  32. data/db/migrate/20170425110933_add_values_to_ctws_min_app_versions.rb +26 -0
  33. data/lib/ctws/engine.rb +13 -0
  34. data/lib/ctws/version.rb +3 -0
  35. data/lib/ctws.rb +18 -0
  36. data/lib/tasks/ctws_tasks.rake +4 -0
  37. data/spec/auth/ctws/authenticate_user_spec.rb +34 -0
  38. data/spec/auth/ctws/authorize_api_request_spec.rb +62 -0
  39. data/spec/controllers/ctws/ctws_controller_spec.rb +41 -0
  40. data/spec/controllers/ctws/users_controller_spec.rb +7 -0
  41. data/spec/dummy/Rakefile +6 -0
  42. data/spec/dummy/app/assets/config/manifest.js +5 -0
  43. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  44. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  45. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  46. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  47. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  48. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  49. data/spec/dummy/app/controllers/user_controller.rb +18 -0
  50. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  51. data/spec/dummy/app/helpers/user_helper.rb +2 -0
  52. data/spec/dummy/app/jobs/application_job.rb +2 -0
  53. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  54. data/spec/dummy/app/models/application_record.rb +3 -0
  55. data/spec/dummy/app/models/user.rb +4 -0
  56. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  57. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  58. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  59. data/spec/dummy/bin/bundle +3 -0
  60. data/spec/dummy/bin/rails +4 -0
  61. data/spec/dummy/bin/rake +4 -0
  62. data/spec/dummy/bin/setup +34 -0
  63. data/spec/dummy/bin/update +29 -0
  64. data/spec/dummy/config/application.rb +15 -0
  65. data/spec/dummy/config/boot.rb +5 -0
  66. data/spec/dummy/config/cable.yml +9 -0
  67. data/spec/dummy/config/database.yml +25 -0
  68. data/spec/dummy/config/environment.rb +5 -0
  69. data/spec/dummy/config/environments/development.rb +54 -0
  70. data/spec/dummy/config/environments/production.rb +86 -0
  71. data/spec/dummy/config/environments/test.rb +42 -0
  72. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  73. data/spec/dummy/config/initializers/assets.rb +11 -0
  74. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  75. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  76. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  77. data/spec/dummy/config/initializers/inflections.rb +16 -0
  78. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  79. data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
  80. data/spec/dummy/config/initializers/session_store.rb +3 -0
  81. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  82. data/spec/dummy/config/locales/en.yml +23 -0
  83. data/spec/dummy/config/puma.rb +47 -0
  84. data/spec/dummy/config/routes.rb +5 -0
  85. data/spec/dummy/config/secrets.yml +22 -0
  86. data/spec/dummy/config/spring.rb +6 -0
  87. data/spec/dummy/config.ru +5 -0
  88. data/spec/dummy/db/development.sqlite3 +0 -0
  89. data/spec/dummy/db/migrate/20170622072636_create_users.rb +10 -0
  90. data/spec/dummy/db/schema.rb +39 -0
  91. data/spec/dummy/db/test.sqlite3 +0 -0
  92. data/spec/dummy/log/development.log +29 -0
  93. data/spec/dummy/log/test.log +31496 -0
  94. data/spec/dummy/public/404.html +67 -0
  95. data/spec/dummy/public/422.html +67 -0
  96. data/spec/dummy/public/500.html +66 -0
  97. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  98. data/spec/dummy/public/apple-touch-icon.png +0 -0
  99. data/spec/dummy/public/favicon.ico +0 -0
  100. data/spec/factories/ctws/ctws_user.rb +7 -0
  101. data/spec/factories/ctws_min_app_version.rb +9 -0
  102. data/spec/models/ctws/min_app_version_spec.rb +11 -0
  103. data/spec/models/ctws/user_spec.rb +8 -0
  104. data/spec/rails_helper.rb +88 -0
  105. data/spec/requests/ctws/authentication_spec.rb +47 -0
  106. data/spec/requests/ctws/min_app_version_spec.rb +169 -0
  107. data/spec/requests/ctws/users_spec.rb +46 -0
  108. data/spec/spec_helper.rb +27 -0
  109. data/spec/support/ctws/controller_spec_helper.rb +29 -0
  110. data/spec/support/ctws/request_spec_helper.rb +10 -0
  111. metadata +367 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0a79d5e21625b0567f9a3cca15eaee2828f01a34
4
+ data.tar.gz: 4ca11d4f89b12d6b0c353cbc0541efb9a7b2d07c
5
+ SHA512:
6
+ metadata.gz: b7d96fa180bc72676e003910f0ef4cf6aec988db26625dbbd39d67a0e5b9a96675df1969ea574b74275761766fe0068d70eaa1f50ecfb552d0afffe5879626ae
7
+ data.tar.gz: 22a334939b4b7f159d62fa9d01f6db7cec8dae94e4f7232852aac0113ebfec742b09eb3971652574994e0211a44e3d7d9dd827f90e2ad4a26f493f53986371b3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 CodiTramuntana
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,295 @@
1
+ # ctws
2
+
3
+ Rails gem to be used as Webservice RESTful JSON API with Rails 5.
4
+
5
+ With `MinAppVersion` and `User` resources, with token based authentication [JSON Web Tokens](https://jwt.io/).
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'ctws'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install ctws
22
+ ```
23
+
24
+ ## Mounting the Engine
25
+
26
+ To make the `ctws` engine's functionality accessible from within your application, it needs to be mounted in that application's `config/routes.rb` file:
27
+
28
+ ```ruby
29
+ mount Ctws::Engine, at: "/ws"
30
+ ```
31
+
32
+ This line will mount the engine at `/ws` in the application. Making it accessible at `http://localhost:3000/ws` when the application runs with rails
33
+ server. It can be whatever you want.
34
+
35
+ ## Engine setup
36
+
37
+ The engine contains migrations for the `ctws_min_app_version` and `xxx` table which need to be created in the application's database so that the engine's models can query them correctly.
38
+ To copy these migrations into the application run the following command from the Rails App root, then run these migrations:
39
+
40
+ ```bash
41
+ rails ctws:install:migrations
42
+ rails db:migrate
43
+ ```
44
+
45
+ If you want to revert engine's migrations before removing it. To revert all migrations from blorgh engine you can run code such as:
46
+
47
+ ```bash
48
+ bin/rails db:migrate SCOPE=ctws VERSION=0
49
+ ```
50
+
51
+ ### Hook the application `User` model with the engine
52
+
53
+ By default the user model is `User` but you can change it by creating or editing the `ctws.rb` initializer file in `config/initializers` and put this content in it:
54
+
55
+ ```ruby
56
+ Ctws.user_class = "Account"
57
+ ```
58
+
59
+ The application `User` model **must have the `email` attribute**.
60
+
61
+ The **`password` is optional** by default a user is validated with password, for `password` validation [`ActiveModel::SecurePassword::InstanceMethodsOnActivation authenticate`](https://apidock.com/rails/v4.2.7/ActiveModel/SecurePassword/InstanceMethodsOnActivation/authenticate) and [`Devise::Models::DatabaseAuthenticatable#valid_password?`](http://www.rubydoc.info/github/plataformatec/devise/Devise%2FModels%2FDatabaseAuthenticatable:valid_password%3F) User instance methods are supported.
62
+
63
+ To opt out the user validation with the password change it by creating or editing the `ctws.rb` initializer file in `config/initializers` and put this content in it:
64
+
65
+ ```ruby
66
+ Ctws.user_validate_with_password = false
67
+ ```
68
+ You can edit your app's required fields for signup by creating or editing the `ctws.rb` initializer file in `config/initializers` and put your strong parameters:
69
+
70
+ ```ruby
71
+ Ctws.user_class_strong_params = %i(email password password_confirmation
72
+ ```
73
+
74
+ ### Set the `JWT` expiry time
75
+
76
+ By default the token expiry time is 24h but you can change it by creating or editing the `ctws.rb` initializer file in `config/initializers` and put this content in it:
77
+
78
+ ```ruby
79
+ Ctws.jwt_expiration_time = 24.hours.from_now
80
+ ```
81
+
82
+ <!--
83
+ Change the app's models so that they know that they are supposed to act like ctws:
84
+
85
+ ```ruby
86
+ # app/models/user.rb
87
+
88
+ class User < ApplicationRecord
89
+ acts_as_ctws
90
+ end
91
+ ```
92
+ -->
93
+
94
+ ## Endpoints
95
+
96
+ | Endpoint | Functionality | Requires Authentication? |
97
+ | -------------------------------------------------- | -----------------------------------------------: | :-----------------------: |
98
+ | `GET /ctws/v1/min_app_version` | Get latest minimum app version for all platforms | No |
99
+ | `POST /ctws/signup` | Signup | No |
100
+ | `POST /ctws/login` | Login | No |
101
+ <!--
102
+ | `GET /ctws/v1/min_app_versions` | List all min_app_versions | Yes |
103
+ | `GET /ctws/v1/min_app_versions/:id ` | Get a min_app_version | Yes |
104
+ | `POST /ctws/v1/min_app_versions` | Creates a min_app_version | Yes |
105
+ | `PUT /ctws/v1/min_app_versions/:id` | Updates a min_app_version | Yes |
106
+ | `DELETE /ctws/v1/min_app_versions/:id` | Delete a min_app_version | Yes |
107
+ -->
108
+
109
+ ### min_app_version
110
+
111
+ **request:**
112
+
113
+ ```bash
114
+ curl localhost:3000/ws/v1/min_app_version
115
+ ```
116
+
117
+ **response:**
118
+
119
+ ```json
120
+ HTTP/1.1 200 OK
121
+ Cache-Control: max-age=0, private, must-revalidate
122
+ Content-Type: application/vnd.api+json; charset=utf-8
123
+ ETag: W/"8dcf1379b7ee203a6d72b3c7773d47f4"
124
+ Transfer-Encoding: chunked
125
+ X-Content-Type-Options: nosniff
126
+ X-Frame-Options: SAMEORIGIN
127
+ X-Request-Id: c1924546-0212-45fe-b86a-83ee3a3b2fa4
128
+ X-Runtime: 0.003897
129
+ X-XSS-Protection: 1; mode=block
130
+
131
+ {
132
+ "data": [
133
+ {
134
+ "id": 3,
135
+ "type": "min_app_version",
136
+ "attributes": {
137
+ "codename": "Second release",
138
+ "description": "Second release Description text",
139
+ "min_version": "0.0.2",
140
+ "platform": "android",
141
+ "store_uri": "htttps://fdsafdsafdsaf.cot",
142
+ "updated_at": "2017-06-22T17:53:31.252+02:00"
143
+ }
144
+ },
145
+ {
146
+ "type": "min_app_version",
147
+ "id": 1,
148
+ "attributes": {
149
+ "codename": "First Release",
150
+ "description": "You need to update your app. You will be redirected to the corresponding store",
151
+ "min_version": "0.0.1",
152
+ "platform": "ios",
153
+ "store_uri": "https://itunes.apple.com/",
154
+ "updated_at": "2017-06-21T14:29:59.348+02:00"
155
+ }
156
+ }
157
+ ]
158
+ }
159
+ ```
160
+ ### signup
161
+
162
+ **request:**
163
+
164
+ ```bash
165
+ curl -X POST -F "email=user@example.com" -F "password=123456789" http://localhost:3000/ws/v1/signup
166
+ ```
167
+
168
+ **Successful response:**
169
+
170
+ ```json
171
+ HTTP/1.1 201 Created
172
+ Cache-Control: max-age=0, private, must-revalidate
173
+ Content-Type: application/vnd.api+json; charset=utf-8
174
+ ETag: W/"ab43e77c2d67636c5c0cd707e661c311"
175
+ Transfer-Encoding: chunked
176
+ X-Content-Type-Options: nosniff
177
+ X-Frame-Options: SAMEORIGIN
178
+ X-Request-Id: 75f9d9cc-4ce2-4aed-9349-e995bb122f39
179
+ X-Runtime: 1.727068
180
+ X-XSS-Protection: 1; mode=block
181
+
182
+ {
183
+ "data": {
184
+ "type": "user",
185
+ "id": 20,
186
+ "attributes": {
187
+ "message": "Account created successfully",
188
+ "auth_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyMCwiZXhwIjoxNDk5ODU1MjQ5fQ.H9ljjShWOAv8b9xn9ZLKv-zgmH8xkPe6dkdhH4JrJPw",
189
+ "created_at": "2017-07-11T12:27:27.916+02:00"
190
+ }
191
+ }
192
+ }
193
+ ```
194
+
195
+ **Error response:**
196
+
197
+ ```json
198
+ HTTP/1.1 401 Unauthorized
199
+ Cache-Control: no-cache
200
+ Content-Type: application/vnd.api+json; charset=utf-8
201
+ Transfer-Encoding: chunked
202
+ X-Content-Type-Options: nosniff
203
+ X-Frame-Options: SAMEORIGIN
204
+ X-Request-Id: b0d91125-446d-4ed3-95cb-4a702ee24289
205
+ X-Runtime: 0.091940
206
+ X-XSS-Protection: 1; mode=block
207
+
208
+ {
209
+ "errors": {
210
+ "message": "Invalid credentials"
211
+ }
212
+ }
213
+ ```
214
+
215
+ ### login
216
+
217
+ **request:**
218
+
219
+ ```bash
220
+ curl -X POST -F "email=user@example.com" -F "password=123456789" http://localhost:3000/ws/v1/login
221
+ ```
222
+
223
+ **Successful response:**
224
+
225
+ ```json
226
+ HTTP/1.1 200 OK
227
+ Cache-Control: max-age=0, private, must-revalidate
228
+ Content-Type: application/vnd.api+json; charset=utf-8
229
+ ETag: W/"4e7a5faaf9eb480a7a7dadb734d01da1"
230
+ Transfer-Encoding: chunked
231
+ X-Content-Type-Options: nosniff
232
+ X-Frame-Options: SAMEORIGIN
233
+ X-Request-Id: 565a8015-9087-480c-b5b6-1dbf634c7d83
234
+ X-Runtime: 0.278055
235
+ X-XSS-Protection: 1; mode=block
236
+
237
+ {
238
+ "data": {
239
+ "type": "authentication",
240
+ "attributes": {
241
+ "message": "Authenticated user successfully",
242
+ "auth_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxNiwiZXhwIjoxNDk5ODU2MDgyfQ.FOLNcInu0yxnp_dqVnyzfzGNwKyv_ERoflhW4cvTa60"
243
+ }
244
+ }
245
+ }
246
+ ```
247
+
248
+ **Error response:**
249
+
250
+ ```json
251
+ HTTP/1.1 401 Unauthorized
252
+ Cache-Control: no-cache
253
+ Content-Type: application/vnd.api+json; charset=utf-8
254
+ Transfer-Encoding: chunked
255
+ X-Content-Type-Options: nosniff
256
+ X-Frame-Options: SAMEORIGIN
257
+ X-Request-Id: e95e4b63-3a83-409f-bd05-4cf2dea6136a
258
+ X-Runtime: 0.015463
259
+ X-XSS-Protection: 1; mode=block
260
+
261
+ {
262
+ "errors": {
263
+ "message": "Invalid credentials"
264
+ }
265
+ }
266
+ ```
267
+
268
+ ## Tests
269
+
270
+ running `rspec` will run tests and output a report, first run migrations the tests:
271
+
272
+ ```bash
273
+ rails db:migrate RAILS_ENV=test
274
+ rspec
275
+ ```
276
+
277
+ ## Contributing
278
+
279
+ Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
280
+
281
+ ## License
282
+
283
+ `ctws` is Copyright © 2017 CodiTramuntana SL. It is free software, and may be redistributed under the terms specified in the LICENSE file.
284
+
285
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
286
+
287
+ # About CodiTramuntana
288
+
289
+ ![CodiTramuntana's Logo](https://avatars0.githubusercontent.com/u/27996979?v=3&u=b0256e23ae7b2f237e3d1b5f2b2abdfe3092b24c&s=400)
290
+
291
+ Maintained by [CodiTramuntana](http://www.coditramuntana.com).
292
+
293
+ The names and logos for CodiTramuntana are trademarks of CodiTramuntana SL.
294
+
295
+ We love open source software!
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
9
+ load 'rails/tasks/engine.rake'
10
+
11
+ Bundler::GemHelper.install_tasks
12
+
13
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
14
+
15
+ require 'rspec/core'
16
+ require 'rspec/core/rake_task'
17
+
18
+ desc "Run all specs in spec directory (excluding plugin specs)"
19
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
20
+
21
+ task :default => :spec
@@ -0,0 +1,36 @@
1
+ module Ctws
2
+ class AuthenticateUser
3
+ def initialize(email, password="12346")
4
+ @email = email
5
+ @password = password
6
+ end
7
+
8
+ # Service entry point
9
+ def call
10
+ Ctws::JsonWebToken.encode(user_id: user.id) if user
11
+
12
+ # attrs_hash = {}
13
+ # Ctws.jwt_auth_token_attrs.each {|a| attrs_hash.merge!({"user_#{a}": user.try(a)})}
14
+ # Ctws::JsonWebToken.encode(attrs_hash) if user
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :email, :password
20
+
21
+ # verify user credentials
22
+ def user
23
+ user = Ctws.user_class.find_by(email: email)
24
+
25
+ if Ctws.user_validate_with_password
26
+ # try method of Active Record's has_secure_password or Devise valid_password?
27
+ authenticated = user.try(:authenticate, password) || user.try(:valid_password?, password)
28
+ elsif !Ctws.user_validate_with_password
29
+ authenticated = true
30
+ end
31
+ return user if user && authenticated
32
+ # raise Authentication error if credentials are invalid
33
+ raise(Ctws::ExceptionHandler::AuthenticationError, Ctws::Message.invalid_credentials)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ module Ctws
2
+ class AuthorizeApiRequest
3
+ def initialize(headers = {})
4
+ @headers = headers
5
+ end
6
+
7
+ # Service entry point - return valid user object
8
+ def call
9
+ {
10
+ user: user
11
+ }
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :headers
17
+
18
+ def user
19
+ # check if user is in the database
20
+ # memoize user object
21
+ @user ||= Ctws.user_class.find(decoded_auth_token[:user_id]) if decoded_auth_token
22
+ # handle user not found
23
+ rescue ActiveRecord::RecordNotFound => e
24
+ # raise custom error
25
+ raise(
26
+ ExceptionHandler::InvalidToken,
27
+ ("#{Ctws::Message.invalid_token} #{e.message}")
28
+ )
29
+ end
30
+
31
+ # decode authentication token
32
+ def decoded_auth_token
33
+ @decoded_auth_token ||= Ctws::JsonWebToken.decode(http_auth_header)
34
+ end
35
+
36
+ # check for token in `Authorization` header
37
+ def http_auth_header
38
+ if headers['Authorization'].present?
39
+ return headers['Authorization'].split(' ').last
40
+ end
41
+ raise(ExceptionHandler::MissingToken, Ctws::Message.missing_token)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ module Ctws
2
+ # In the case where the record does not exist,
3
+ # ActiveRecord will throw an exception ActiveRecord::RecordNotFound.
4
+ # We'll rescue from this exception and return a 404 message.
5
+ # List of Rails Status Code Symbols http://billpatrianakos.me/blog/2013/10/13/list-of-rails-status-code-symbols
6
+
7
+ module ExceptionHandler
8
+ # provides the more graceful `included` method
9
+ extend ActiveSupport::Concern
10
+
11
+ # Define custom error subclasses - rescue catches `StandardErrors`
12
+ class AuthenticationError < StandardError; end
13
+ class MissingToken < StandardError; end
14
+ class InvalidToken < StandardError; end
15
+ class ExpiredSignature < StandardError; end
16
+ class UnprocessableEntity < StandardError; end
17
+ class RoutingError < StandardError; end
18
+
19
+ included do
20
+ # Define custom handlers
21
+ rescue_from ActiveRecord::RecordInvalid, with: :four_twenty_two
22
+ rescue_from ExceptionHandler::AuthenticationError, with: :unauthorized_request
23
+ rescue_from ExceptionHandler::MissingToken, with: :four_twenty_two
24
+ rescue_from ExceptionHandler::InvalidToken, with: :four_twenty_two
25
+ rescue_from ExceptionHandler::UnprocessableEntity, with: :four_twenty_two
26
+ rescue_from ExceptionHandler::ExpiredSignature, with: :four_ninety_eight
27
+ rescue_from ExceptionHandler::RoutingError, with: :not_found
28
+ rescue_from ActiveRecord::RecordNotFound, with: :not_found
29
+ rescue_from ActionController::RoutingError, with: :not_found
30
+
31
+ rescue_from ActiveRecord::RecordInvalid do |e|
32
+ json_response({ message: e.message }, :unprocessable_entity)
33
+ end
34
+ end
35
+
36
+ # JSON response with message; Status code 401 - Unauthorized
37
+ def unauthorized_request(e)
38
+ json_response({ message: e.message }, :unauthorized)
39
+ end
40
+
41
+ # JSON response with message; Status code 401 - Unauthorized
42
+ def not_found(e)
43
+ json_response({ message: e.message }, :not_found)
44
+ end
45
+
46
+ # JSON response with message; Status code 422 - unprocessable entity
47
+ def four_twenty_two(e)
48
+ json_response({ message: e.message }, :unprocessable_entity)
49
+ end
50
+
51
+
52
+ # JSON response with message; Status code 498 - Invalid Token
53
+ def four_ninety_eight(e)
54
+ json_response({ message: e.message }, :invalid_token)
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,25 @@
1
+ module Ctws
2
+ module Response
3
+ # responds with JSON and an HTTP status code (200 by default)
4
+ # json_response(@todo, :created)
5
+ def payload? object, status
6
+ case status
7
+ when :not_found, :unprocessable_entity, :unauthorized, :invalid_token
8
+ self.errors_payload(object)
9
+ else
10
+ self.data_payload(object)
11
+ end
12
+ end
13
+
14
+ def json_response(object = {}, status = :ok)
15
+ render json: self.payload?(object, status), status: status
16
+ end
17
+
18
+ def data_payload(object)
19
+ {data: object}
20
+ end
21
+ def errors_payload(object)
22
+ {errors: object}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ module Ctws
2
+ module V1
3
+ class ExceptionHandler < Ctws::ExceptionHandler
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Ctws
2
+ module V1
3
+ module Response < Ctws::Response
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Ctws
2
+ class ApplicationController < ActionController::API
3
+ # protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,28 @@
1
+ module Ctws
2
+ class AuthenticationController < CtwsController
3
+ skip_before_action :authorize_request, only: :authenticate
4
+
5
+ # return auth token once user is authenticated
6
+ def authenticate
7
+ auth_token = Ctws::AuthenticateUser.new(auth_params[:email], auth_params[:password]).call
8
+ json_response auth_as_jsonapi(auth_token)
9
+
10
+ end
11
+
12
+ private
13
+
14
+ def auth_as_jsonapi auth_token
15
+ {
16
+ type: controller_name,
17
+ attributes: {
18
+ message: Ctws::Message.authenticated_user_success,
19
+ auth_token: auth_token,
20
+ }
21
+ }
22
+ end
23
+
24
+ def auth_params
25
+ params.permit(:email, :password)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ require_dependency "ctws/application_controller"
2
+
3
+ module Ctws
4
+ class CtwsController < ApplicationController
5
+ include Response
6
+ include ExceptionHandler
7
+ # Generic API stuff here
8
+
9
+ # called before every action on controllers
10
+ before_action :authorize_request
11
+ skip_before_action :authorize_request, only: [:raise_not_found!]
12
+ attr_reader :current_user
13
+
14
+ def raise_not_found!
15
+ raise Ctws::ExceptionHandler::RoutingError, ("#{Ctws::Message.unmatched_route(params[:unmatched_route])}")
16
+ end
17
+ private
18
+
19
+ # Check for valid request token and return user
20
+ def authorize_request
21
+ @current_user = (Ctws::AuthorizeApiRequest.new(request.headers).call)[:user]
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,55 @@
1
+ module Ctws
2
+ class MinAppVersionsController < CtwsController
3
+ skip_before_action :authorize_request, only: [:min_app_version]
4
+ before_action :set_min_app_version, only: [:show, :update, :destroy]
5
+
6
+ # GET /min_app_version
7
+ def min_app_version
8
+ min_app_versions = []
9
+ MinAppVersion.group(:platform).each do |platform|
10
+ min_app_versions << platform.as_jsonapi
11
+ end
12
+ json_response min_app_versions
13
+ end
14
+
15
+ # GET /min_app_versions
16
+ def index
17
+ json_response MinAppVersion.all
18
+ end
19
+
20
+ # GET /min_app_versions/1
21
+ def show
22
+ json_response @min_app_version.as_jsonapi
23
+ end
24
+
25
+ # POST /min_app_versions
26
+ def create
27
+ @min_app_version = MinAppVersion.create!(min_app_version_params)
28
+ json_response @min_app_version, :created
29
+ end
30
+
31
+ # PATCH/PUT /min_app_versions/1
32
+ def update
33
+ @min_app_version.update(min_app_version_params)
34
+ head :no_content
35
+ end
36
+
37
+ # DELETE /min_app_versions/1
38
+ def destroy
39
+ @min_app_version.destroy
40
+ head :no_content
41
+ end
42
+
43
+ private
44
+ # Use callbacks to share common setup or constraints between actions.
45
+ def set_min_app_version
46
+ @min_app_version = MinAppVersion.find(params[:id])
47
+ end
48
+
49
+ # Only allow a trusted parameter "white list" through.
50
+ def min_app_version_params
51
+ params.require(:min_app_version).permit(:codename, :description, :platform, :min_version, :store_uri)
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,39 @@
1
+ module Ctws
2
+ class UsersController < CtwsController
3
+ skip_before_action :authorize_request, only: :create
4
+
5
+ # POST /signup
6
+ # return authenticated token upon signup
7
+ def create
8
+ # We use Active Record's create! method so that in the event there's an error,
9
+ # an exception will be raised and handled in the exception handler.
10
+ ctws_user = Ctws.user_class.create!(ctws_user_params)
11
+ if Ctws.user_validate_with_password
12
+ auth_token = Ctws::AuthenticateUser.new(ctws_user.email, ctws_user.password).call
13
+ elsif !Ctws.user_validate_with_password
14
+ auth_token = Ctws::AuthenticateUser.new(ctws_user.email).call
15
+ end
16
+ # response = { message: Ctws::Message.account_created, auth_token: auth_token }
17
+
18
+ json_response(user_as_jsonapi(ctws_user, auth_token), :created)
19
+ end
20
+
21
+ private
22
+
23
+ def user_as_jsonapi user, auth_token
24
+ {
25
+ type: ActiveModel::Naming.param_key(Ctws.user_class),
26
+ id: user.id,
27
+ attributes: {
28
+ message: Ctws::Message.account_created,
29
+ auth_token: auth_token,
30
+ created_at: user.created_at
31
+ }
32
+ }
33
+ end
34
+
35
+ def ctws_user_params
36
+ params.permit(Ctws.user_class_strong_params)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,6 @@
1
+ module Ctws
2
+ module V1
3
+ class AuthenticationController < Ctws::AuthenticationController
4
+ end
5
+ end
6
+ end