ctws 0.1.5.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +295 -0
- data/Rakefile +21 -0
- data/app/auth/ctws/authenticate_user.rb +36 -0
- data/app/auth/ctws/authorize_api_request.rb +44 -0
- data/app/controllers/concerns/ctws/exception_handler.rb +58 -0
- data/app/controllers/concerns/ctws/response.rb +25 -0
- data/app/controllers/concerns/ctws/v1/exception_handler.rb +6 -0
- data/app/controllers/concerns/ctws/v1/response.rb +6 -0
- data/app/controllers/ctws/application_controller.rb +5 -0
- data/app/controllers/ctws/authentication_controller.rb +28 -0
- data/app/controllers/ctws/ctws_controller.rb +24 -0
- data/app/controllers/ctws/min_app_versions_controller.rb +55 -0
- data/app/controllers/ctws/users_controller.rb +39 -0
- data/app/controllers/ctws/v1/authentication_controller.rb +6 -0
- data/app/controllers/ctws/v1/ctws_controller.rb +9 -0
- data/app/controllers/ctws/v1/min_app_versions_controller.rb +6 -0
- data/app/controllers/ctws/v1/users_controller.rb +6 -0
- data/app/controllers/ctws/v2/ctws_controller.rb +9 -0
- data/app/controllers/ctws/v2/min_app_versions_controller.rb +6 -0
- data/app/jobs/ctws/application_job.rb +4 -0
- data/app/lib/ctws/json_web_token.rb +25 -0
- data/app/lib/ctws/message.rb +43 -0
- data/app/mailers/ctws/application_mailer.rb +6 -0
- data/app/models/ctws/application_record.rb +5 -0
- data/app/models/ctws/min_app_version.rb +22 -0
- data/config/initializers/ctws.rb +5 -0
- data/config/initializers/mime_types.rb +1 -0
- data/config/routes.rb +18 -0
- data/db/migrate/20170425110839_create_ctws_min_app_versions.rb +13 -0
- data/db/migrate/20170425110933_add_values_to_ctws_min_app_versions.rb +26 -0
- data/lib/ctws/engine.rb +13 -0
- data/lib/ctws/version.rb +3 -0
- data/lib/ctws.rb +18 -0
- data/lib/tasks/ctws_tasks.rake +4 -0
- data/spec/auth/ctws/authenticate_user_spec.rb +34 -0
- data/spec/auth/ctws/authorize_api_request_spec.rb +62 -0
- data/spec/controllers/ctws/ctws_controller_spec.rb +41 -0
- data/spec/controllers/ctws/users_controller_spec.rb +7 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +5 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/javascripts/cable.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/user_controller.rb +18 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/user_helper.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/user.rb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +34 -0
- data/spec/dummy/bin/update +29 -0
- data/spec/dummy/config/application.rb +15 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +9 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +54 -0
- data/spec/dummy/config/environments/production.rb +86 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/puma.rb +47 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20170622072636_create_users.rb +10 -0
- data/spec/dummy/db/schema.rb +39 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +29 -0
- data/spec/dummy/log/test.log +31496 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/ctws/ctws_user.rb +7 -0
- data/spec/factories/ctws_min_app_version.rb +9 -0
- data/spec/models/ctws/min_app_version_spec.rb +11 -0
- data/spec/models/ctws/user_spec.rb +8 -0
- data/spec/rails_helper.rb +88 -0
- data/spec/requests/ctws/authentication_spec.rb +47 -0
- data/spec/requests/ctws/min_app_version_spec.rb +169 -0
- data/spec/requests/ctws/users_spec.rb +46 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/ctws/controller_spec_helper.rb +29 -0
- data/spec/support/ctws/request_spec_helper.rb +10 -0
- 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,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
|