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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +34 -0
- data/angular/README.md +31 -0
- data/angular/angular-cli.json +59 -0
- data/angular/karma.conf.js +45 -0
- data/angular/package.json +49 -0
- data/angular/protractor.conf.js +32 -0
- data/angular/src/app/app.component.css +0 -0
- data/angular/src/app/app.component.html +4 -0
- data/angular/src/app/app.component.spec.ts +47 -0
- data/angular/src/app/app.component.ts +10 -0
- data/angular/src/app/app.module.ts +29 -0
- data/angular/src/app/app.routes.module.ts +29 -0
- data/angular/src/app/index.ts +2 -0
- data/angular/src/app/registration/registration.component.css +0 -0
- data/angular/src/app/registration/registration.component.html +14 -0
- data/angular/src/app/registration/registration.component.spec.ts +157 -0
- data/angular/src/app/registration/registration.component.ts +42 -0
- data/angular/src/environments/environment.prod.ts +3 -0
- data/angular/src/environments/environment.ts +8 -0
- data/angular/src/favicon.ico +0 -0
- data/angular/src/index.html +14 -0
- data/angular/src/main.ts +12 -0
- data/angular/src/polyfills.ts +19 -0
- data/angular/src/styles.css +1 -0
- data/angular/src/test.ts +31 -0
- data/angular/src/tsconfig.json +18 -0
- data/angular/src/typings.d.ts +2 -0
- data/angular/tslint.json +114 -0
- data/angular/typings.json +4 -0
- data/app/controllers/api/boards_controller.rb +67 -0
- data/app/controllers/api/comments_controller.rb +51 -0
- data/app/controllers/api/posts_controller.rb +58 -0
- data/app/controllers/api/share_board_controller.rb +118 -0
- data/app/controllers/api/users_controller.rb +27 -0
- data/app/controllers/application_controller.rb +5 -0
- data/app/controllers/concerns/board_owner_controller_concern.rb +38 -0
- data/app/controllers/concerns/comment_owner_controller_concern.rb +33 -0
- data/app/controllers/concerns/logged_in_controller_concern.rb +21 -0
- data/app/controllers/concerns/post_owner_controller_concern.rb +36 -0
- data/app/controllers/concerns/serializer_controller_concern.rb +11 -0
- data/app/controllers/user_token_controller.rb +2 -0
- data/app/controllers/web_base_controller.rb +11 -0
- data/app/models/application_record.rb +5 -0
- data/app/models/board.rb +14 -0
- data/app/models/comment.rb +9 -0
- data/app/models/concerns/encryptable_model_concern.rb +96 -0
- data/app/models/post.rb +12 -0
- data/app/models/user.rb +6 -0
- data/app/models/user_board.rb +71 -0
- data/app/serializers/board_serializer.rb +5 -0
- data/app/serializers/comment_serializer.rb +10 -0
- data/app/serializers/post_serializer.rb +23 -0
- data/app/serializers/user_board_serializer.rb +10 -0
- data/app/serializers/user_serializer.rb +6 -0
- data/config/initializers/unsakini.rb +4 -0
- data/config/routes.rb +22 -0
- data/db/migrate/20161116114222_create_boards.rb +9 -0
- data/db/migrate/20161116200034_create_user_boards.rb +11 -0
- data/db/migrate/20161118031023_create_posts.rb +12 -0
- data/db/migrate/20161118100454_create_comments.rb +11 -0
- data/db/migrate/20161118221508_add_encrypted_password_to_user_board.rb +5 -0
- data/db/migrate/20161122211105_create_users.rb +12 -0
- data/lib/generators/unsakini/angular/USAGE +8 -0
- data/lib/generators/unsakini/angular/angular_generator.rb +7 -0
- data/lib/generators/unsakini/config/USAGE +8 -0
- data/lib/generators/unsakini/config/config_generator.rb +7 -0
- data/lib/generators/unsakini/config/templates/unsakini.rb +4 -0
- data/lib/tasks/unsakini_tasks.rake +33 -0
- data/lib/unsakini/engine.rb +30 -0
- data/lib/unsakini/version.rb +3 -0
- data/lib/unsakini.rb +5 -0
- data/spec/concerns/models/encryptable_concern.rb +40 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/angular/README.md +31 -0
- data/spec/dummy/angular/angular-cli.json +59 -0
- data/spec/dummy/angular/e2e/app.e2e-spec.ts +14 -0
- data/spec/dummy/angular/e2e/app.po.ts +11 -0
- data/spec/dummy/angular/e2e/signup.e2e-spec.ts +28 -0
- data/spec/dummy/angular/e2e/signup.po.ts +31 -0
- data/spec/dummy/angular/e2e/tsconfig.json +16 -0
- data/spec/dummy/angular/karma.conf.js +45 -0
- data/spec/dummy/angular/package.json +50 -0
- data/spec/dummy/angular/protractor.conf.js +32 -0
- data/spec/dummy/angular/src/app/app.component.css +0 -0
- data/spec/dummy/angular/src/app/app.component.html +4 -0
- data/spec/dummy/angular/src/app/app.component.spec.ts +47 -0
- data/spec/dummy/angular/src/app/app.component.ts +10 -0
- data/spec/dummy/angular/src/app/app.module.ts +29 -0
- data/spec/dummy/angular/src/app/app.routes.module.ts +29 -0
- data/spec/dummy/angular/src/app/index.ts +2 -0
- data/spec/dummy/angular/src/app/registration/registration.component.css +0 -0
- data/spec/dummy/angular/src/app/registration/registration.component.html +14 -0
- data/spec/dummy/angular/src/app/registration/registration.component.spec.ts +157 -0
- data/spec/dummy/angular/src/app/registration/registration.component.ts +42 -0
- data/spec/dummy/angular/src/environments/environment.prod.ts +3 -0
- data/spec/dummy/angular/src/environments/environment.ts +8 -0
- data/spec/dummy/angular/src/favicon.ico +0 -0
- data/spec/dummy/angular/src/index.html +14 -0
- data/spec/dummy/angular/src/main.ts +12 -0
- data/spec/dummy/angular/src/polyfills.ts +19 -0
- data/spec/dummy/angular/src/styles.css +1 -0
- data/spec/dummy/angular/src/test.ts +31 -0
- data/spec/dummy/angular/src/tsconfig.json +18 -0
- data/spec/dummy/angular/src/typings.d.ts +2 -0
- data/spec/dummy/angular/tslint.json +114 -0
- data/spec/dummy/angular/typings.json +4 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/assets/javascripts/application.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 +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/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 +22 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +9 -0
- data/spec/dummy/config/crypto.yml +7 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +47 -0
- data/spec/dummy/config/environments/production.rb +78 -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/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cors.rb +16 -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 +18 -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 +3 -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/schema.rb +56 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/public/app/favicon.ico +0 -0
- data/spec/dummy/public/app/index.html +14 -0
- data/spec/dummy/public/app/inline.bundle.js +139 -0
- data/spec/dummy/public/app/inline.map +1 -0
- data/spec/dummy/public/app/main.bundle.js +64689 -0
- data/spec/dummy/public/app/main.map +1 -0
- data/spec/dummy/public/app/styles.bundle.js +364 -0
- data/spec/dummy/public/app/styles.map +1 -0
- data/spec/factories/boards.rb +5 -0
- data/spec/factories/comments.rb +7 -0
- data/spec/factories/posts.rb +8 -0
- data/spec/factories/user_boards.rb +9 -0
- data/spec/factories/users.rb +10 -0
- data/spec/models/board_spec.rb +19 -0
- data/spec/models/comment_spec.rb +26 -0
- data/spec/models/post_spec.rb +19 -0
- data/spec/models/user_board_spec.rb +193 -0
- data/spec/models/user_spec.rb +5 -0
- data/spec/rails_helper.rb +58 -0
- data/spec/requests/api/api_boards_spec.rb +238 -0
- data/spec/requests/api/api_share_board_spec.rb +167 -0
- data/spec/requests/api/api_users_spec.rb +52 -0
- data/spec/requests/api/board/api_board_posts_spec.rb +299 -0
- data/spec/requests/api/board/post/api_board_post_comments_spec.rb +370 -0
- data/spec/requests/render_app_index_spec.rb +19 -0
- data/spec/schema/board.json +39 -0
- data/spec/schema/comment.json +51 -0
- data/spec/schema/post.json +87 -0
- data/spec/schema/user.json +27 -0
- data/spec/spec_helper.rb +67 -0
- data/spec/support/auth_helper.rb +17 -0
- data/spec/support/scenario_helper.rb +134 -0
- data/spec/support/serialize_helper.rb +37 -0
- 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>
|
data/angular/src/main.ts
ADDED
|
@@ -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 */
|
data/angular/src/test.ts
ADDED
|
@@ -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
|
+
}
|
data/angular/tslint.json
ADDED
|
@@ -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,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,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
|