unsakini 0.0.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 (184) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +34 -0
  5. data/angular/README.md +31 -0
  6. data/angular/angular-cli.json +59 -0
  7. data/angular/karma.conf.js +45 -0
  8. data/angular/package.json +49 -0
  9. data/angular/protractor.conf.js +32 -0
  10. data/angular/src/app/app.component.css +0 -0
  11. data/angular/src/app/app.component.html +4 -0
  12. data/angular/src/app/app.component.spec.ts +47 -0
  13. data/angular/src/app/app.component.ts +10 -0
  14. data/angular/src/app/app.module.ts +29 -0
  15. data/angular/src/app/app.routes.module.ts +29 -0
  16. data/angular/src/app/index.ts +2 -0
  17. data/angular/src/app/registration/registration.component.css +0 -0
  18. data/angular/src/app/registration/registration.component.html +14 -0
  19. data/angular/src/app/registration/registration.component.spec.ts +157 -0
  20. data/angular/src/app/registration/registration.component.ts +42 -0
  21. data/angular/src/environments/environment.prod.ts +3 -0
  22. data/angular/src/environments/environment.ts +8 -0
  23. data/angular/src/favicon.ico +0 -0
  24. data/angular/src/index.html +14 -0
  25. data/angular/src/main.ts +12 -0
  26. data/angular/src/polyfills.ts +19 -0
  27. data/angular/src/styles.css +1 -0
  28. data/angular/src/test.ts +31 -0
  29. data/angular/src/tsconfig.json +18 -0
  30. data/angular/src/typings.d.ts +2 -0
  31. data/angular/tslint.json +114 -0
  32. data/angular/typings.json +4 -0
  33. data/app/controllers/api/boards_controller.rb +67 -0
  34. data/app/controllers/api/comments_controller.rb +51 -0
  35. data/app/controllers/api/posts_controller.rb +58 -0
  36. data/app/controllers/api/share_board_controller.rb +118 -0
  37. data/app/controllers/api/users_controller.rb +27 -0
  38. data/app/controllers/application_controller.rb +5 -0
  39. data/app/controllers/concerns/board_owner_controller_concern.rb +38 -0
  40. data/app/controllers/concerns/comment_owner_controller_concern.rb +33 -0
  41. data/app/controllers/concerns/logged_in_controller_concern.rb +21 -0
  42. data/app/controllers/concerns/post_owner_controller_concern.rb +36 -0
  43. data/app/controllers/concerns/serializer_controller_concern.rb +11 -0
  44. data/app/controllers/user_token_controller.rb +2 -0
  45. data/app/controllers/web_base_controller.rb +11 -0
  46. data/app/models/application_record.rb +5 -0
  47. data/app/models/board.rb +14 -0
  48. data/app/models/comment.rb +9 -0
  49. data/app/models/concerns/encryptable_model_concern.rb +96 -0
  50. data/app/models/post.rb +12 -0
  51. data/app/models/user.rb +6 -0
  52. data/app/models/user_board.rb +71 -0
  53. data/app/serializers/board_serializer.rb +5 -0
  54. data/app/serializers/comment_serializer.rb +10 -0
  55. data/app/serializers/post_serializer.rb +23 -0
  56. data/app/serializers/user_board_serializer.rb +10 -0
  57. data/app/serializers/user_serializer.rb +6 -0
  58. data/config/initializers/unsakini.rb +4 -0
  59. data/config/routes.rb +22 -0
  60. data/db/migrate/20161116114222_create_boards.rb +9 -0
  61. data/db/migrate/20161116200034_create_user_boards.rb +11 -0
  62. data/db/migrate/20161118031023_create_posts.rb +12 -0
  63. data/db/migrate/20161118100454_create_comments.rb +11 -0
  64. data/db/migrate/20161118221508_add_encrypted_password_to_user_board.rb +5 -0
  65. data/db/migrate/20161122211105_create_users.rb +12 -0
  66. data/lib/generators/unsakini/angular/USAGE +8 -0
  67. data/lib/generators/unsakini/angular/angular_generator.rb +7 -0
  68. data/lib/generators/unsakini/config/USAGE +8 -0
  69. data/lib/generators/unsakini/config/config_generator.rb +7 -0
  70. data/lib/generators/unsakini/config/templates/unsakini.rb +4 -0
  71. data/lib/tasks/unsakini_tasks.rake +33 -0
  72. data/lib/unsakini/engine.rb +30 -0
  73. data/lib/unsakini/version.rb +3 -0
  74. data/lib/unsakini.rb +5 -0
  75. data/spec/concerns/models/encryptable_concern.rb +40 -0
  76. data/spec/dummy/Rakefile +6 -0
  77. data/spec/dummy/angular/README.md +31 -0
  78. data/spec/dummy/angular/angular-cli.json +59 -0
  79. data/spec/dummy/angular/e2e/app.e2e-spec.ts +14 -0
  80. data/spec/dummy/angular/e2e/app.po.ts +11 -0
  81. data/spec/dummy/angular/e2e/signup.e2e-spec.ts +28 -0
  82. data/spec/dummy/angular/e2e/signup.po.ts +31 -0
  83. data/spec/dummy/angular/e2e/tsconfig.json +16 -0
  84. data/spec/dummy/angular/karma.conf.js +45 -0
  85. data/spec/dummy/angular/package.json +50 -0
  86. data/spec/dummy/angular/protractor.conf.js +32 -0
  87. data/spec/dummy/angular/src/app/app.component.css +0 -0
  88. data/spec/dummy/angular/src/app/app.component.html +4 -0
  89. data/spec/dummy/angular/src/app/app.component.spec.ts +47 -0
  90. data/spec/dummy/angular/src/app/app.component.ts +10 -0
  91. data/spec/dummy/angular/src/app/app.module.ts +29 -0
  92. data/spec/dummy/angular/src/app/app.routes.module.ts +29 -0
  93. data/spec/dummy/angular/src/app/index.ts +2 -0
  94. data/spec/dummy/angular/src/app/registration/registration.component.css +0 -0
  95. data/spec/dummy/angular/src/app/registration/registration.component.html +14 -0
  96. data/spec/dummy/angular/src/app/registration/registration.component.spec.ts +157 -0
  97. data/spec/dummy/angular/src/app/registration/registration.component.ts +42 -0
  98. data/spec/dummy/angular/src/environments/environment.prod.ts +3 -0
  99. data/spec/dummy/angular/src/environments/environment.ts +8 -0
  100. data/spec/dummy/angular/src/favicon.ico +0 -0
  101. data/spec/dummy/angular/src/index.html +14 -0
  102. data/spec/dummy/angular/src/main.ts +12 -0
  103. data/spec/dummy/angular/src/polyfills.ts +19 -0
  104. data/spec/dummy/angular/src/styles.css +1 -0
  105. data/spec/dummy/angular/src/test.ts +31 -0
  106. data/spec/dummy/angular/src/tsconfig.json +18 -0
  107. data/spec/dummy/angular/src/typings.d.ts +2 -0
  108. data/spec/dummy/angular/tslint.json +114 -0
  109. data/spec/dummy/angular/typings.json +4 -0
  110. data/spec/dummy/app/assets/config/manifest.js +3 -0
  111. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  112. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  113. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  114. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  115. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  116. data/spec/dummy/app/jobs/application_job.rb +2 -0
  117. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  118. data/spec/dummy/app/models/application_record.rb +3 -0
  119. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  120. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  121. data/spec/dummy/bin/bundle +3 -0
  122. data/spec/dummy/bin/rails +4 -0
  123. data/spec/dummy/bin/rake +4 -0
  124. data/spec/dummy/bin/setup +34 -0
  125. data/spec/dummy/bin/update +29 -0
  126. data/spec/dummy/config/application.rb +22 -0
  127. data/spec/dummy/config/boot.rb +5 -0
  128. data/spec/dummy/config/cable.yml +9 -0
  129. data/spec/dummy/config/crypto.yml +7 -0
  130. data/spec/dummy/config/database.yml +25 -0
  131. data/spec/dummy/config/environment.rb +5 -0
  132. data/spec/dummy/config/environments/development.rb +47 -0
  133. data/spec/dummy/config/environments/production.rb +78 -0
  134. data/spec/dummy/config/environments/test.rb +42 -0
  135. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  136. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  137. data/spec/dummy/config/initializers/cors.rb +16 -0
  138. data/spec/dummy/config/initializers/inflections.rb +16 -0
  139. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  140. data/spec/dummy/config/initializers/new_framework_defaults.rb +18 -0
  141. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  142. data/spec/dummy/config/locales/en.yml +23 -0
  143. data/spec/dummy/config/puma.rb +47 -0
  144. data/spec/dummy/config/routes.rb +3 -0
  145. data/spec/dummy/config/secrets.yml +22 -0
  146. data/spec/dummy/config/spring.rb +6 -0
  147. data/spec/dummy/config.ru +5 -0
  148. data/spec/dummy/db/development.sqlite3 +0 -0
  149. data/spec/dummy/db/schema.rb +56 -0
  150. data/spec/dummy/db/test.sqlite3 +0 -0
  151. data/spec/dummy/public/app/favicon.ico +0 -0
  152. data/spec/dummy/public/app/index.html +14 -0
  153. data/spec/dummy/public/app/inline.bundle.js +139 -0
  154. data/spec/dummy/public/app/inline.map +1 -0
  155. data/spec/dummy/public/app/main.bundle.js +64689 -0
  156. data/spec/dummy/public/app/main.map +1 -0
  157. data/spec/dummy/public/app/styles.bundle.js +364 -0
  158. data/spec/dummy/public/app/styles.map +1 -0
  159. data/spec/factories/boards.rb +5 -0
  160. data/spec/factories/comments.rb +7 -0
  161. data/spec/factories/posts.rb +8 -0
  162. data/spec/factories/user_boards.rb +9 -0
  163. data/spec/factories/users.rb +10 -0
  164. data/spec/models/board_spec.rb +19 -0
  165. data/spec/models/comment_spec.rb +26 -0
  166. data/spec/models/post_spec.rb +19 -0
  167. data/spec/models/user_board_spec.rb +193 -0
  168. data/spec/models/user_spec.rb +5 -0
  169. data/spec/rails_helper.rb +58 -0
  170. data/spec/requests/api/api_boards_spec.rb +238 -0
  171. data/spec/requests/api/api_share_board_spec.rb +167 -0
  172. data/spec/requests/api/api_users_spec.rb +52 -0
  173. data/spec/requests/api/board/api_board_posts_spec.rb +299 -0
  174. data/spec/requests/api/board/post/api_board_post_comments_spec.rb +370 -0
  175. data/spec/requests/render_app_index_spec.rb +19 -0
  176. data/spec/schema/board.json +39 -0
  177. data/spec/schema/comment.json +51 -0
  178. data/spec/schema/post.json +87 -0
  179. data/spec/schema/user.json +27 -0
  180. data/spec/spec_helper.rb +67 -0
  181. data/spec/support/auth_helper.rb +17 -0
  182. data/spec/support/scenario_helper.rb +134 -0
  183. data/spec/support/serialize_helper.rb +37 -0
  184. metadata +540 -0
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Angular</title>
6
+ <base href="/app/">
7
+
8
+ <meta name="viewport" content="width=device-width, initial-scale=1">
9
+ <link rel="icon" type="image/x-icon" href="favicon.ico">
10
+ </head>
11
+ <body>
12
+ <app-root>Loading...</app-root>
13
+ </body>
14
+ </html>
@@ -0,0 +1,12 @@
1
+ import './polyfills.ts';
2
+
3
+ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
4
+ import { enableProdMode } from '@angular/core';
5
+ import { environment } from './environments/environment';
6
+ import { AppModule } from './app/';
7
+
8
+ if (environment.production) {
9
+ enableProdMode();
10
+ }
11
+
12
+ platformBrowserDynamic().bootstrapModule(AppModule);
@@ -0,0 +1,19 @@
1
+ // This file includes polyfills needed by Angular 2 and is loaded before
2
+ // the app. You can add your own extra polyfills to this file.
3
+ import 'core-js/es6/symbol';
4
+ import 'core-js/es6/object';
5
+ import 'core-js/es6/function';
6
+ import 'core-js/es6/parse-int';
7
+ import 'core-js/es6/parse-float';
8
+ import 'core-js/es6/number';
9
+ import 'core-js/es6/math';
10
+ import 'core-js/es6/string';
11
+ import 'core-js/es6/date';
12
+ import 'core-js/es6/array';
13
+ import 'core-js/es6/regexp';
14
+ import 'core-js/es6/map';
15
+ import 'core-js/es6/set';
16
+ import 'core-js/es6/reflect';
17
+
18
+ import 'core-js/es7/reflect';
19
+ import 'zone.js/dist/zone';
@@ -0,0 +1 @@
1
+ /* You can add global styles to this file, and also import other style files */
@@ -0,0 +1,31 @@
1
+ import './polyfills.ts';
2
+ import 'zone.js/dist/long-stack-trace-zone';
3
+ import 'zone.js/dist/proxy.js';
4
+ import 'zone.js/dist/sync-test';
5
+ import 'zone.js/dist/jasmine-patch';
6
+ import 'zone.js/dist/async-test';
7
+ import 'zone.js/dist/fake-async-test';
8
+ import { getTestBed } from '@angular/core/testing';
9
+ import {
10
+ BrowserDynamicTestingModule,
11
+ platformBrowserDynamicTesting
12
+ } from '@angular/platform-browser-dynamic/testing';
13
+
14
+ // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
15
+ declare var __karma__: any;
16
+ declare var require: any;
17
+
18
+ // Prevent Karma from running prematurely.
19
+ __karma__.loaded = function () {};
20
+
21
+ // First, initialize the Angular testing environment.
22
+ getTestBed().initTestEnvironment(
23
+ BrowserDynamicTestingModule,
24
+ platformBrowserDynamicTesting()
25
+ );
26
+ // Then we find all the tests.
27
+ let context = require.context('./', true, /\.spec\.ts/);
28
+ // And load the modules.
29
+ context.keys().map(context);
30
+ // Finally, start Karma to run the tests.
31
+ __karma__.start();
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": "",
4
+ "declaration": false,
5
+ "emitDecoratorMetadata": true,
6
+ "experimentalDecorators": true,
7
+ "lib": ["es6", "dom"],
8
+ "mapRoot": "./",
9
+ "module": "es6",
10
+ "moduleResolution": "node",
11
+ "outDir": "../dist/out-tsc",
12
+ "sourceMap": true,
13
+ "target": "es5",
14
+ "typeRoots": [
15
+ "../node_modules/@types"
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,2 @@
1
+ // Typings reference file, you can add your own global typings here
2
+ // https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html
@@ -0,0 +1,114 @@
1
+ {
2
+ "rulesDirectory": [
3
+ "node_modules/codelyzer"
4
+ ],
5
+ "rules": {
6
+ "class-name": true,
7
+ "comment-format": [
8
+ true,
9
+ "check-space"
10
+ ],
11
+ "curly": true,
12
+ "eofline": true,
13
+ "forin": true,
14
+ "indent": [
15
+ true,
16
+ "spaces"
17
+ ],
18
+ "label-position": true,
19
+ "label-undefined": true,
20
+ "max-line-length": [
21
+ true,
22
+ 140
23
+ ],
24
+ "member-access": false,
25
+ "member-ordering": [
26
+ true,
27
+ "static-before-instance",
28
+ "variables-before-functions"
29
+ ],
30
+ "no-arg": true,
31
+ "no-bitwise": true,
32
+ "no-console": [
33
+ true,
34
+ "debug",
35
+ "info",
36
+ "time",
37
+ "timeEnd",
38
+ "trace"
39
+ ],
40
+ "no-construct": true,
41
+ "no-debugger": true,
42
+ "no-duplicate-key": true,
43
+ "no-duplicate-variable": true,
44
+ "no-empty": false,
45
+ "no-eval": true,
46
+ "no-inferrable-types": true,
47
+ "no-shadowed-variable": true,
48
+ "no-string-literal": false,
49
+ "no-switch-case-fall-through": true,
50
+ "no-trailing-whitespace": true,
51
+ "no-unused-expression": true,
52
+ "no-unused-variable": true,
53
+ "no-unreachable": true,
54
+ "no-use-before-declare": true,
55
+ "no-var-keyword": true,
56
+ "object-literal-sort-keys": false,
57
+ "one-line": [
58
+ true,
59
+ "check-open-brace",
60
+ "check-catch",
61
+ "check-else",
62
+ "check-whitespace"
63
+ ],
64
+ "quotemark": [
65
+ true,
66
+ "single"
67
+ ],
68
+ "radix": true,
69
+ "semicolon": [
70
+ "always"
71
+ ],
72
+ "triple-equals": [
73
+ true,
74
+ "allow-null-check"
75
+ ],
76
+ "typedef-whitespace": [
77
+ true,
78
+ {
79
+ "call-signature": "nospace",
80
+ "index-signature": "nospace",
81
+ "parameter": "nospace",
82
+ "property-declaration": "nospace",
83
+ "variable-declaration": "nospace"
84
+ }
85
+ ],
86
+ "variable-name": false,
87
+ "whitespace": [
88
+ true,
89
+ "check-branch",
90
+ "check-decl",
91
+ "check-operator",
92
+ "check-separator",
93
+ "check-type"
94
+ ],
95
+
96
+ "directive-selector-prefix": [true, "app"],
97
+ "component-selector-prefix": [true, "app"],
98
+ "directive-selector-name": [true, "camelCase"],
99
+ "component-selector-name": [true, "kebab-case"],
100
+ "directive-selector-type": [true, "attribute"],
101
+ "component-selector-type": [true, "element"],
102
+ "use-input-property-decorator": true,
103
+ "use-output-property-decorator": true,
104
+ "use-host-property-decorator": true,
105
+ "no-input-rename": true,
106
+ "no-output-rename": true,
107
+ "use-life-cycle-interface": true,
108
+ "use-pipe-transform-interface": true,
109
+ "component-class-suffix": true,
110
+ "directive-class-suffix": true,
111
+ "templates-use-public": true,
112
+ "invoke-injectable": true
113
+ }
114
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "globalDevDependencies": {
3
+ }
4
+ }
@@ -0,0 +1,67 @@
1
+ class Api::BoardsController < ApplicationController
2
+
3
+
4
+ include LoggedInControllerConcern
5
+ include SerializerControllerConcern
6
+ include BoardOwnerControllerConcern
7
+ include ::ActionController::Serialization
8
+
9
+ before_action :ensure_board, :only => [:show, :update, :destroy]
10
+ before_action :ensure_board_owner, :only => [:update, :destroy]
11
+
12
+ # Returns boards belonging to current user
13
+ #
14
+ # `GET /api/boards`
15
+ #
16
+ def index
17
+ render json: @user.user_boards
18
+ end
19
+
20
+ # Creates board belonging to current user.
21
+ #
22
+ # `POST /api/boards`
23
+ #
24
+ def create
25
+ @user_board = UserBoard.new(
26
+ name: params[:board][:name],
27
+ user_id: @user.id,
28
+ encrypted_password: params[:encrypted_password],
29
+ is_admin: true
30
+ )
31
+ if @user_board.save
32
+ render json: @user_board, status: :created
33
+ else
34
+ render json: @user_board.errors.full_messages, status: 422
35
+ end
36
+
37
+ end
38
+
39
+ # Render a single board.
40
+ #
41
+ # `GET /api/boards/:id`
42
+ #
43
+ def show
44
+ render json: @user_board
45
+ end
46
+
47
+ # Updates a single board.
48
+ #
49
+ # `PUT /api/boards/:id`
50
+ def update
51
+ if @user_board.update(name: params[:board][:name], encrypted_password: params[:encrypted_password])
52
+ render json: @user_board
53
+ else
54
+ errors = @board.errors.full_messages.concat @user_board.errors.full_messages
55
+ render json: errors, status: 422
56
+ end
57
+ end
58
+
59
+ # Deletes a board resource.
60
+ #
61
+ # `DELETE /api/boards/:id`
62
+ def destroy
63
+ @board.destroy
64
+ render status: :ok
65
+ end
66
+
67
+ end
@@ -0,0 +1,51 @@
1
+ class Api::CommentsController < ApplicationController
2
+
3
+ include LoggedInControllerConcern
4
+ include PostOwnerControllerConcern
5
+ include CommentOwnerControllerConcern
6
+ include ::ActionController::Serialization
7
+
8
+ before_action :ensure_post, only: [:index, :create]
9
+ before_action :ensure_comment, only: [:show, :update, :destroy]
10
+ before_action :ensure_comment_owner, only: [:update, :destroy]
11
+
12
+ # Renders the comments belonging to the post
13
+ #
14
+ # `GET /api/boards/:board_id/posts/:post_id/`
15
+ def index
16
+ render json: @post.comments
17
+ end
18
+
19
+ # Creates new comment belonging to the post
20
+ #
21
+ # `POST /api/boards/:board_id/posts/:post_id/`
22
+ def create
23
+ @comment = Comment.new(params.permit(:content))
24
+ @comment.user = @user
25
+ @comment.post = @post
26
+ if @comment.save
27
+ render json: @comment
28
+ else
29
+ render json: @comment.errors, status: 422
30
+ end
31
+ end
32
+
33
+ # Updates a comment
34
+ #
35
+ # `PUT /api/boards/:board_id/posts/:post_id/comments/:id`
36
+ def update
37
+ if @comment.update(params.permit(:content))
38
+ render json: @comment
39
+ else
40
+ render json: @comment.errors, status: 422
41
+ end
42
+ end
43
+
44
+ # Deletes a comment
45
+ #
46
+ # `DELETE /api/boards/:board_id/posts/:post_id/comments/:id`
47
+ def destroy
48
+ @comment.destroy
49
+ render status: :ok
50
+ end
51
+ end
@@ -0,0 +1,58 @@
1
+ class Api::PostsController < ApplicationController
2
+
3
+ include LoggedInControllerConcern
4
+ include BoardOwnerControllerConcern
5
+ include PostOwnerControllerConcern
6
+ include ::ActionController::Serialization
7
+
8
+ before_action :ensure_board, only: [:index, :create]
9
+ before_action :ensure_post, only: [:show, :update, :destroy]
10
+ before_action :ensure_post_owner, only: [:update, :destroy]
11
+
12
+ # Renders the post belonging to the board
13
+ #
14
+ # `GET /api/boards/:board_id/posts`
15
+ def index
16
+ render json: @board.posts
17
+ end
18
+
19
+ # Renders a single post belonging to the board
20
+ #
21
+ # `GET /api/boards/:board_id/posts/:id`
22
+ def show
23
+ render json: @post
24
+ end
25
+
26
+ # Creates a single post belonging to the board
27
+ #
28
+ # `POST /api/boards/:board_id/posts/`
29
+ def create
30
+ @post = Post.new(params.permit(:title, :content, :board_id))
31
+ @post.user = @user
32
+ if (@post.save)
33
+ render json: @post, status: :created
34
+ else
35
+ render json: @post.errors, status: 422
36
+ end
37
+ end
38
+
39
+ # Updates a single post belonging to the board
40
+ #
41
+ # `PUT /api/boards/:board_id/posts/:id`
42
+ def update
43
+ if (@post.update(params.permit(:title, :content)))
44
+ render json: @post, status: :ok
45
+ else
46
+ render json: @post.errors, status: 422
47
+ end
48
+ end
49
+
50
+ # Deletes a single post belonging to the board
51
+ #
52
+ # `DELETE /api/boards/:board_id/posts/:id`
53
+ def destroy
54
+ @post.destroy
55
+ render status: :ok
56
+ end
57
+
58
+ end
@@ -0,0 +1,118 @@
1
+ class Api::ShareBoardController < ApplicationController
2
+
3
+ include LoggedInControllerConcern
4
+ include BoardOwnerControllerConcern
5
+ include PostOwnerControllerConcern
6
+ include CommentOwnerControllerConcern
7
+
8
+ before_action :validate_params
9
+
10
+ # Shares a board to other users. Example payload param:
11
+ #
12
+ # `POST /api/share/board`
13
+ #
14
+ # ```
15
+ # {
16
+ # board: {
17
+ # id: 1,
18
+ # name: 'some encrypted text',
19
+ # },
20
+ # posts: [
21
+ # {
22
+ # board_id: 1,
23
+ # title: 'some encrypted text',
24
+ # content: 'some encrypted text',
25
+ # comments: [
26
+ # {
27
+ # id: 1,
28
+ # content: 'some encrypted text',
29
+ # user_id: 1,
30
+ # post_id: 1,
31
+ # }
32
+ # ]
33
+ # }
34
+ # ],
35
+ # shared_user_ids: [1, 2, 3, 4],
36
+ # encrypted_password: 'some encrypted password'
37
+ # }
38
+ # ```
39
+ # The `encrypted_password` param will be used to decrypt contents of this board. The encryption happens in the client so
40
+ # the server don't really know what is the original password. The board creator will have to share it privately to other users whom he/she shared it with so they can access the board.
41
+ #
42
+ # `posts` and `comments` fields can be empty.
43
+ def index
44
+ ActiveRecord::Base.transaction do
45
+ if params[:posts]
46
+ params[:posts].each do |post|
47
+ p = Post.find(post[:id])
48
+ p.title = post[:title]
49
+ p.content = post[:content]
50
+ p.save!
51
+
52
+ if post[:comments] and p.valid?
53
+ post[:comments].each do |comment|
54
+ c = Comment.find(comment[:id])
55
+ c.content = comment[:content]
56
+ c.save!
57
+ end
58
+ end
59
+ end
60
+ end
61
+ if @user_board.share(params[:shared_user_ids], params[:encrypted_password])
62
+ render status: :ok
63
+ else
64
+ raise "An error occured"
65
+ end
66
+ end
67
+ rescue
68
+ # clean up the created {UserBoard}s
69
+ render status: 422, json: ["Some of the data can't be saved."]
70
+ end
71
+
72
+ # Validates the contents of params against the database records.
73
+ def validate_params
74
+
75
+ if params[:encrypted_password].nil? or params[:shared_user_ids].nil? or params[:board].nil?
76
+ render status: 422
77
+ return
78
+ end
79
+
80
+ result = has_board_access(params[:board][:id])
81
+ if result[:status] != :ok
82
+ render status: result[:status]
83
+ return
84
+ else
85
+ if !result[:user_board].is_admin
86
+ render status: :forbidden
87
+ return
88
+ end
89
+ @board = result[:board]
90
+ @user_board = result[:user_board]
91
+ end
92
+
93
+ if params[:posts]
94
+
95
+ params[:posts].each do |post|
96
+ s = has_post_access(params[:board][:id], post[:id])[:status]
97
+ if s != :ok
98
+ render status: s
99
+ return
100
+ end
101
+
102
+ if post[:comments]
103
+ post[:comments].each do |comment|
104
+ s = has_comment_access(post[:id], comment[:id])[:status]
105
+ if s != :ok
106
+ render status: s
107
+ return
108
+ end
109
+ end
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,27 @@
1
+ class Api::UsersController < ApplicationController
2
+
3
+ include LoggedInControllerConcern
4
+ include ::ActionController::Serialization
5
+
6
+ # Renders the current user as json
7
+ #
8
+ # `GET /api/user/:id`
9
+ #
10
+ def show
11
+ render json: @user
12
+ end
13
+
14
+ # Returns the user with matching email
15
+ #
16
+ # `GET /api/users/search?email=xxx`
17
+ #
18
+ def search
19
+ user = User.where("email = ? AND id != ?", params[:email], @user.id).first
20
+ if user
21
+ render json: user
22
+ else
23
+ render status: :not_found
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,5 @@
1
+ # Base controller for API controllers
2
+
3
+ class ApplicationController < ActionController::API
4
+
5
+ end
@@ -0,0 +1,38 @@
1
+ #Ensure user has access to the board and sets the `@board` variable in the controller
2
+ module BoardOwnerControllerConcern
3
+ extend ActiveSupport::Concern
4
+
5
+ #Ensure user has access to the board and sets the `@board` variable in the controller
6
+ def ensure_board
7
+ board_id = params[:board_id] || params[:id]
8
+ result = has_board_access(board_id)
9
+ @board = result[:board]
10
+ @user_board = result[:user_board]
11
+ render status: result[:status] if result[:status] != :ok
12
+ end
13
+
14
+ # Validate if user has access to board
15
+ #
16
+ # @param board_id [Integer] board id
17
+ def has_board_access(board_id)
18
+ board = nil
19
+ if !board_id.nil?
20
+ board = Board.find_by_id(board_id)
21
+ else
22
+ return {status: :bad_request}
23
+ end
24
+ if (board)
25
+ user_board = UserBoard.where(user_id: @user.id, board_id: board_id).first
26
+ return {status: :forbidden }if user_board.nil?
27
+ return {status: :ok, board: board, user_board: user_board}
28
+ else
29
+ return {status: :not_found}
30
+ end
31
+ end
32
+
33
+ #Ensures user is owner of the board. Must be run after {#ensure_board} method.
34
+ def ensure_board_owner
35
+ render status: :forbidden if !@user_board.is_admin
36
+ end
37
+
38
+ end
@@ -0,0 +1,33 @@
1
+ # Ensures user is owner of the comment and sets the `@comment` variable in the controllers
2
+ module CommentOwnerControllerConcern
3
+ extend ActiveSupport::Concern
4
+
5
+ # Ensures user is owner of the comment and sets the `@comment` variable in the controllers
6
+ def ensure_comment
7
+ post_id = params[:post_id]
8
+ comment_id = params[:comment_id] || params[:id]
9
+ result = has_comment_access post_id, comment_id
10
+ @comment = result[:comment]
11
+ status = result[:status]
12
+ render status: status if status != :ok
13
+ end
14
+
15
+ # Validate if user has access to comment in the post
16
+ #
17
+ # @param post_id [Integer] post id
18
+ # @param comment_id [Integer] comment id
19
+ def has_comment_access(post_id, comment_id)
20
+ comment = Comment.where(id: comment_id, post_id: post_id, user_id: @user.id).first
21
+ if comment.nil?
22
+ return {status: :forbidden, comment: comment}
23
+ else
24
+ return {status: :ok, comment: comment}
25
+ end
26
+ end
27
+
28
+ # Ensures user is the owner of the comment. Must be run after {#ensure_comment} method.
29
+ def ensure_comment_owner
30
+ render status: :forbidden if @comment.user_id != @user.id
31
+ end
32
+
33
+ end
@@ -0,0 +1,21 @@
1
+ # Ensures users are logged in and sets `@user` instance variable in the controllers.
2
+ # This is included in the base api controller.
3
+ #
4
+ # Returns `401` error if user is not authenticated
5
+ module LoggedInControllerConcern
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include Knock::Authenticable
10
+ before_action :authenticate_user
11
+ before_action :set_user
12
+ end
13
+
14
+ private
15
+ # Sets the `@user` variable in the controllers
16
+ def set_user
17
+ render status: :unauthorized if current_user.nil?
18
+ @user = current_user
19
+ end
20
+
21
+ end
@@ -0,0 +1,36 @@
1
+ # Ensures user is owner of the post and sets the `@post` variable in the controllers
2
+ module PostOwnerControllerConcern
3
+ extend ActiveSupport::Concern
4
+
5
+ # Ensures user is owner of the post and sets the `@post` variable in the controllers
6
+ def ensure_post
7
+ post_id = params[:post_id] || params[:id]
8
+ board_id = params[:board_id]
9
+ result = has_post_access(board_id, post_id)
10
+ status = result[:status]
11
+ @post = result[:post]
12
+ render status: status if status != :ok
13
+ end
14
+
15
+ # Validate if user has access to the post in the board
16
+ #
17
+ # @param board_id [Integer] board id
18
+ # @param post_id [Integer] post id
19
+ def has_post_access(board_id, post_id)
20
+ post = Post.where(id: post_id, board_id: board_id)
21
+ .joins("LEFT JOIN user_boards ON user_boards.board_id = posts.board_id")
22
+ .where("user_boards.user_id = ?", @user.id)
23
+ .first
24
+ if post.nil?
25
+ return {status: :forbidden}
26
+ else
27
+ return {status: :ok, post: post}
28
+ end
29
+ end
30
+
31
+ # Ensures user is owner of the post. Must be run after {#ensure_post}`.
32
+ def ensure_post_owner
33
+ render status: :forbidden if @post.user_id != @user.id
34
+ end
35
+
36
+ end