├── .DS_Store
├── .gitignore
├── LICENSE
├── README.md
├── admin
├── Utils.js
├── admin.js
├── apps
│ └── tasks
│ │ ├── db
│ │ ├── functions
│ │ │ ├── create_bulk_tasks.sql
│ │ │ ├── create_task.sql
│ │ │ ├── delete_task.sql
│ │ │ ├── select_task.sql
│ │ │ └── update_task.sql
│ │ └── script.sql
│ │ └── install.json
├── config
│ └── admin
├── controllers
│ ├── Connection.js
│ ├── Dashboard.js
│ ├── Function.js
│ ├── Route.js
│ ├── User.js
│ └── dbUtils.js
├── core
│ └── models
│ │ ├── Connection.js
│ │ ├── Function.js
│ │ ├── Route.js
│ │ └── User.js
├── install
│ ├── db
│ │ ├── DB.sql
│ │ ├── database.json
│ │ └── functions
│ │ │ ├── add_admin_user.sql
│ │ │ ├── install_application.sql
│ │ │ └── validate_session.sql
│ └── index.js
├── models
│ ├── Connection.js
│ ├── Function.js
│ ├── Route.js
│ └── User.js
├── router
│ └── index.js
└── sql
│ └── main.sql
├── dist
└── admin
│ ├── index.html
│ ├── main.25406552.map
│ ├── main.51c0438c.js
│ ├── main.98aa3d49.css
│ ├── main.bcb0b657.css
│ ├── main.bcb0b657.js
│ ├── main.bcb0b657.map
│ └── pgAPI-icon.5a767025.png
├── index.js
├── package-lock.json
└── package.json
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thrinz/pgapi/e27510461c95017e357f8a46dbd76a7376ac206f/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
63 | .DS_Store
64 |
--------------------------------------------------------------------------------
/admin/admin.js:
--------------------------------------------------------------------------------
1 | /* This file is part of pgAPI.
2 | pgAPI - Database as a service
3 | Copyright (C) 2018 Praveen Muralidhar
4 |
5 | pgAPI is a free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | any later version.
9 |
10 | pgAPI is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | const program = require('commander');
20 | const { prompt } = require('inquirer');
21 | const dotenv = require('dotenv');
22 | const path = require('path');
23 | const utils = require('./Utils');
24 | const findUp = require('find-up');
25 |
26 | // Load env variables from .env file
27 | dotenv.config({
28 | path: findUp.sync('config.env')
29 | })
30 |
31 |
32 | // Load Runtime variables
33 | utils.loadRuntimeEnvVariables({
34 | DB_HOST : process.env.PG_HOST || process.env.DB_HOST,
35 | DB_USER: process.env.PG_USER || process.env.DB_USER,
36 | DB_PASSWORD: process.env.PG_PASSWORD || process.env.DB_PASSWORD,
37 | DB_NAME: process.env.PG_DATABASE || process.env.DB_NAME,
38 | DB_PORT: process.env.PG_PORT || process.env.DB_PORT,
39 | PGAPI_SECRET_KEY: process.env.TOKEN_SECRET_KEY || process.env.PGAPI_SECRET_KEY,
40 | DEMO_INSTALL: process.env.DEMO_INSTALL || 'Y'
41 | });
42 |
43 | const userController = require('../admin/controllers/User');
44 |
45 | const resetpasswd = [
46 | {
47 | type : 'input',
48 | name : 'username',
49 | message : 'Enter Username ...'
50 | },
51 | {
52 | type : 'input',
53 | name : 'password',
54 | message : 'Enter password ...'
55 | },
56 | {
57 | type : 'input',
58 | name : 'confirmPassword',
59 | message : 'Enter password again ...'
60 | }
61 | ];
62 |
63 | const addUserQ = [
64 | {
65 | type : 'input',
66 | name : 'username',
67 | message : 'Enter Username ...'
68 | },
69 | {
70 | type : 'input',
71 | name : 'firstname',
72 | message : 'Enter Firstname ...'
73 | },
74 | {
75 | type : 'input',
76 | name : 'lastname',
77 | message : 'Enter Lastname ...'
78 | },
79 | {
80 | type : 'input',
81 | name : 'password',
82 | message : 'Enter Password ...'
83 | },
84 | {
85 | type : 'input',
86 | name : 'confirmPassword',
87 | message : 'Enter Password again ...'
88 | }
89 | ];
90 |
91 | const deleteUserQ = [
92 | {
93 | type : 'input',
94 | name : 'username',
95 | message : 'Enter Username ...'
96 | }
97 | ];
98 |
99 | const enableDisableQ = [
100 | {
101 | type : 'input',
102 | name : 'username',
103 | message : 'Enter Username ...'
104 | },
105 | {
106 | type : 'input',
107 | name : 'enabled_flag',
108 | message : 'Enable or Disable (Y or N) ...'
109 | }
110 | ];
111 |
112 | const validateSessionQ = [
113 | {
114 | type : 'input',
115 | name : 'token',
116 | message : 'Enter Token ...'
117 | }
118 | ];
119 |
120 | // const generateTokenQ = [
121 | // {
122 | // type : 'input',
123 | // name : 'refresh_token',
124 | // message : 'Enter Refresh Token ...'
125 | // }
126 | // ];
127 |
128 |
129 | const updateUserQ = [
130 | {
131 | type : 'input',
132 | name : 'username',
133 | message : 'Enter Username ...'
134 | },
135 | {
136 | type : 'input',
137 | name : 'firstname',
138 | message : 'Enter Firstname ...'
139 | },
140 | {
141 | type : 'input',
142 | name : 'lastname',
143 | message : 'Enter Lastname ...'
144 | }
145 | ];
146 |
147 | const loginQ = [
148 | {
149 | type : 'input',
150 | name : 'username',
151 | message : 'Enter Username ...'
152 | },
153 | {
154 | type : 'input',
155 | name : 'password',
156 | message : 'Enter Password ...'
157 | }
158 | ];
159 |
160 | program
161 | .version('1.0.0')
162 | .description('API as a Service');
163 |
164 | program
165 | .command('resetPassword')
166 | .alias('passwd')
167 | .description('Reset User Password')
168 | .action(() => {
169 | prompt(resetpasswd).then(answers =>
170 | userController.resetPasswordCommand(answers.username,answers.password,answers.confirmPassword));
171 | });
172 |
173 | program
174 | .command('addUser')
175 | .alias('adduser')
176 | .description('Add New User')
177 | .action(() => {
178 | prompt(addUserQ).then(answers =>
179 | userController.addUserCommand({username: answers.username,first_name: answers.firstname, last_name: answers.lastname, password: answers.password, confirmPassword: answers.confirmPassword}));
180 | });
181 |
182 | program
183 | .command('updateUser')
184 | .alias('updateuser')
185 | .description('Update User')
186 | .action(() => {
187 | prompt(updateUserQ).then(answers =>
188 | userController.updateUserCommand({username: answers.username,first_name: answers.firstname, last_name: answers.lastname}));
189 | });
190 |
191 | program
192 | .command('deleteUser')
193 | .alias('deleteuser')
194 | .description('Delete User')
195 | .action(() => {
196 | prompt(deleteUserQ).then(answers =>
197 | userController.deleteUserCommand({username: answers.username}));
198 | });
199 |
200 | program
201 | .command('loginUser')
202 | .alias('login')
203 | .description('Login User')
204 | .action(() => {
205 | prompt(loginQ).then(answers =>
206 | userController.loginCommand(answers.username, answers.password));
207 | });
208 |
209 | program
210 | .command('sessionValidate')
211 | .alias('session')
212 | .description('Validate Session')
213 | .action(() => {
214 | prompt(validateSessionQ).then(answers =>
215 | userController.validateSessionCommand(answers.token));
216 | });
217 |
218 | program
219 | .command('enableDisableUser')
220 | .alias('userstatus')
221 | .description('Enable or Disable User')
222 | .action(() => {
223 | prompt(enableDisableQ).then(answers =>
224 | userController.enableDisableUserCommand({username: answers.username, enabled_flag: answers.enabled_flag}));
225 | });
226 |
227 | // program
228 | // .command('generateToken')
229 | // .alias('generatetoken')
230 | // .description('Generate Token')
231 | // .action(() => {
232 | // prompt(generateTokenQ).then(answers =>
233 | // userController.generateTokenCommand({refresh_token: answers.refresh_token }));
234 | // });
235 |
236 |
237 |
238 | program.parse(process.argv);
--------------------------------------------------------------------------------
/admin/apps/tasks/db/functions/create_bulk_tasks.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION create_bulk_tasks ( p_data json)
2 | RETURNS json AS
3 | $BODY$
4 | DECLARE
5 | l_out json;
6 | l_message_text text;
7 | l_exception_detail text;
8 | l_exception_hint text;
9 | --
10 | l_id uuid;
11 | l_name text;
12 | l_description text;
13 | l_start_date timestamp;
14 | l_due_date timestamp;
15 | l_priority integer;
16 | l_task_record json;
17 | l_tasks_c CURSOR FOR SELECT json_array_elements(p_data->'tasks');
18 |
19 | BEGIN
20 |
21 | OPEN l_tasks_c;
22 | LOOP
23 | FETCH l_tasks_c INTO l_task_record;
24 | EXIT WHEN NOT FOUND;
25 |
26 | l_id := md5(random()::text || clock_timestamp()::text)::uuid;
27 | l_name := (l_task_record->>'name')::text;
28 | l_description := (l_task_record->>'description')::text;
29 | l_start_date := NOW();
30 | l_due_date := (l_task_record->>'due_date')::timestamp;
31 | l_priority := (l_task_record->>'priority')::integer;
32 |
33 | INSERT INTO tasks
34 | (
35 | id,
36 | name,
37 | description,
38 | start_date,
39 | due_date,
40 | priority,
41 | created,
42 | updated
43 | )
44 | VALUES
45 | (
46 | l_id,
47 | l_name,
48 | l_description,
49 | l_start_date,
50 | l_due_date,
51 | l_priority,
52 | NOW(),
53 | NOW()
54 | );
55 |
56 |
57 | END LOOP;
58 | CLOSE l_tasks_c;
59 |
60 | l_out := '{"status" : "S" , "message" : "OK" }';
61 | RETURN l_out;
62 |
63 | EXCEPTION WHEN OTHERS THEN
64 | GET STACKED DIAGNOSTICS l_message_text = MESSAGE_TEXT,
65 | l_exception_detail = PG_EXCEPTION_DETAIL,
66 | l_exception_hint = PG_EXCEPTION_HINT;
67 | l_out := '{ "status" : "E" , "message" : "' || REPLACE(l_message_text, '"', E'\\"') || '" }';
68 | return l_out;
69 | END
70 | $BODY$
71 | LANGUAGE plpgsql;
--------------------------------------------------------------------------------
/admin/apps/tasks/db/functions/create_task.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION create_task ( p_data json)
2 | RETURNS json AS
3 | $BODY$
4 | DECLARE
5 | l_out json;
6 | l_message_text text;
7 | l_exception_detail text;
8 | l_exception_hint text;
9 | --
10 | l_id uuid;
11 | l_name text;
12 | l_description text;
13 | l_start_date timestamp;
14 | l_due_date timestamp;
15 | l_priority integer;
16 |
17 | BEGIN
18 | l_id := md5(random()::text || clock_timestamp()::text)::uuid;
19 | l_name := (p_data->>'name')::text;
20 | l_description := (p_data->>'description')::text;
21 | l_start_date := NOW();
22 | l_due_date := (p_data->>'due_date')::timestamp;
23 | l_priority := (p_data->>'priority')::integer;
24 |
25 | INSERT INTO tasks
26 | (
27 | id,
28 | name,
29 | description,
30 | start_date,
31 | due_date,
32 | priority,
33 | created,
34 | updated
35 | )
36 | VALUES
37 | (
38 | l_id,
39 | l_name,
40 | l_description,
41 | l_start_date,
42 | l_due_date,
43 | l_priority,
44 | NOW(),
45 | NOW()
46 | );
47 |
48 | l_out := '{"status" : "S" , "message" : "OK" , "id" : "' || l_id || '"}';
49 | RETURN l_out;
50 | EXCEPTION WHEN OTHERS THEN
51 | GET STACKED DIAGNOSTICS l_message_text = MESSAGE_TEXT,
52 | l_exception_detail = PG_EXCEPTION_DETAIL,
53 | l_exception_hint = PG_EXCEPTION_HINT;
54 | l_out := '{ "status" : "E" , "message" : "' || REPLACE(l_message_text, '"', E'\\"') || '" }';
55 | return l_out;
56 | END
57 | $BODY$
58 | LANGUAGE plpgsql;
--------------------------------------------------------------------------------
/admin/apps/tasks/db/functions/delete_task.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION delete_task ( p_data json)
2 | RETURNS json AS
3 | $BODY$
4 | DECLARE
5 | l_out json;
6 | l_message_text text;
7 | l_exception_detail text;
8 | l_exception_hint text;
9 | --
10 | l_id uuid;
11 | l_cnt int;
12 | BEGIN
13 | l_id := (p_data->>'id')::uuid;
14 |
15 | DELETE FROM tasks
16 | WHERE id = l_id;
17 |
18 | GET DIAGNOSTICS l_cnt = row_count;
19 |
20 | l_out := '{"status" : "S" , "message" : "OK" , "rows_affected" : "' || l_cnt || '"}';
21 | RETURN l_out;
22 | EXCEPTION WHEN OTHERS THEN
23 | GET STACKED DIAGNOSTICS l_message_text = MESSAGE_TEXT,
24 | l_exception_detail = PG_EXCEPTION_DETAIL,
25 | l_exception_hint = PG_EXCEPTION_HINT;
26 | l_out := '{ "status" : "E" , "message" : "' || REPLACE(l_message_text, '"', E'\\"') || '" }';
27 | return l_out;
28 | END
29 | $BODY$
30 | LANGUAGE plpgsql;
--------------------------------------------------------------------------------
/admin/apps/tasks/db/functions/select_task.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION select_task ( p_data json)
2 | RETURNS json AS
3 | $BODY$
4 | DECLARE
5 | l_out json;
6 | l_message_text text;
7 | l_exception_detail text;
8 | l_exception_hint text;
9 | --
10 | l_data text;
11 | l_id uuid;
12 | l_params json;
13 | BEGIN
14 |
15 | l_params := (p_data->>'urlparams')::json;
16 |
17 | IF l_params IS NOT NULL THEN
18 | l_id := (l_params->>'id')::uuid;
19 | END IF;
20 |
21 | IF l_id IS NULL THEN
22 | SELECT array_to_json(array_agg(row_to_json(t.*))) INTO l_data
23 | FROM (SELECT * FROM tasks) t;
24 | ELSE
25 | SELECT array_to_json(array_agg(row_to_json(t.*))) INTO l_data
26 | FROM (SELECT * FROM tasks WHERE id = l_id) t;
27 | END IF;
28 |
29 | l_out := '{"status" : "S" , "message" : "OK" , "data" : ' || l_data || '}';
30 | RETURN l_out;
31 | EXCEPTION WHEN OTHERS THEN
32 | GET STACKED DIAGNOSTICS l_message_text = MESSAGE_TEXT,
33 | l_exception_detail = PG_EXCEPTION_DETAIL,
34 | l_exception_hint = PG_EXCEPTION_HINT;
35 | l_out := '{ "status" : "E" , "message" : "' || REPLACE(l_message_text, '"', E'\\"') || '" }';
36 | return l_out;
37 | END
38 | $BODY$
39 | LANGUAGE plpgsql;
--------------------------------------------------------------------------------
/admin/apps/tasks/db/functions/update_task.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION update_task ( p_data json)
2 | RETURNS json AS
3 | $BODY$
4 | DECLARE
5 | l_out json;
6 | l_message_text text;
7 | l_exception_detail text;
8 | l_exception_hint text;
9 | --
10 | l_id uuid;
11 | l_name text;
12 | l_description text;
13 | l_due_date timestamp;
14 | l_priority integer;
15 | l_cnt int;
16 | BEGIN
17 | l_id := (p_data->>'id')::uuid;
18 | l_name := (p_data->>'name')::text;
19 | l_description := (p_data->>'description')::text;
20 | l_due_date := (p_data->>'due_date')::timestamp;
21 | l_priority := (p_data->>'priority')::integer;
22 |
23 | UPDATE tasks
24 | SET name = COALESCE(l_name,name)
25 | , description = COALESCE(l_description, description)
26 | , due_date = COALESCE(l_due_date, due_date)
27 | , priority = COALESCE(l_priority, priority)
28 | , updated = NOW()
29 | WHERE id = l_id;
30 |
31 | GET DIAGNOSTICS l_cnt = row_count;
32 |
33 | l_out := '{"status" : "S" , "message" : "OK" , "rows_affected" : "' || l_cnt || '"}';
34 | RETURN l_out;
35 | EXCEPTION WHEN OTHERS THEN
36 | GET STACKED DIAGNOSTICS l_message_text = MESSAGE_TEXT,
37 | l_exception_detail = PG_EXCEPTION_DETAIL,
38 | l_exception_hint = PG_EXCEPTION_HINT;
39 | l_out := '{ "status" : "E" , "message" : "' || REPLACE(l_message_text, '"', E'\\"') || '" }';
40 | return l_out;
41 | END
42 | $BODY$
43 | LANGUAGE plpgsql;
--------------------------------------------------------------------------------
/admin/apps/tasks/db/script.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS tasks (
2 | id uuid NOT NULL,
3 | name text NOT NULL,
4 | description text NOT NULL,
5 | start_date timestamp with time zone NOT NULL,
6 | due_date timestamp with time zone NOT NULL,
7 | priority integer NOT NULL,
8 | created timestamp with time zone NOT NULL,
9 | updated timestamp with time zone NOT NULL
10 | );
--------------------------------------------------------------------------------
/admin/apps/tasks/install.json:
--------------------------------------------------------------------------------
1 | {
2 | "application" :
3 | {
4 | "identifier" : "1a6d3a4f-446e-84d5-fd5d-cd83f5fdc57c"
5 | , "name" : "Task Demo"
6 | , "short_code" : "task"
7 | } ,
8 | "functions" :
9 | [{
10 | "name" : "create_task"
11 | , "db_method" : "create_task"
12 | , "routes" : [{
13 | "name" : "Create Task"
14 | , "route_url" : "/api/task/create"
15 | , "route_method" : "POST"
16 | , "sample_request" : "{\"name\":\"Task3\" , \"description\":\"Task Description 2\", \"priority\": 2, \"start_date\":\"2018-12-08 02:41:17\", \"due_date\":\"2018-12-12 01:31:10\"}"
17 | , "sample_response" : "{\"status\":\"S\",\"message\":\"OK\",\"result\":[{\"result\":{\"status\":\"S\",\"message\":\"OK\",\"id\":\"8003c392-d89a-e577-be11-5f42808cf28b\"}}]}"
18 | }]
19 | }, {
20 | "name" : "create_bulk_tasks"
21 | , "db_method" : "create_bulk_tasks"
22 | , "routes" : [{
23 | "name" : "Create Bulk Task"
24 | , "route_url" : "/api/tasks/bulk/create"
25 | , "route_method" : "POST"
26 | , "sample_request" : "{\"tasks\": [{\"name\":\"Task4\" , \"description\":\"Task Description 4\", \"priority\": 2, \"start_date\":\"2018-12-08 02:41:17\", \"due_date\":\"2018-12-12 01:31:10\"},{\"name\":\"Task5\" , \"description\":\"Task Description 5\", \"priority\": 2, \"start_date\":\"2018-12-08 02:41:17\", \"due_date\":\"2018-12-12 01:31:10\"}]}"
27 | , "sample_response" : "{\"status\":\"S\",\"message\":\"OK\",\"result\":[{\"result\":{\"status\":\"S\",\"message\":\"OK\"}}]}"
28 | }]
29 | } , {
30 | "name" : "update_task"
31 | , "db_method" : "update_task"
32 | , "routes" : [{
33 | "name" : "Update Task"
34 | , "route_url" : "/api/task/update"
35 | , "route_method" : "POST"
36 | , "sample_request" : "{\"id\":\"8003c392-d89a-e577-be11-5f42808cf28b\",\"name\":\"Task2\"}"
37 | , "sample_response" : "{\"status\":\"S\",\"message\":\"OK\",\"result\":[{\"result\":{\"status\":\"S\",\"message\":\"OK\",\"rows_affected\":\"1\"}}]}"
38 | }]
39 | } ,{
40 | "name" : "delete_task"
41 | , "db_method" : "delete_task"
42 | , "routes" : [{
43 | "name" : "Delete Task"
44 | , "route_url" : "/api/task/delete"
45 | , "route_method" : "POST"
46 | , "sample_request" : "{\"id\":\"8003c392-d89a-e577-be11-5f42808cf28b\"}"
47 | , "sample_response" : "{\"status\":\"S\",\"message\":\"OK\",\"result\":[{\"result\":{\"status\":\"S\",\"message\":\"OK\",\"rows_affected\":\"1\"}}]}"
48 | }]
49 | }, {
50 | "name" : "select_task"
51 | , "db_method" : "select_task"
52 | , "routes" : [{
53 | "name" : "Select Task"
54 | , "route_url" : "/api/tasks"
55 | , "route_method" : "GET"
56 | , "sample_request" : ""
57 | , "sample_response" : "{\"status\":\"S\",\"message\":\"OK\",\"result\":[{\"result\":{\"status\":\"S\",\"message\":\"OK\",\"data\":[{\"id\":\"d716a072-be43-2301-1d9e-80998bb0c95e\",\"name\":\"Task4\",\"description\":\"Task Description 4\",\"start_date\":\"2018-12-22T23:56:29.495069+05:30\",\"due_date\":\"2018-12-12T01:31:10+05:30\",\"priority\":2,\"created\":\"2018-12-22T23:56:29.495069+05:30\",\"updated\":\"2018-12-22T23:56:29.495069+05:30\"},{\"id\":\"4ee0bec0-f5df-e75e-9180-25dc216bd021\",\"name\":\"Task5\",\"description\":\"Task Description 5\",\"start_date\":\"2018-12-22T23:56:29.495069+05:30\",\"due_date\":\"2018-12-12T01:31:10+05:30\",\"priority\":2,\"created\":\"2018-12-22T23:56:29.495069+05:30\",\"updated\":\"2018-12-22T23:56:29.495069+05:30\"}]}}]}"
58 | },
59 | {
60 | "name" : "Select Task By Id"
61 | , "route_url" : "/api/tasks/:id"
62 | , "route_method" : "GET"
63 | , "sample_request": ""
64 | , "sample_response" : "{\"status\":\"S\",\"message\":\"OK\",\"result\":[{\"result\":{\"status\":\"S\",\"message\":\"OK\",\"data\":[{\"id\":\"d716a072-be43-2301-1d9e-80998bb0c95e\",\"name\":\"Task4\",\"description\":\"Task Description 4\",\"start_date\":\"2018-12-22T23:56:29.495069+05:30\",\"due_date\":\"2018-12-12T01:31:10+05:30\",\"priority\":2,\"created\":\"2018-12-22T23:56:29.495069+05:30\",\"updated\":\"2018-12-22T23:56:29.495069+05:30\"}]}}]}"
65 | }]
66 | }
67 | ]
68 | }
--------------------------------------------------------------------------------
/admin/config/admin:
--------------------------------------------------------------------------------
1 | username=admin
2 | password=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXNzd29yZCI6ImFkbWluIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTUzNjc4NDQxOH0.TsHgUUsnSHFRXA8tihL-X7_mdqfT0gphTDOTJNJfCO0
3 | encrypt=Y
4 |
--------------------------------------------------------------------------------
/admin/controllers/Connection.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const model = require('../models/Connection');
21 | const coremodel = require('../core/models/Connection');
22 | const utils = require('../Utils');
23 |
24 | const create = async function(record) {
25 | let validation = await model.validate(record,'I',true);
26 |
27 | if (validation.status === 'E') {
28 | return {
29 | status: validation.status,
30 | message: validation.message
31 | };
32 | }
33 | return await model.insert(validation.record);
34 |
35 | }
36 |
37 | const addDefaultConnection = async function() {
38 | // Add the default Database Connection
39 | const db = JSON.parse(process.env.pgapi);
40 | let record = {
41 | name: "default-connection",
42 | host: db.DB_HOST,
43 | port: db.DB_PORT,
44 | database: db.DB_NAME,
45 | username: db.DB_USER,
46 | password: db.DB_PASSWORD,
47 | config_flag: "Y"
48 | };
49 |
50 | let response = await create(record);
51 |
52 | if (response.status === "S") {
53 | console.log("Default connection entry added.")
54 | } else {
55 | console.log(`Failed to create default connection ${response.message}`.yellow);
56 | }
57 |
58 | }
59 |
60 |
61 |
62 | const createAPI = async function(req, res) {
63 | let record = req.body;
64 | let response = await create(record);
65 | res.json(response);
66 | res.end();
67 | }
68 |
69 | const update = async function(req, res) {
70 | let id = req.params.id;
71 |
72 | if (!id) {
73 | res.json({
74 | status: 'E',
75 | message: 'Missing id information'
76 | });
77 | return;
78 | }
79 |
80 | let record = req.body;
81 | record.id = id;
82 | let validation = await model.validate(record,'U',true);
83 | if (validation.status === 'E') {
84 | res.json({
85 | status: validation.status,
86 | message: validation.message
87 | });
88 | return;
89 | }
90 | const response = await model.update(validation.record);
91 | res.json(response);
92 | }
93 |
94 | const deleteItem = async function(req, res) {
95 | let id = req.params.id;
96 |
97 | if (!id) {
98 | res.json({
99 | status: 'E',
100 | message: 'Missing id information'
101 | });
102 | return;
103 | }
104 |
105 | let record = { id: id};
106 | let validation = await model.validate(record,'D',true);
107 | if (validation.status === 'E') {
108 | res.json({
109 | status: validation.status,
110 | message: validation.message
111 | });
112 | return;
113 | }
114 | const response = await model.delete(record);
115 | res.json(response);
116 | }
117 |
118 | const fetch = async function(req, res) {
119 | const response = await model.fetchAll();
120 | res.json(response);
121 | };
122 |
123 | const fetchByName = async function(record) {
124 | const response = await coremodel.fetchByName(record);
125 | return response;
126 | };
127 |
128 | const testDBConnection = async function(req, res) {
129 |
130 | if (!!req.query && !!req.query.host && !!req.query.port && !!req.query.database
131 | && !!req.query.username && !!req.query.password ) {
132 | const record = req.query;
133 | if (!!record.id && record.decrypt === 'Y') {
134 | const passwd = record["password"];
135 | record["password"] = utils.decryptByKey(passwd,'connection');
136 | }
137 | const response = await utils.validateConnection(record);
138 | res.json({status: response.status , message: response.message });
139 | return;
140 | }
141 | else {
142 | res.json({status: 'E' , message: 'Missing required parameters : [host,port,database,username,password]'});
143 | return;
144 | }
145 | };
146 |
147 | const testDBConnections = async function(req, res) {
148 | const connections = await model.fetchAll();
149 | let output = {};
150 | for (let i in connections) {
151 | const record = connections[i];
152 | const passwd = record["password"];
153 | record["password"] = utils.decryptByKey(passwd,'connection');
154 | const response = await utils.validateConnection(record);
155 | if (response.status === "E") {
156 | output[record.id] = false;
157 | } else {
158 | output[record.id] = true;
159 | }
160 |
161 | }
162 | res.json(output);
163 | };
164 |
165 | module.exports = {
166 | createAPI: createAPI,
167 | create: create,
168 | update: update,
169 | fetch: fetch,
170 | delete: deleteItem,
171 | testDBConnection: testDBConnection,
172 | testDBConnections: testDBConnections,
173 | addDefaultConnection: addDefaultConnection,
174 | fetchByName: fetchByName
175 | }
--------------------------------------------------------------------------------
/admin/controllers/Dashboard.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const utils = require('../Utils');
21 | const fs = require('fs');
22 | const path = require('path');
23 | const connectionModel = require('../core/models/Connection');
24 | const functionModel = require('../core/models/Function');
25 | const routeModel = require('../core/models/Route');
26 |
27 | const exportConfig = async function(req, res) {
28 | if (!!req.query && !!req.query.secret_key) {
29 | const response = await utils.exportConfig(req.query.secret_key);
30 | res.json({status: 'S' , message: 'OK' , results : response});
31 | return;
32 | }
33 | else {
34 | res.json({status: 'E' , message: 'Missing input parameter : secret_key' , results : []});
35 | return
36 | }
37 |
38 | };
39 |
40 | const deleteConfig = async function(req, res) {
41 | const response = await deleteConfigurations();
42 | res.json(response);
43 | return;
44 |
45 | };
46 |
47 | const importConfig = async function(req, res) {
48 | if (!!req.body) {
49 | if (!req.body.secret_key) {
50 | res.json({status: 'E' , message: 'Missing input parameter : secret_key' , results : []});
51 | return
52 | }
53 | if (!req.body.secret_key) {
54 | res.json({status: 'E' , message: 'Missing input parameter : configuration file input' , results : []});
55 | return
56 |
57 | }
58 |
59 |
60 | const response = await importConfigContent(req.body.secret_key, req.body.content );
61 | res.json(response);
62 | return;
63 | } else {
64 | res.json({status: 'E' , message: 'Missing input parameter : secret_key , configuration file input' , results : []});
65 | return
66 | }
67 |
68 | };
69 |
70 |
71 | function CustomException() {}
72 |
73 | const processApplications = async function(applications, pool) {
74 | let applicationErrors = [];
75 | let status = 'S';
76 | let message = 'OK';
77 |
78 |
79 | if (!Array.isArray(applications)) {
80 | applicationErrors.push( 'Invalid File. The Applications must be of type = Array');
81 | status = 'E';
82 | message = 'Invalid File';
83 | return {status: status, message: message, errors: applicationErrors};
84 | }
85 |
86 | for (let i in applications) {
87 | if (typeof applications[i] === 'object') {
88 | let record = applications[i];
89 | let response = await utils.callSQL("INSERT INTO APPLICATIONS (id,name,created,updated) VALUES ($1,$2,$3,$4) ",[record["id"],record["name"], record["created"], record["updated"]], pool);
90 |
91 | if (response.status === 'E') {
92 | applicationErrors.push(response.message);
93 | status = 'E';
94 | message = 'Invalid File';
95 | return {status: status, message: message, errors: applicationErrors};
96 | }
97 | } else {
98 | applicationErrors.push('Invalid File. Record[' + i + '] -> The Applications array elements must be of type = Object');
99 |
100 | if (applicationErrors.length > 0) {
101 | status = 'E';
102 | message = 'Invalid File';
103 | return {status: status, message: message, errors: applicationErrors};
104 | }
105 | }
106 |
107 | }
108 | return {status: status, message: message, errors: [] };
109 | }
110 |
111 | const processConnections = async function(secretKey, connections, client) {
112 |
113 | let connectionErrors = [];
114 | let status = 'S';
115 | let message = 'OK';
116 |
117 |
118 | if (!Array.isArray(connections)) {
119 | connectionErrors.push( 'Invalid File. The connections must be of type = Array');
120 | status = 'E';
121 | message = 'Invalid File';
122 | return {status: status, message: message, errors: connectionErrors};
123 | }
124 |
125 | for (let i in connections) {
126 |
127 | if (typeof connections[i] === 'object') {
128 | let record = connections[i];
129 |
130 | if (!!record.id) {
131 | record.ref_source_id = record.id;
132 | record.id = null;
133 | }
134 | if (!!record.created) {
135 | record.created = null;
136 | }
137 | if (!!record.updated) {
138 | record.updated = null;
139 | }
140 |
141 | let validation = await connectionModel.validate(record, 'I', false, client);
142 |
143 | if (validation.status === 'E') {
144 | connectionErrors.push('Invalid File. Record[' + (i + 1) + '] -> ' + validation.message);
145 | status = 'E';
146 | message = 'Invalid File';
147 | return {status: status, message: message, errors: connectionErrors};
148 | }
149 |
150 | if (connectionErrors.length == 0)
151 | {
152 | if ( record.encrypt === 'Y') {
153 | let passwd = record.password;
154 | let decryptPassword = utils.decryptByKey(passwd,secretKey);
155 | validation.record["password"] = utils.encryptByKey(decryptPassword, 'connection');
156 | } else {
157 | let passwd = record.password;
158 | validation.record["password"] = utils.encryptByKey(passwd, 'connection');
159 | }
160 |
161 | // do the insert
162 | let response = await connectionModel.insert(validation.record,client);
163 |
164 | if (response.status === 'E') {
165 | connectionErrors.push(response.message);
166 | status = 'E';
167 | message = 'Invalid File';
168 | return {status: status, message: message, errors: connectionErrors};
169 | }
170 | }
171 |
172 | } else {
173 | connectionErrors.push('Invalid File. Record[' + i + '] -> The connections array elements must be of type = Object');
174 |
175 | if (connectionErrors.length > 0) {
176 | status = 'E';
177 | message = 'Invalid File';
178 | return {status: status, message: message, errors: connectionErrors};
179 | }
180 | }
181 | }
182 |
183 | return {status: status, message: message, errors: [] };
184 |
185 | }
186 |
187 | const processFunctions = async function(functions, client) {
188 |
189 | let functionErrors = [];
190 | let status = 'S';
191 | let message = 'OK';
192 |
193 |
194 | if (!Array.isArray(functions)) {
195 | functionErrors.push( 'Invalid File. The Functions must be of type = Array');
196 | status = 'E';
197 | message = 'Invalid File';
198 | return {status: status, message: message, errors: functionErrors};
199 | }
200 |
201 | for (let i in functions) {
202 |
203 | if (typeof functions[i] === 'object') {
204 | let record = functions[i];
205 |
206 | if (!!record.id) {
207 | record.ref_source_id = record.id;
208 | record.id = null;
209 | }
210 | if (!!record.created) {
211 | record.created = null;
212 | }
213 | if (!!record.updated) {
214 | record.updated = null;
215 | }
216 |
217 | // cross reference the connection ID
218 | const connectionArray = await utils.getSQLResults("SELECT id FROM connections WHERE ref_source_id = $1",[record.connection_id],client);
219 | const connectionID = connectionArray[0]["id"];
220 |
221 | record.connection_id = connectionID;
222 | let validation = await functionModel.validate(record, 'I', false, client);
223 |
224 | if (validation.status === 'E') {
225 | functionErrors.push('Invalid File. Record[' + (i + 1) + '] -> ' + validation.message);
226 | status = 'E';
227 | message = 'Invalid File';
228 | return {status: status, message: message, errors: functionErrors};
229 | }
230 |
231 | if (functionErrors.length == 0)
232 | {
233 |
234 | // do the insert
235 | let response = await functionModel.insert(validation.record,client);
236 |
237 | if (response.status === 'E') {
238 | functionErrors.push(response.message);
239 | status = 'E';
240 | message = 'Invalid File';
241 | return {status: status, message: message, errors: functionErrors};
242 | }
243 | }
244 |
245 | } else {
246 | functionErrors.push('Invalid File. Record[' + i + '] -> The functions array elements must be of type = Object');
247 |
248 | if (functionErrors.length > 0) {
249 | status = 'E';
250 | message = 'Invalid File';
251 | return {status: status, message: message, errors: functionErrors};
252 | }
253 | }
254 | }
255 |
256 | return {status: status, message: message, errors: functionErrors};
257 | }
258 |
259 | const processRoutes = async function(routes, client) {
260 |
261 | let routeErrors = [];
262 | let status = 'S';
263 | let message = 'OK';
264 |
265 |
266 | if (!Array.isArray(routes)) {
267 | routeErrors.push( 'Invalid File. The connections must be of type = Array');
268 | status = 'E';
269 | message = 'Invalid File';
270 | return {status: status, message: message, errors: routeErrors};
271 | }
272 |
273 | for (let i in routes) {
274 |
275 | if (typeof routes[i] === 'object') {
276 | let record = routes[i];
277 |
278 | if (!!record.id) {
279 | record.ref_source_id = record.id;
280 | record.id = null;
281 | }
282 | if (!!record.created) {
283 | record.created = null;
284 | }
285 | if (!!record.updated) {
286 | record.updated = null;
287 | }
288 |
289 | // cross reference the connection ID
290 | const functionArray = await utils.getSQLResults("SELECT id FROM functions WHERE ref_source_id = $1",[record.function_id],client);
291 | const functionID = functionArray[0]["id"];
292 |
293 | record.function_id = functionID;
294 |
295 | let validation = await routeModel.validate(record, 'I', false, client);
296 |
297 | if (validation.status === 'E') {
298 | routeErrors.push('Invalid File. Record[' + (i + 1) + '] -> ' + validation.message);
299 | status = 'E';
300 | message = 'Invalid File';
301 | return {status: status, message: message, errors: routeErrors};
302 | }
303 |
304 | if (routeErrors.length == 0)
305 | {
306 | // do the insert
307 | let response = await routeModel.insert(validation.record,client);
308 |
309 | if (response.status === 'E') {
310 | routeErrors.push(response.message);
311 | status = 'E';
312 | message = 'Invalid File';
313 | return {status: status, message: message, errors: routeErrors};
314 | }
315 | }
316 |
317 | } else {
318 | routeErrors.push('Invalid File. Record[' + i + '] -> The routes array elements must be of type = Object');
319 |
320 | if (routeErrors.length > 0) {
321 | status = 'E';
322 | message = 'Invalid File';
323 | return {status: status, message: message, errors: routeErrors};
324 | }
325 | }
326 | }
327 |
328 | return {status: status, message: message, errors: routeErrors};
329 | }
330 |
331 | const getEncryptedPassword = function(connections) {
332 | for (let i in connections) {
333 | if (connections[i].encrypt === "Y") {
334 | return connections[i].password;
335 | }
336 | }
337 |
338 | return null
339 | }
340 |
341 | const deleteConfigurations = async function() {
342 |
343 | let status = 'S';
344 | let message = 'OK';
345 |
346 | const pool = await utils.getClient();
347 |
348 | const client = await pool.connect();
349 |
350 | try {
351 |
352 | await client.query('BEGIN');
353 |
354 | let status = await utils.callSQL("DELETE FROM ROUTES WHERE 1 = $1",[1],client);
355 |
356 | if (status.status === "E") {
357 | status = "E";
358 | message = "Error Deleting Configurations (routes)";
359 | throw new CustomException();
360 | }
361 |
362 | status = await utils.callSQL("DELETE FROM FUNCTIONS WHERE 1 = $1",[1],client);
363 |
364 | if (status.status === "E") {
365 | status = "E";
366 | message = "Error Deleting Configurations (functions)";
367 | throw new CustomException();
368 | }
369 |
370 | status = await utils.callSQL("DELETE FROM CONNECTIONS WHERE 1 = $1",[1],client);
371 |
372 | if (status.status === "E") {
373 | status = "E";
374 | message = "Error Deleting Configurations (connections)";
375 | throw new CustomException();
376 | }
377 |
378 | status = await utils.callSQL("DELETE FROM APPLICATIONS WHERE 1 = $1",[1],client);
379 |
380 | if (status.status === "E") {
381 | status = "E";
382 | message = "Error Deleting Configurations (applications)";
383 | throw new CustomException();
384 | }
385 |
386 | await client.query('COMMIT');
387 |
388 |
389 | } catch (e) {
390 | console.log(e);
391 | console.log("Rollback Called");
392 | await client.query('ROLLBACK')
393 | // throw e
394 | } finally {
395 | client.release()
396 | }
397 |
398 | return {status: status , message: message };
399 |
400 | }
401 |
402 | const importConfigContent = async function(secretKey, content) {
403 | let importObj = null;
404 | let status = 'S';
405 | let message = 'OK';
406 |
407 | try {
408 | importObj = JSON.parse(content);
409 | } catch(e) {
410 | console.log(e);
411 | return {status: 'E' , message: 'Invalid File Format. The file must contain JSON Content', result: {} };
412 |
413 | }
414 |
415 | if (!importObj) {
416 | return {status: 'E' , message: 'File is empty', result: {} };
417 |
418 | }
419 |
420 | if (!importObj["connections"] && !importObj["functions"] && !importObj["routes"]) {
421 | return {status: 'S' , message: 'OK', result: {connections : {count: 0 , errors: [] } , functions : {count: 0 , errors: [] } , routes : {count: 0 , errors: [] }
422 | } };
423 | }
424 |
425 | const pool = await utils.getClient();
426 |
427 | const client = await pool.connect();
428 | let result = {connections: [] , functions: [] , routes:[] };
429 |
430 | try {
431 |
432 | await client.query('BEGIN');
433 |
434 | if (!!importObj["connections"]) {
435 |
436 | let encryptedPassword = getEncryptedPassword(importObj["connections"]);
437 | if (!!encryptedPassword && utils.decryptByKey(encryptedPassword,secretKey) === '') {
438 | return {status: "E" , message: "Invalid Secret Key", result: result};
439 | }
440 |
441 | const connectionStatus = await processConnections(secretKey, importObj["connections"], client);
442 |
443 | if (!connectionStatus) {
444 | const connections = {count : 0 , errors : [] };
445 | status = 'E';
446 | message = 'Invalid File';
447 | result.connections = connections;
448 | throw new CustomException();
449 |
450 | }
451 | if (connectionStatus.status === "E") {
452 | const connections = {count : 0 , errors :connectionStatus.errors };
453 | status = 'E';
454 | message = 'Invalid File';
455 | result.connections = connections;
456 | throw new CustomException();
457 | } else {
458 | const connections = {count : importObj["connections"].length , errors :connectionStatus.errors };
459 | result.connections = connections;
460 | }
461 | }
462 |
463 | if (!!importObj["functions"]) {
464 | const functionStatus = await processFunctions(importObj["functions"], client);
465 | if (functionStatus.status === "E") {
466 | const functions = {count : 0 , errors : functionStatus.errors };
467 | status = 'E';
468 | message = 'Invalid File';
469 | result.functions = functions;
470 | throw new CustomException();
471 | } else {
472 | const functions = {count : importObj["functions"].length , errors : functionStatus.errors };
473 | result.functions = functions;
474 | }
475 | }
476 |
477 | if (!!importObj["routes"]) {
478 | const routeStatus = await processRoutes(importObj["routes"], client);
479 | if (routeStatus.status === "E") {
480 | const routes = {count : 0 , errors : routeStatus.errors };
481 | status = 'E';
482 | message = 'Invalid File';
483 | result.routes = routes;
484 | throw new CustomException();
485 | } else {
486 | const routes = {count : importObj["routes"].length , errors : routeStatus.errors };
487 | result.routes = routes;
488 | }
489 | }
490 |
491 | if (!!importObj["applications"]) {
492 | const applicationStatus = await processApplications(importObj["applications"], client);
493 | if (applicationStatus.status === "E") {
494 | const applications = {count : 0 , errors : applicationStatus.errors };
495 | status = 'E';
496 | message = 'Invalid File';
497 | result.applications = applications;
498 | throw new CustomException();
499 | } else {
500 | const applications = {count : importObj["applications"].length , errors : applicationStatus.errors };
501 | result.applications = applications;
502 | }
503 | }
504 |
505 |
506 | await client.query('COMMIT');
507 |
508 |
509 | } catch (e) {
510 | console.log(e);
511 | console.log("Rollback Called");
512 | await client.query('ROLLBACK')
513 | // throw e
514 | } finally {
515 | client.release()
516 | }
517 |
518 | return {status: status , message: message, result: result };
519 | };
520 |
521 | const importFileConfig = async function(secretKey, filename) {
522 | const fname = path.resolve(__dirname, filename );
523 | let content = fs.readFileSync(fname, 'utf8');
524 | return await importConfigContent(secretKey,content);
525 | }
526 |
527 | module.exports = {
528 | exportConfig: exportConfig,
529 | importConfig: importConfig,
530 | importConfigContent: importConfigContent,
531 | importFileConfig: importFileConfig,
532 | deleteConfigurations: deleteConfigurations,
533 | deleteConfig: deleteConfig
534 |
535 | }
--------------------------------------------------------------------------------
/admin/controllers/Function.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const model = require('../models/Function');
21 | const coremodel = require('../core/models/Function');
22 | const utils = require('../Utils');
23 |
24 | const create = async function(record) {
25 | let validation = await model.validate(record,'I',true);
26 |
27 | if (validation.status === 'E') {
28 | return {
29 | status: validation.status,
30 | message: validation.message
31 | };
32 | }
33 | let response = await model.insert(validation.record);
34 | return response;
35 | }
36 |
37 | const createAPI = async function(req, res) {
38 | let record = req.body;
39 | let response = await create(record);
40 | res.json(response);
41 | res.end();
42 | }
43 |
44 | const update = async function(req, res) {
45 | let id = req.params.id;
46 |
47 | if (!id) {
48 | res.json({
49 | status: 'E',
50 | message: 'Missing id information'
51 | });
52 | return;
53 | }
54 |
55 | let record = req.body;
56 | record.id = id;
57 | let validation = await model.validate(record,'U',true);
58 | if (validation.status === 'E') {
59 | res.json({
60 | status: validation.status,
61 | message: validation.message
62 | });
63 | return;
64 | }
65 | const response = await model.update(validation.record);
66 | res.json(response);
67 | }
68 |
69 | const deleteItem = async function(req, res) {
70 | let id = req.params.id;
71 |
72 | if (!id) {
73 | res.json({
74 | status: 'E',
75 | message: 'Missing id information'
76 | });
77 | return;
78 | }
79 |
80 | let record = { id: id};
81 | let validation = await model.validate(record,'D',true);
82 | if (validation.status === 'E') {
83 | res.json({
84 | status: validation.status,
85 | message: validation.message
86 | });
87 | return;
88 | }
89 | const response = await model.delete(record);
90 | res.json(response);
91 | }
92 |
93 | const fetch = async function(req, res) {
94 | const response = await model.fetchAll();
95 | res.json(response);
96 | };
97 |
98 | const fetchByName = async function(record) {
99 | const response = await coremodel.fetchByName(record);
100 | return response;
101 | };
102 |
103 | const testDBFunctions = async function(req, res) {
104 | const functions = await model.fetchAll();
105 |
106 | let output = {};
107 | for (let i in functions) {
108 | const record = functions[i];
109 | const resultsObject = await utils.validateFunction(record["connection_id"],record["db_method"]);
110 |
111 | if (resultsObject.status === "E") {
112 | output[record.id] = { status: false, message: resultsObject.message};
113 |
114 | } else {
115 | output[record.id] = { status: true, message: "Function is Valid"};
116 | }
117 | }
118 |
119 | res.json(output);
120 | };
121 |
122 | module.exports = {
123 | create: create,
124 | createAPI: createAPI,
125 | update: update,
126 | fetch: fetch,
127 | delete: deleteItem,
128 | testDBFunctions: testDBFunctions,
129 | fetchByName: fetchByName
130 | }
--------------------------------------------------------------------------------
/admin/controllers/Route.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const model = require('../models/Route');
21 | const utils = require('../Utils');
22 | const colors = require('colors');
23 |
24 | const create = async function(record) {
25 |
26 | let validation = await model.validate(record,'I',true);
27 |
28 | if (validation.status === 'E') {
29 | return {
30 | status: validation.status,
31 | message: validation.message
32 | };
33 |
34 | }
35 | let response = await model.insert(validation.record);
36 |
37 | if (response.status === "S") {
38 | const dbRecord = await model.getRoutesByUrl(record.route_url);
39 | addRouteDetail(dbRecord.result[0]);
40 | }
41 |
42 | return response;
43 | }
44 |
45 | const createAPI = async function(req, res) {
46 | let record = req.body;
47 | let response = await create(record);
48 |
49 | res.json(response);
50 | res.end();
51 | }
52 |
53 | const update = async function(req, res) {
54 | let id = req.params.id;
55 | let deleteRouteFlag = false;
56 | let addRouteFlag = false;
57 |
58 | if (!id) {
59 | res.json({
60 | status: 'E',
61 | message: 'Missing id information'
62 | });
63 | return;
64 | }
65 |
66 | let record = req.body;
67 | record.id = id;
68 | const dbRecord = await model.fetchById(id);
69 |
70 | let validation = await model.validate(record,'U',true);
71 | if (validation.status === 'E') {
72 | res.json({
73 | status: validation.status,
74 | message: validation.message
75 | });
76 | return;
77 | }
78 | const response = await model.update(validation.record);
79 |
80 | if (response.status === "S") {
81 |
82 | if (dbRecord[0].route_url !== record.route_url ) {
83 | deleteRoute(dbRecord[0].route_url);
84 | }
85 |
86 | if (dbRecord[0].enabled_flag !== record.enabled_flag && dbRecord[0].enabled_flag === "Y") {
87 | deleteRoute(dbRecord[0].route_url);
88 | } else {
89 | const dbRecord = await model.getRoutesByUrl(record.route_url);
90 | addRouteDetail(dbRecord.result[0]);
91 | }
92 | }
93 |
94 | res.json(response);
95 | }
96 |
97 | const deleteItem = async function(req, res) {
98 | let id = req.params.id;
99 |
100 | if (!id) {
101 | res.json({
102 | status: 'E',
103 | message: 'Missing id information'
104 | });
105 | return;
106 | }
107 |
108 | const record = { id: id};
109 | const dbRecord = await model.fetchById(id);
110 |
111 | let validation = await model.validate(record,'D',true);
112 | if (validation.status === 'E') {
113 | res.json({
114 | status: validation.status,
115 | message: validation.message
116 | });
117 | return;
118 | }
119 | const response = await model.delete(record);
120 |
121 | if (response.status === 'S') {
122 | deleteRoute(dbRecord[0].route_url);
123 | }
124 |
125 |
126 | res.json(response);
127 | }
128 |
129 | const fetch = async function(req, res) {
130 | const response = await model.fetchAll();
131 | res.json(response);
132 | };
133 |
134 | const fetchById = async function(record) {
135 | const response = await model.fetchById(record);
136 | res.json(response);
137 | };
138 |
139 |
140 | const callDB = async function(req, res, routeCallback,contentType,pool) {
141 |
142 | var data = req.body, results = [],
143 | queryString = "";
144 |
145 | if (req.method === "GET") data = req.query;
146 |
147 | if (contentType === "file") data = { token : req.headers['authorization'] , file_name : req.file.originalname};
148 |
149 | if (!utils.isEmpty(req.params)) {
150 | data["urlparams"] = req.params;
151 | }
152 |
153 | queryString = "select " + routeCallback + "( $1 ) as result";
154 |
155 | let response = await utils.getSQLResultswithStatus(queryString,[ JSON.stringify(data)], pool);
156 |
157 | if (!!response.result && !!response.result[0] && !!response.result[0].result && !!response.result[0].result.private) {
158 | let privateInfo = response.result[0].result.private
159 | utils.handlePrivate(privateInfo, response.result[0].result, req, res).then(function (data) {
160 | delete response.result[0].result.private;
161 | res.json(response);
162 | });
163 |
164 | } else {
165 | return res.json(response);
166 | }
167 |
168 |
169 |
170 | }
171 |
172 | // End of Call
173 |
174 | const addRouteDetail = function(routeInfo) {
175 |
176 | var flag = 0;
177 | var r = global.router;
178 |
179 | for (var i = r.stack.length - 1; i >= 0; i--) {
180 | if (r.stack[i].path === routeInfo.route_url) {
181 | global.router.stack.splice(i, 1);
182 | addRoute(routeInfo);
183 | flag = 1;
184 | }
185 | else if (r.stack[i].path === undefined)
186 | {
187 | if (r.stack[i].route)
188 | {
189 | if ( r.stack[i].route.path === routeInfo.route_url)
190 | {
191 | global.router.stack.splice(i, 1);
192 | addRoute(routeInfo);
193 | flag = 1;
194 | }
195 | }
196 | else
197 | {
198 | // console.log("Route Object empty");
199 | }
200 | }
201 | }
202 |
203 | if (!flag)
204 | {
205 | addRoute(routeInfo);
206 | }
207 |
208 | }
209 |
210 | const addRoute = async function (routeObj) {
211 | if ( routeObj.route_method === "POST")
212 | {
213 |
214 | console.log("loading POST " + routeObj.route_url );
215 | global.router.post(routeObj.route_url, async function(req, res) {
216 | let record = {
217 | host: routeObj.host
218 | , port: routeObj.port
219 | , username: routeObj.username
220 | , password: utils.decryptByKey(routeObj.password,'connection')
221 | , database: routeObj.database
222 | , name: routeObj.connection_name
223 | };
224 |
225 | let pool = await utils.getPoolByName(routeObj.connection_name,record);
226 | callDB(req,res,routeObj.route_callback,routeObj.content_type, pool);
227 |
228 | });
229 | }
230 | else
231 | {
232 | console.log("loading GET " + routeObj.route_url );
233 | global.router.get(routeObj.route_url, async function(req, res) {
234 | let record = {
235 | host: routeObj.host
236 | , port: routeObj.port
237 | , username: routeObj.username
238 | , password: utils.decryptByKey(routeObj.password,'connection')
239 | , database: routeObj.database
240 | , name: routeObj.connection_name
241 | };
242 |
243 | let pool = await utils.getPoolByName(routeObj.connection_name,record);
244 | callDB(req,res,routeObj.route_callback,routeObj.content_type,pool);
245 |
246 | });
247 | }
248 | }
249 |
250 | const deleteRoute = function (url) {
251 | console.log("Deleting route " + url);
252 |
253 | for (var i = global.router.stack.length - 1; i >= 0; i--) {
254 | if (global.router.stack[i].path === url) {
255 | global.router.stack.splice(i, 1);
256 | }
257 | else if (global.router.stack[i].path === undefined)
258 | {
259 | if (global.router.stack[i].route)
260 | {
261 | if ( global.router.stack[i].route.path === url)
262 | {
263 | global.router.stack.splice(i, 1);
264 | }
265 | }
266 | else
267 | {
268 | // console.log("Route Object empty");
269 | }
270 | }
271 | }
272 | }
273 |
274 | const getRoutes = async function () {
275 |
276 | let routesInfo = [];
277 | const response = await model.getRoutes();
278 |
279 | if (response.status === "E") {
280 | return response;
281 | }
282 |
283 | routesInfo = response.result;
284 |
285 | global.router.get('/', (req, res) => { // 2
286 | res.send('Homepage!')
287 | });
288 |
289 | console.log("Generating routes... ".blue)
290 | routesInfo.forEach(function(routeObj){
291 |
292 | if (routeObj.enabled_flag === "Y") {
293 | addRouteDetail(routeObj);
294 | }
295 |
296 | });
297 |
298 | return {status: "S", message : "OK"};
299 | };
300 |
301 | const refreshRoutes = async function(req, res) {
302 | global.router.stack.splice(0,global.router.stack.length);
303 | console.log("Refreshing routes");
304 |
305 | const status = await getRoutes();
306 | res.json(status);
307 | };
308 |
309 | module.exports = {
310 | create: create,
311 | createAPI: createAPI,
312 | update: update,
313 | fetch: fetch,
314 | fetchById: fetchById,
315 | delete: deleteItem,
316 | getRoutes: getRoutes,
317 | refreshRoutes: refreshRoutes,
318 | deleteRoute: deleteRoute
319 | }
--------------------------------------------------------------------------------
/admin/controllers/User.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const model = require('../models/User');
21 | const utils = require('../Utils');
22 |
23 | const resetPassword = async function(username, userPassword , confirmPassword) {
24 |
25 | if (!!userPassword) {
26 | if (!!confirmPassword) {
27 | if (userPassword === confirmPassword) {
28 | let dbRecord = await model.fetchByUsername(username);
29 | // Update Database
30 | // let response = await model.updatePassword({id: dbRecord.id , })
31 | if (!!dbRecord && !!dbRecord.result && dbRecord.result.length > 0) {
32 | let record = dbRecord.result[0];
33 | let encryptedPassword = utils.encryptPassword(userPassword);
34 | let response = await model.updatePassword({password: encryptedPassword , id: record.id });
35 | return response;
36 | } else {
37 | return {status: "ERROR" , message: "Unable to reset the Password"};
38 | }
39 |
40 | } else {
41 | return {status: "ERROR" , message: "The Password and Confirm Password must match"};
42 | }
43 | } else {
44 | return { status: "ERROR" , message: "Invalid Confirm Password Information. THe password Information is blank" };
45 | }
46 | } else {
47 | return { status: "ERROR" , message: "Invalid Password Information. THe password Information is blank" };
48 | }
49 |
50 | }
51 |
52 | const validateLogin = async function(username, password) {
53 | let dbRecord = await model.fetchByUsername(username);
54 |
55 | if (!!dbRecord && !!dbRecord.status && dbRecord.status === "E") {
56 | return dbRecord;
57 | }
58 |
59 | if (dbRecord.result.length === 0 ) {
60 | return {status: "E" , message: "Unable to find user"};
61 | }
62 |
63 | let record = dbRecord.result[0];
64 |
65 | if (utils.isValidPassword(password,record.password)) {
66 | // valid login
67 | return {status:"S",message: "OK", record: record};
68 | } else {
69 | return {status:"E" , message: "Invalid Credentials. Unable to login"};
70 | }
71 |
72 | }
73 |
74 | const resetPasswordAPI = async function(req, res) {
75 | let record = req.body;
76 |
77 | let claims = req.claims;
78 | console.log(claims);
79 |
80 | if (!!record.password && !!record.newpassword && !!record.confirmpassword) {
81 | let response = await validateLogin(claims.username,record.password);
82 | let userPassword = record.newpassword;
83 | let confirmPassword = record.confirmpassword;
84 | if (response.status === "S") {
85 | if (userPassword === confirmPassword) {
86 | let dbRecord = await model.fetchByUsername(claims.username);
87 | // Update Database
88 | // let response = await model.updatePassword({id: dbRecord.id , })
89 | if (!!dbRecord && !!dbRecord.result && dbRecord.result.length > 0) {
90 | let record1 = dbRecord.result[0];
91 | let encryptedPassword = utils.encryptPassword(userPassword);
92 | let response = await model.updatePassword({password: encryptedPassword, id: record1.id });
93 | res.json( response);
94 | res.end();
95 | return;
96 | } else {
97 | res.json({status: "E" , message: "Unable to reset the Password"});
98 | res.end();
99 | return;
100 | }
101 |
102 | } else {
103 | res.json({status: "E" , message: "The Password and Confirm Password must match"});
104 | res.end();
105 | return;
106 | }
107 | } else {
108 | console.log("Error")
109 | res.json(response);
110 | res.end();
111 | return;
112 | }
113 | } else {
114 | res.json({status: "E" , message: "Missing required Information [current password, new password, confirm password]"});
115 | res.end();
116 | return;
117 | }
118 |
119 |
120 | }
121 |
122 | const login = async function(username, password) {
123 |
124 | try {
125 | let response = await validateLogin(username,password);
126 |
127 | if (response.status === "S") {
128 | let d = new Date();
129 | d.setMinutes(d.getMinutes() + 4880);
130 | let record = response.record;
131 | let claims = { id: record.id, username: record.username , first_name: record.first_name , last_name: record.last_name};
132 | let tokenObj = { claims: claims , exp_time: d };
133 | const token = utils.encryptObjectByKey(tokenObj, process.env.PGAPI_SECRET_KEY);
134 | let obj = { token: token , claims: claims };
135 |
136 | let insertTokenResponse = await model.insertToken({token: token, user_id: record.id});
137 |
138 | if (insertTokenResponse.status === "E") {
139 | return {status: "E" , message: insertTokenResponse.message };
140 | }
141 | else {
142 | return {status: "S" , message: "OK" , data: obj};
143 | }
144 |
145 |
146 | } else {
147 | return {status: "E" , message: response.message };
148 | }
149 | } catch (e) {
150 | return {status: "E" , message: e.message };
151 | }
152 |
153 | }
154 |
155 | const loginAPI = async function(req, res) {
156 | let record = req.body;
157 |
158 | let response = await login(record.username, record.password);
159 |
160 | if (response.status === "E") {
161 | res.json(response);
162 | return;
163 | } else {
164 | res.json(response);
165 | res.end();
166 | }
167 | }
168 |
169 | const fetchAPI = async function(req, res) {
170 | let record = req.query;
171 |
172 | let response = await model.fetchByIdUser(record.id);
173 |
174 | res.json(response);
175 | res.end();
176 | }
177 |
178 | const sessionAPI = async function(req, res) {
179 | let record = req.body;
180 |
181 | let response = await validateSession(record.refresh_token);
182 |
183 | if (response.status === "E") {
184 | res.json(response);
185 | return;
186 | } else {
187 | res.json(response);
188 | res.end();
189 | }
190 | }
191 |
192 |
193 | const loginCommand = async function(username, password) {
194 | let response = await login(username, password);
195 |
196 | if (response.status === "E") {
197 | console.log(response.message);
198 | } else {
199 | console.log("Login Success.");
200 | console.log(response.data);
201 | }
202 | }
203 |
204 | const validateSession = async function(token) {
205 | let decoded = utils.decryptObjectByKey(token,process.env.PGAPI_SECRET_KEY);
206 |
207 | if (utils.isEmpty(decoded)) {
208 | return {status: "E" , message: "Invalid Session Information", code: "INVALID"};
209 | } else {
210 | let expTime = new Date(decoded.exp_time);
211 | let currentTime = new Date();
212 |
213 | if (currentTime > expTime) {
214 | return {status: "E" , message: "Session Timeout" , code: "RELOGIN"};
215 | }
216 |
217 | let id = decoded.claims.id;
218 |
219 | const dbRecord = await model.validateSession({token: token});
220 |
221 | if (!!dbRecord && dbRecord.length > 0) {
222 | let result = dbRecord[0].result;
223 |
224 | if (result.status === "E") {
225 | return {status: "E" , message: "Invalid Session Information.", code: result.message};
226 | } else
227 | {
228 | return {status: "S" , message: "OK" , decoded: decoded};
229 | }
230 | } else {
231 | return {status: "E" , message: "Invalid Session Information.", code: "INVALID_USER"};
232 | }
233 |
234 | return {status: "S" , message: "OK" , decoded: decoded};
235 | }
236 | }
237 |
238 | const validateSessionCommand = async function(token) {
239 | let response = await validateSession(token,process.env.PGAPI_SECRET_KEY);
240 |
241 | if (response.status === "E") {
242 | console.log(response.message);
243 | } else {
244 | console.log("Session is Valid.");
245 | console.log(response.decoded);
246 | }
247 | }
248 |
249 |
250 |
251 | const addUser = async function(record) {
252 | let validation = await model.validate(record,'I',true);
253 |
254 | if (validation.status === 'E') {
255 | return {
256 | status: validation.status,
257 | message: validation.message
258 | };
259 | }
260 | let response = await model.insert(validation.record);
261 |
262 | return response;
263 | }
264 |
265 | const addUserCommand = async function(record) {
266 | console.log("Adding user");
267 | let response = await addUser(record);
268 |
269 | if (response.status === "E") {
270 | console.log(response.message);
271 | } else {
272 | console.log("The User has been successfully added.")
273 | }
274 | }
275 |
276 | const updateUser = async function(record) {
277 | let id = record.id;
278 |
279 | if (!id) {
280 | return {
281 | status: 'E',
282 | message: 'Missing id information'
283 | };
284 | }
285 |
286 | let validation = await model.validate(record,'U',true);
287 | if (validation.status === 'E') {
288 | return {
289 | status: validation.status,
290 | message: validation.message
291 | };
292 | }
293 |
294 | const response = await model.update(validation.record);
295 | return response;
296 | }
297 |
298 |
299 | const updateUserAPI = async function(req, res) {
300 | let record = req.body;
301 |
302 | let response = await updateUser(record);
303 |
304 | if (response.status === "E") {
305 | res.json(response);
306 | return;
307 | } else {
308 | res.json(response);
309 | res.end();
310 | }
311 | }
312 |
313 | const deleteUser = async function(record) {
314 | let id = record.id;
315 |
316 | if (!id) {
317 | return {
318 | status: 'E',
319 | message: 'Missing id information'
320 | };
321 | }
322 |
323 | let validation = await model.validate(record,'D',true);
324 | if (validation.status === 'E') {
325 | return {
326 | status: validation.status,
327 | message: validation.message
328 | };
329 | }
330 |
331 | const dbRecord = await model.fetchById(id);
332 |
333 | if (dbRecord[0].username === "admin") {
334 | return {status: "E" , message: "You are not allowed to delete admin account"};
335 | }
336 |
337 | const response = await model.delete(record);
338 |
339 | if (response.status === "S") {
340 | let resp = await model.insertArchive({username: dbRecord[0].username, first_name: dbRecord[0].first_name , last_name: dbRecord[0].last_name
341 | , id: dbRecord[0].id});
342 | return resp;
343 | }
344 |
345 | return response;
346 | }
347 |
348 | const deleteUserCommand = async function(record) {
349 |
350 | let dbRecord = await model.fetchByUsername(record.username);
351 |
352 | if (!!dbRecord && !!dbRecord.status && dbRecord.status === "E") {
353 | console.log(dbRecord.message);
354 | return;
355 | }
356 |
357 | if (dbRecord.result.length === 0 ) {
358 | console.log("Unable to find the user");
359 | return;
360 | }
361 |
362 | record.id = dbRecord.result[0].id;
363 |
364 | let response = await deleteUser(record);
365 |
366 | if (response.status === "E") {
367 | console.log(response.message);
368 | } else {
369 | console.log("The User has been successfully deleted.")
370 | }
371 | }
372 |
373 |
374 |
375 | const updateUserCommand = async function(record) {
376 |
377 | let dbRecord = await model.fetchByUsername(record.username);
378 |
379 | if (!!dbRecord && !!dbRecord.status && dbRecord.status === "E") {
380 | console.log(dbRecord.message);
381 | return;
382 | }
383 |
384 | if (dbRecord.result.length === 0 ) {
385 | console.log("Unable to find the user");
386 | return;
387 | }
388 |
389 | record.id = dbRecord.result[0].id;
390 |
391 | let response = await updateUser(record);
392 |
393 | if (response.status === "E") {
394 | console.log(response.message);
395 | } else {
396 | console.log("The User has been successfully updated.")
397 | }
398 | }
399 |
400 | const resetPasswordCommand = async function(username, userPassword , confirmPassword) {
401 | let response = await resetPassword(username, userPassword , confirmPassword);
402 |
403 | if (response.status === "E") {
404 | console.log(response.message);
405 | } else {
406 | console.log("Password has been changed Successfully.")
407 | }
408 | }
409 |
410 | const enableDisableUser = async function(record) {
411 |
412 | let id = record.id;
413 |
414 | if (!id) {
415 | return {
416 | status: 'E',
417 | message: 'Missing id information'
418 | };
419 | }
420 |
421 | if (!!record && !!record.enabled_flag) {
422 | } else {
423 | return {status: "E" , message: "Invalid enabled_flag value. The value is either incorrect or not provided. Valid Values [Y,N]"}
424 | }
425 |
426 |
427 | const dbRecord = await model.fetchById(id);
428 |
429 | if (!!dbRecord && dbRecord.length > 0) {
430 | if (dbRecord[0].username === "admin") {
431 | return {status: "E" , message: "You are not allowed to modify admin account"};
432 | }
433 |
434 | let response = await model.updateEnabledFlag(record);
435 |
436 | return response;
437 |
438 | } else
439 | {
440 | return {status:"E" , message: "Unable to find the user"};
441 | }
442 |
443 | }
444 |
445 | const enableDisableUserCommand = async function(record) {
446 | let dbRecord = await model.fetchByUsername(record.username);
447 |
448 | if (!!dbRecord && !!dbRecord.status && dbRecord.status === "E") {
449 | console.log(dbRecord.message);
450 | return;
451 | }
452 |
453 | if (dbRecord.result.length === 0 ) {
454 | console.log("Unable to find the user");
455 | return;
456 | }
457 |
458 | record.id = dbRecord.result[0].id;
459 |
460 | let response = await enableDisableUser(record);
461 |
462 | if (response.status === "E") {
463 | console.log(response.message);
464 | } else {
465 | console.log("The User status has been successfully updated.")
466 | }
467 | }
468 |
469 | // const generateToken = async function(record) {
470 | // if (!!record && !!record.refresh_token) {
471 | // let decoded = utils.decryptObjectByKey(record.refresh_token,process.env.REFRESH_SECRET_KEY);
472 | // if (utils.isEmpty(decoded)) {
473 | // return {status: "E" , message: "Invalid Refresh Token Information", code: "RELOGIN"};
474 | // } else {
475 | // let id = decoded.claims.id;
476 |
477 | // const dbRecord = await model.fetchById(id);
478 | // // console.log(dbRecord);
479 |
480 | // if (!!dbRecord && dbRecord.length > 0) {
481 |
482 | // let d = new Date();
483 | // d.setMinutes(d.getMinutes() + 30);
484 | // let claims = decoded.claims;
485 | // let tokenObj = { claims: claims , exp_time: d };
486 | // const token = utils.encryptObjectByKey(tokenObj, process.env.PGAPI_SECRET_KEY);
487 | // let obj = { token: token , refresh_token: record.refresh_token , claims: claims };
488 | // return {status: "S" , message: "OK", data: obj};
489 | // } else {
490 | // return {status: "E" , message: "Invalid Session Information.", code: "INVALID_USER"};
491 | // }
492 | // }
493 |
494 | // } else {
495 | // return {status: "E" , message: "Please provide the refresh token."};
496 | // }
497 | // }
498 |
499 | // const generateTokenCommand = async function(record) {
500 | // let response = await generateToken(record);
501 |
502 | // if (response.status === "E") {
503 | // console.log(response.message);
504 | // } else {
505 | // console.log("The User has been validated.")
506 | // console.log(response.data);
507 | // }
508 | // }
509 |
510 |
511 | module.exports = {
512 | validateLogin: validateLogin,
513 | loginCommand: loginCommand,
514 | loginAPI: loginAPI,
515 | fetchAPI: fetchAPI,
516 | sessionAPI: sessionAPI,
517 | resetPassword: resetPassword,
518 | resetPasswordCommand: resetPasswordCommand,
519 | resetPasswordAPI: resetPasswordAPI,
520 | addUser: addUser,
521 | addUserCommand: addUserCommand,
522 | updateUserCommand: updateUserCommand,
523 | updateUserAPI: updateUserAPI,
524 | deleteUserCommand: deleteUserCommand,
525 | validateSession: validateSession,
526 | validateSessionCommand: validateSessionCommand,
527 | enableDisableUserCommand: enableDisableUserCommand,
528 | // generateTokenCommand: generateTokenCommand
529 | }
--------------------------------------------------------------------------------
/admin/controllers/dbUtils.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const utils = require('../Utils');
21 | const path = require('path');
22 | const fs = require('fs');
23 |
24 | const executeFunction = async function(req, res) {
25 | let record = req.body;
26 |
27 | try {
28 | let response = await utils.loadDBFunctionString(record.sql);
29 | res.json(response);
30 | } catch(e) {
31 | res.json({status:"E" , message: e.message});
32 | }
33 |
34 |
35 | // res.end();
36 | }
37 |
38 | const getDBFunction = async function(req, res) {
39 | let functionName = req.query.db_method;
40 | let connectionID = req.query.connection_id;
41 | let sql = "select pg_get_functiondef(oid) as result from pg_proc where proname = $1"
42 | const sqlResult = await utils.getSQLResultsByConnectionId(connectionID,sql, [functionName]);
43 | let result = "";
44 | if (!!sqlResult && !!sqlResult.data && sqlResult.data.length > 0 ) {
45 | result = sqlResult["data"][0]["result"];
46 | }
47 | const response = {status: "S" , response: "OK", data: result};
48 | res.json(response);
49 | }
50 |
51 | const saveSQL = async function(req, res) {
52 | let record = req.body;
53 |
54 | try {
55 | fs.writeFileSync(path.resolve(__dirname, '../sql/main.sql'),record.sql,{encoding:'utf8',flag:'w'})
56 | res.json({status: "S" , message: "OK"});
57 | } catch(e) {
58 | // console.log(e);
59 | res.json({status:"E" , message: e.message});
60 | }
61 |
62 |
63 | // res.end();
64 | }
65 |
66 | const getSQL = async function(req, res) {
67 | try {
68 | let contents = fs.readFileSync(path.resolve(__dirname, '../sql/main.sql'), 'utf8');
69 | res.json({status: "S" , message: "OK" , data: contents});
70 | } catch(e) {
71 | // console.log(e);
72 | res.json({status:"E" , message: e.message});
73 | }
74 |
75 |
76 | // res.end();
77 | }
78 |
79 |
80 | module.exports = {
81 | executeFunction: executeFunction,
82 | saveSQL: saveSQL,
83 | getSQL: getSQL,
84 | getDBFunction: getDBFunction
85 | }
--------------------------------------------------------------------------------
/admin/core/models/Connection.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const utils = require('../../Utils');
21 | const modelName = "connections";
22 | const metadata = {
23 | insert : {
24 | sql : 'INSERT INTO CONNECTIONS (id,name,host,port,database,username,password,ref_source_id,config_flag,created,updated) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)',
25 | params : function(record) {
26 | let uuid = "";
27 |
28 | if (!record["id"]) {
29 | uuid = utils.getUUID();
30 | } else {
31 | uuid = record["id"];
32 | }
33 |
34 | let config = "N";
35 |
36 | if (!!record["config_flag"]) {
37 | config = record["config_flag"];
38 | }
39 |
40 | return [uuid,record.name,record.host,record.port,record.database,record.username,record.password,record.ref_source_id,config,record.created,record.updated];
41 | },
42 | failureMessage : function(e) {
43 | const status = 'E';
44 | let message = 'Failed to create connection ' + e;
45 |
46 | return {status:status,message:message};
47 | }
48 | },
49 | update : {
50 | sql : 'UPDATE CONNECTIONS SET name = $1 , host = $2 , port = $3 ,database = $4,username = $5,password = $6, updated = $7 WHERE id = $8',
51 | params : function(record) {
52 |
53 | const d = new Date();
54 | return [record.name
55 | , record.host
56 | , record.port
57 | , record.database
58 | , record.username
59 | , record.password
60 | , d
61 | , record.id];
62 | },
63 | failureMessage : function(e) {
64 | const status = 'E';
65 | let message = 'Failed to update connection ' + e;
66 |
67 | return {status:status,message:message};
68 | }
69 |
70 | },
71 | delete : {
72 | sql : 'DELETE FROM CONNECTIONS WHERE id = $1',
73 | params : function(record) {
74 | return [record.id];
75 | },
76 | failureMessage : function(e) {
77 | const status = 'E';
78 | let message = 'Failed to delete connection ' + e;
79 |
80 | return {status:status,message:message};
81 | }
82 | },
83 | fetch : {
84 | sql : 'SELECT * FROM CONNECTIONS',
85 | params : function(record) {
86 | return [];
87 | },
88 | failureMessage : function(e) {
89 | return {};
90 | }
91 | },
92 | fetchByName : {
93 | sql : 'SELECT * FROM CONNECTIONS WHERE name = $1',
94 | params : function(record) {
95 | return [record.name];
96 | },
97 | failureMessage : function(e) {
98 | const status = 'E';
99 | let message = 'Failed to Select connection ' + e;
100 |
101 | return {status:status,message:message};
102 | }
103 | },
104 | fetchById : {
105 | sql : 'SELECT * FROM CONNECTIONS WHERE id = $1',
106 | params : function(record) {
107 | return [record.id];
108 | },
109 | failureMessage : function(e) {
110 | const status = 'E';
111 | let message = 'Failed to Select connection ' + e;
112 |
113 | return {status:status,message:message};
114 | }
115 | }
116 | }
117 |
118 |
119 | const validate = async function(record, mode, custom) {
120 | let status = "S";
121 | let message = "OK";
122 | const model = utils.getModelMetadata(modelName);
123 | const newRecord = utils.handleDefaults(model,record,mode);
124 | let dbRecord = {};
125 |
126 | // if (mode === "U" || mode === "D") {
127 | // // check the id information first
128 | // const existCount = await utils.checkId(modelName,record["id"]);
129 | // if (existCount === 0) {
130 | // status = 'E';
131 | // message = 'No Data found for column [id]';
132 | // return {status: status , message:message};
133 | // }
134 | // }
135 |
136 | if (mode === "U" || mode === "D") {
137 | const dbRecordResponse = await fetchById({id: record["id"]});
138 | if (!!dbRecordResponse && dbRecordResponse.length > 0 ) {
139 | dbRecord = dbRecordResponse[0];
140 | } else {
141 | status = 'E';
142 | message = 'No Data found for column [id]';
143 | return {status: status , message:message};
144 | }
145 | }
146 |
147 | switch(mode) {
148 | case 'I' :
149 | if (!!record) {
150 | const validateRequiredFields = utils.validateRequiredColumns(model,mode,newRecord);
151 | if (validateRequiredFields.status === "E") {
152 | return {status: validateRequiredFields.status , message: validateRequiredFields.message};
153 | }
154 |
155 | let validateDatatypes = utils.validateDatatypes(model,mode,newRecord);
156 |
157 | if (validateDatatypes.status === "E") {
158 | return {status: validateDatatypes.status , message: validateDatatypes.message};
159 | }
160 |
161 | const validateConstraints = await utils.validateConstraints(model,mode,newRecord);
162 |
163 | if (validateConstraints.status === "E") {
164 | return {status: validateConstraints.status , message: validateConstraints.message};
165 | }
166 |
167 | const validateTableConstraints = await utils.validateTableConstraints(model,mode,newRecord);
168 |
169 | if (validateTableConstraints.status === "E") {
170 | return {status: validateTableConstraints.status , message: validateTableConstraints.message};
171 | }
172 |
173 | // write your custom logic here
174 | if (custom) {
175 | const checkDB = await utils.validateConnection(newRecord);
176 |
177 | if (checkDB.status === "E") {
178 | return {status: checkDB.status , message: checkDB.message};
179 | }
180 | newRecord["password"] = utils.encryptByKey(newRecord["password"],'connection');
181 | }
182 |
183 | return {status: status , message:message, record: newRecord};
184 |
185 | } else {
186 | status = 'E';
187 | message = 'Missing Record Information';
188 | return {status: status , message:message};
189 | }
190 | case 'U':
191 | if (!!record) {
192 | const validateRequiredFields = utils.validateRequiredColumns(model,mode,newRecord);
193 |
194 | if (validateRequiredFields.status === "E") {
195 | return {status: validateRequiredFields.status , message: validateRequiredFields.message};
196 | }
197 |
198 | const validateDatatypes = utils.validateDatatypes(model,mode,newRecord);
199 |
200 | if (validateDatatypes.status === "E") {
201 | return {status: validateDatatypes.status , message: validateDatatypes.message};
202 | }
203 |
204 | const validateConstraints = await utils.validateConstraints(model,mode,newRecord);
205 |
206 | if (validateConstraints.status === "E") {
207 | return {status: validateConstraints.status , message: validateConstraints.message};
208 | }
209 |
210 | const validateTableConstraints = await utils.validateTableConstraints(model,mode,newRecord);
211 |
212 | if (validateTableConstraints.status === "E") {
213 | return {status: validateTableConstraints.status , message: validateTableConstraints.message};
214 | }
215 |
216 | // write your custom logic here
217 | if (custom) {
218 |
219 | const passwd = newRecord["password"];
220 |
221 | if (dbRecord["password"] === passwd) {
222 | newRecord["password"] = utils.decryptByKey(passwd,'connection');
223 | }
224 |
225 | const checkDB = await utils.validateConnection(newRecord);
226 |
227 | if (checkDB.status === "E") {
228 | return {status: checkDB.status , message: checkDB.message};
229 | }
230 | newRecord["password"] = utils.encrypt(newRecord["password"]);
231 | }
232 |
233 | return {status: status , message:message, record: newRecord};
234 |
235 |
236 | } else {
237 | status = 'E';
238 | message = 'Missing Record Information';
239 | return {status: status , message:message};
240 | }
241 | case 'D':
242 | // write your custom logic here
243 | return {status: status , message:message};
244 | }
245 |
246 |
247 | }
248 |
249 |
250 | const insert = async function(record,pool) {
251 |
252 | const metaObj = metadata["insert"];
253 | try {
254 |
255 | const sql = metaObj.sql;
256 | const params = metaObj.params(record);
257 |
258 | return await utils.callSQL(sql,params,pool);
259 |
260 | } catch (e) {
261 | return metaObj.failureMessage(e);
262 | }
263 |
264 | }
265 |
266 | const update = async function(record) {
267 |
268 | const metaObj = metadata["update"];
269 | try {
270 | const sql = metaObj.sql;
271 | const params = metaObj.params(record);
272 |
273 | return await utils.callSQL(sql,params);
274 |
275 | } catch (e) {
276 | return metaObj.failureMessage(e);
277 | }
278 | }
279 |
280 | const deleteRecord = async function(record) {
281 |
282 | const metaObj = metadata["delete"];
283 |
284 | try {
285 | const sql = metaObj.sql;
286 | const params = metaObj.params(record);
287 |
288 | return await utils.callSQL(sql,params);
289 |
290 | } catch (e) {
291 | return metaObj.failureMessage(e);
292 | }
293 | }
294 |
295 | const fetchAll = async function() {
296 |
297 | const metaObj = metadata["fetch"];
298 | try {
299 | const sql = metaObj.sql;
300 | const params = metaObj.params();
301 | return await utils.getSQLResults(sql,params);
302 |
303 | } catch (e) {
304 | return metaObj.failureMessage();
305 | }
306 | }
307 |
308 | const fetchByName = async function(record) {
309 |
310 | const metaObj = metadata["fetchByName"];
311 | try {
312 | const sql = metaObj.sql;
313 | const params = metaObj.params(record);
314 | return await utils.getSQLResults(sql,params);
315 |
316 | } catch (e) {
317 | return metaObj.failureMessage();
318 | }
319 | }
320 |
321 | const fetchById = async function(record) {
322 |
323 | const metaObj = metadata["fetchById"];
324 | try {
325 | const sql = metaObj.sql;
326 | const params = metaObj.params(record);
327 | return await utils.getSQLResults(sql,params);
328 |
329 | } catch (e) {
330 | return metaObj.failureMessage();
331 | }
332 | }
333 |
334 | module.exports = {
335 | validate: validate,
336 | insert: insert,
337 | update: update,
338 | delete: deleteRecord,
339 | fetchAll: fetchAll,
340 | fetchById: fetchById,
341 | metadata: metadata,
342 | modelName: modelName,
343 | fetchByName: fetchByName
344 | }
--------------------------------------------------------------------------------
/admin/core/models/Function.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const utils = require('../../Utils');
21 | const modelName = "functions";
22 | const metadata = {
23 | insert : {
24 | sql : 'INSERT INTO FUNCTIONS (id,name,connection_id,db_method,ref_source_id,created,updated) VALUES ($1,$2,$3,$4,$5,$6,$7)',
25 | params : function(record) {
26 | let uuid = "";
27 |
28 | if (!record["id"]) {
29 | uuid = utils.getUUID();
30 | } else {
31 | uuid = record["id"];
32 | }
33 |
34 | return [uuid,record.name,record.connection_id,record.db_method,record.ref_source_id,record.created,record.updated];
35 | },
36 | failureMessage : function(e) {
37 | const status = 'E';
38 | let message = 'Failed to create Function ' + e;
39 |
40 | return {status:status,message:message};
41 | }
42 | },
43 | update : {
44 | sql : 'UPDATE FUNCTIONS SET name = $1 , connection_id = $2 , db_method = $3 , updated = $4 WHERE id = $5',
45 | params : function(record) {
46 |
47 | const d = new Date();
48 | return [record.name
49 | , record.connection_id
50 | , record.db_method
51 | , d
52 | , record.id];
53 | },
54 | failureMessage : function(e) {
55 | const status = 'E';
56 | let message = 'Failed to update Function ' + e;
57 |
58 | return {status:status,message:message};
59 | }
60 |
61 | },
62 | delete : {
63 | sql : 'DELETE FROM FUNCTIONS WHERE id = $1',
64 | params : function(record) {
65 | return [record.id];
66 | },
67 | failureMessage : function(e) {
68 | const status = 'E';
69 | let message = 'Failed to delete function ' + e;
70 |
71 | return {status:status,message:message};
72 | }
73 | },
74 | fetch : {
75 | sql : 'SELECT a.*,b.name as connection_name FROM FUNCTIONS a, CONNECTIONS b WHERE a.connection_id = b.id',
76 | params : function(record) {
77 | return [];
78 | },
79 | failureMessage : function(e) {
80 | return {};
81 | }
82 | },
83 | fetchByName: {
84 | sql : 'SELECT a.* FROM FUNCTIONS a WHERE name = $1',
85 | params : function(record) {
86 | return [record.name];
87 | },
88 | failureMessage : function(e) {
89 | const status = 'E';
90 | let message = 'Failed to delete function ' + e;
91 | return {status:status,message:message};
92 | }
93 | }
94 | }
95 |
96 |
97 | const validate = async function(record, mode, custom, pool) {
98 | let status = "S";
99 | let message = "OK";
100 | const model = utils.getModelMetadata(modelName);
101 | const newRecord = utils.handleDefaults(model,record,mode);
102 |
103 | if (mode === "U" || mode === "D") {
104 | // check the id information first
105 | const existCount = await utils.checkId(modelName,record["id"]);
106 | if (existCount === 0) {
107 | status = 'E';
108 | message = 'No Data found for column [id]';
109 | return {status: status , message:message};
110 | }
111 | }
112 |
113 | switch(mode) {
114 | case 'I':
115 | if (!!record) {
116 | const validateRequiredFields = utils.validateRequiredColumns(model,mode,newRecord);
117 | if (validateRequiredFields.status === "E") {
118 | return {status: validateRequiredFields.status , message: validateRequiredFields.message};
119 | }
120 | let validateDatatypes = utils.validateDatatypes(model,mode,newRecord);
121 |
122 | if (validateDatatypes.status === "E") {
123 | return {status: validateDatatypes.status , message: validateDatatypes.message};
124 | }
125 |
126 | const validateConstraints = await utils.validateConstraints(model,mode,newRecord,pool);
127 |
128 | if (validateConstraints.status === "E") {
129 | return {status: validateConstraints.status , message: validateConstraints.message};
130 | }
131 |
132 | const validateTableConstraints = await utils.validateTableConstraints(model,mode,newRecord,pool);
133 |
134 | if (validateTableConstraints.status === "E") {
135 | return {status: validateTableConstraints.status , message: validateTableConstraints.message};
136 | }
137 |
138 | // write your custom logic here
139 | if (custom) {
140 | const checkFunction = await utils.validateFunction(record["connection_id"], record["db_method"]);
141 | if (checkFunction.status === "E") {
142 | return {status: checkFunction.status , message: checkFunction.message};
143 | }
144 | }
145 |
146 | return {status: status , message:message, record: newRecord};
147 |
148 |
149 | } else {
150 | status = 'E';
151 | message = 'Missing Record Information';
152 | return {status: status , message:message};
153 | }
154 | case 'U':
155 | if (!!record) {
156 | const validateRequiredFields = utils.validateRequiredColumns(model,mode,newRecord);
157 | if (validateRequiredFields.status === "E") {
158 | return {status: validateRequiredFields.status , message: validateRequiredFields.message};
159 | }
160 |
161 | const validateDatatypes = utils.validateDatatypes(model,mode,newRecord);
162 |
163 | if (validateDatatypes.status === "E") {
164 | return {status: validateDatatypes.status , message: validateDatatypes.message};
165 | }
166 |
167 | const validateConstraints = await utils.validateConstraints(model,mode,newRecord);
168 |
169 | if (validateConstraints.status === "E") {
170 | return {status: validateConstraints.status , message: validateConstraints.message};
171 | }
172 |
173 | const validateTableConstraints = await utils.validateTableConstraints(model,mode,newRecord,pool);
174 |
175 | if (validateTableConstraints.status === "E") {
176 | return {status: validateTableConstraints.status , message: validateTableConstraints.message};
177 | }
178 |
179 | // write your custom logic heres
180 | if (custom) {
181 | const checkFunction = await utils.validateFunction(record["connection_id"],record["db_method"]);
182 | if (checkFunction.status === "E") {
183 | return {status: checkFunction.status , message: checkFunction.message};
184 | }
185 | }
186 |
187 | return {status: status , message:message, record: newRecord};
188 |
189 |
190 | } else {
191 | status = 'E';
192 | message = 'Missing Record Information';
193 | return {status: status , message:message};
194 | }
195 | case 'D':
196 | // write your custom logic here
197 | return {status: status , message:message};
198 | }
199 |
200 |
201 | }
202 |
203 |
204 | const insert = async function(record, pool) {
205 |
206 | const metaObj = metadata["insert"];
207 | try {
208 | const sql = metaObj.sql;
209 | const params = metaObj.params(record);
210 |
211 | return await utils.callSQL(sql,params, pool);
212 |
213 | } catch (e) {
214 | return metaObj.failureMessage(e);
215 | }
216 |
217 | }
218 |
219 | const update = async function(record) {
220 |
221 | const metaObj = metadata["update"];
222 | try {
223 | const sql = metaObj.sql;
224 | const params = metaObj.params(record);
225 |
226 | return await utils.callSQL(sql,params);
227 |
228 | } catch (e) {
229 | return metaObj.failureMessage(e);
230 | }
231 | }
232 |
233 | const deleteRecord = async function(record) {
234 |
235 | const metaObj = metadata["delete"];
236 | console.log("Deleting Recrod");
237 |
238 | try {
239 | const sql = metaObj.sql;
240 | const params = metaObj.params(record);
241 |
242 | return await utils.callSQL(sql,params);
243 |
244 | } catch (e) {
245 | return metaObj.failureMessage(e);
246 | }
247 | }
248 |
249 | const fetchAll = async function() {
250 |
251 | const metaObj = metadata["fetch"];
252 | try {
253 | const sql = metaObj.sql;
254 | const params = metaObj.params();
255 | return await utils.getSQLResults(sql,params);
256 |
257 | } catch (e) {
258 | return metaObj.failureMessage();
259 | }
260 | }
261 |
262 | const fetchByName = async function(record) {
263 |
264 | const metaObj = metadata["fetchByName"];
265 | try {
266 | const sql = metaObj.sql;
267 | const params = metaObj.params(record);
268 | return await utils.getSQLResults(sql,params);
269 |
270 | } catch (e) {
271 | return metaObj.failureMessage();
272 | }
273 | }
274 |
275 | module.exports = {
276 | validate: validate,
277 | insert: insert,
278 | update: update,
279 | delete: deleteRecord,
280 | fetchAll: fetchAll,
281 | fetchByName: fetchByName
282 | }
--------------------------------------------------------------------------------
/admin/core/models/Route.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const utils = require('../../Utils');
21 | const modelName = "routes";
22 | const metadata = {
23 | insert : {
24 | sql : 'INSERT INTO ROUTES (id,name,function_id,route_method,enabled_flag,route_url,description,sample_request,sample_response,ref_source_id,created,updated) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)',
25 | params : function(record) {
26 | let uuid = "";
27 |
28 | if (!record["id"]) {
29 | uuid = utils.getUUID();
30 | } else {
31 | uuid = record["id"];
32 | }
33 |
34 | return [uuid,record.name,record.function_id,record.route_method,'Y',record.route_url,record.description,record.sample_request,record.sample_response,record.ref_source_id,record.created,record.updated];
35 | },
36 | failureMessage : function(e) {
37 | const status = 'E';
38 | let message = 'Failed to create Route ' + e;
39 |
40 | return {status:status,message:message};
41 | }
42 | },
43 | update : {
44 | sql : 'UPDATE ROUTES SET name = $1 , function_id = $2 , route_method = $3 , enabled_flag = $4, route_url = $5,description = $6,sample_request = $7,sample_response = $8, updated = $9 WHERE id = $10',
45 | params : function(record) {
46 |
47 | const d = new Date();
48 | return [record.name
49 | , record.function_id
50 | , record.route_method
51 | , record.enabled_flag
52 | , record.route_url
53 | , record.description
54 | , record.sample_request
55 | , record.sample_response
56 | , d
57 | , record.id];
58 | },
59 | failureMessage : function(e) {
60 | const status = 'E';
61 | let message = 'Failed to update Route ' + e;
62 |
63 | return {status:status,message:message};
64 | }
65 |
66 | },
67 | delete : {
68 | sql : 'DELETE FROM ROUTES WHERE id = $1',
69 | params : function(record) {
70 | return [record.id];
71 | },
72 | failureMessage : function(e) {
73 | const status = 'E';
74 | let message = 'Failed to delete routes ' + e;
75 |
76 | return {status:status,message:message};
77 | }
78 | },
79 | fetch : {
80 | sql : 'SELECT a.* , b.name as function_name, c.name as connection_name FROM routes a , functions b, connections c where a.function_id = b.id and c.id = b.connection_id',
81 | params : function(record) {
82 | return [];
83 | },
84 | failureMessage : function(e) {
85 | return {};
86 | }
87 | },
88 | fetchById : {
89 | sql : 'SELECT a.* , b.name as function_name, c.name as connection_name FROM routes a , functions b, connections c ' +
90 | 'where a.function_id = b.id and c.id = b.connection_id and a.id = $1',
91 | params : function(id) {
92 | return [id];
93 | },
94 | failureMessage : function(e) {
95 | return {};
96 | }
97 | }
98 | }
99 |
100 |
101 | const validate = async function(record, mode, custom,pool) {
102 | let status = "S";
103 | let message = "OK";
104 | const model = utils.getModelMetadata(modelName);
105 | const newRecord = utils.handleDefaults(model,record,mode);
106 |
107 | if (mode === "U" || mode === "D") {
108 | // check the id information first
109 | const existCount = await utils.checkId(modelName,record["id"]);
110 | if (existCount === 0) {
111 | status = 'E';
112 | message = 'No Data found for column [id]';
113 | return {status: status , message:message};
114 | }
115 |
116 | }
117 | switch(mode) {
118 | case 'I' :
119 | if (!!record) {
120 | const validateRequiredFields = utils.validateRequiredColumns(model,mode,newRecord);
121 | if (validateRequiredFields.status === "E") {
122 | return {status: validateRequiredFields.status , message: validateRequiredFields.message};
123 | }
124 |
125 | let validateDatatypes = utils.validateDatatypes(model,mode,newRecord);
126 |
127 | if (validateDatatypes.status === "E") {
128 | return {status: validateDatatypes.status , message: validateDatatypes.message};
129 | }
130 |
131 | const validateConstraints = await utils.validateConstraints(model,mode,newRecord,pool);
132 |
133 | if (validateConstraints.status === "E") {
134 | return {status: validateConstraints.status , message: validateConstraints.message};
135 | }
136 |
137 | const validateTableConstraints = await utils.validateTableConstraints(model,mode,newRecord,pool);
138 |
139 | if (validateTableConstraints.status === "E") {
140 | return {status: validateTableConstraints.status , message: validateTableConstraints.message};
141 | }
142 |
143 | // write your custom logic here
144 | if (custom) {
145 |
146 | }
147 |
148 | return {status: status , message:message, record: newRecord};
149 |
150 |
151 | } else {
152 | status = 'E';
153 | message = 'Missing Record Information';
154 | return {status: status , message:message};
155 | }
156 | case 'U':
157 | if (!!record) {
158 | const validateRequiredFields = utils.validateRequiredColumns(model,mode,newRecord);
159 |
160 | if (validateRequiredFields.status === "E") {
161 | return {status: validateRequiredFields.status , message: validateRequiredFields.message};
162 | }
163 |
164 | const validateDatatypes = utils.validateDatatypes(model,mode,newRecord);
165 |
166 | if (validateDatatypes.status === "E") {
167 | return {status: validateDatatypes.status , message: validateDatatypes.message};
168 | }
169 |
170 | const validateConstraints = await utils.validateConstraints(model,mode,newRecord,pool);
171 |
172 | if (validateConstraints.status === "E") {
173 | return {status: validateConstraints.status , message: validateConstraints.message};
174 | }
175 |
176 | const validateTableConstraints = await utils.validateTableConstraints(model,mode,newRecord,pool);
177 |
178 | if (validateTableConstraints.status === "E") {
179 | return {status: validateTableConstraints.status , message: validateTableConstraints.message};
180 | }
181 |
182 | // write your custom logic here
183 | if (custom) {
184 |
185 | }
186 |
187 | return {status: status , message:message, record: newRecord};
188 |
189 | } else {
190 | status = 'E';
191 | message = 'Missing Record Information';
192 | return {status: status , message:message};
193 | }
194 | case 'D':
195 | // write your custom logic here
196 | return {status: status , message:message};
197 | }
198 |
199 | }
200 |
201 |
202 | const insert = async function(record, pool) {
203 |
204 | const metaObj = metadata["insert"];
205 | try {
206 | const sql = metaObj.sql;
207 | const params = metaObj.params(record);
208 |
209 | return await utils.callSQL(sql,params, pool);
210 |
211 | } catch (e) {
212 | return metaObj.failureMessage(e);
213 | }
214 |
215 | }
216 |
217 | const update = async function(record) {
218 |
219 | const metaObj = metadata["update"];
220 | try {
221 | const sql = metaObj.sql;
222 | const params = metaObj.params(record);
223 |
224 | return await utils.callSQL(sql,params);
225 |
226 | } catch (e) {
227 | return metaObj.failureMessage(e);
228 | }
229 | }
230 |
231 | const deleteRecord = async function(record) {
232 |
233 | const metaObj = metadata["delete"];
234 |
235 | try {
236 | const sql = metaObj.sql;
237 | const params = metaObj.params(record);
238 |
239 | return await utils.callSQL(sql,params);
240 |
241 | } catch (e) {
242 | return metaObj.failureMessage(e);
243 | }
244 | }
245 |
246 | const fetchAll = async function() {
247 |
248 | const metaObj = metadata["fetch"];
249 | try {
250 | const sql = metaObj.sql;
251 | const params = metaObj.params();
252 | return await utils.getSQLResults(sql,params);
253 |
254 | } catch (e) {
255 | return metaObj.failureMessage();
256 | }
257 | }
258 |
259 | const fetchById = async function(id) {
260 |
261 | const metaObj = metadata["fetchById"];
262 | try {
263 | const sql = metaObj.sql;
264 | const params = metaObj.params(id);
265 | return await utils.getSQLResults(sql,params);
266 |
267 | } catch (e) {
268 | return metaObj.failureMessage();
269 | }
270 | }
271 |
272 |
273 | module.exports = {
274 | validate: validate,
275 | insert: insert,
276 | update: update,
277 | delete: deleteRecord,
278 | fetchAll: fetchAll,
279 | fetchById: fetchById
280 | }
281 |
--------------------------------------------------------------------------------
/admin/core/models/User.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const utils = require('../../Utils');
21 | const modelName = "users";
22 | const metadata = {
23 | insert : {
24 | sql : 'INSERT INTO USERS (id,username,first_name,last_name,password,ref_user_id,enabled_flag,created,updated) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)',
25 | params : function(record) {
26 | let uuid = "";
27 |
28 | if (!record["id"]) {
29 | uuid = utils.getUUID();
30 | } else {
31 | uuid = record["id"];
32 | }
33 |
34 | const passwordHash = utils.encryptPassword(record.password);
35 |
36 | return [uuid,record.username,record.first_name,record.last_name,passwordHash,record.ref_user_id, 'Y', record.created,record.updated];
37 | },
38 | failureMessage : function(e) {
39 | const status = 'E';
40 | let message = 'Failed to create User ' + e;
41 |
42 | return {status:status,message:message};
43 | }
44 | },
45 | update : {
46 | sql : 'UPDATE USERS SET first_name = $1 , last_name = $2 , updated = $3 WHERE id = $4',
47 | params : function(record) {
48 |
49 | const d = new Date();
50 | return [record.first_name
51 | , record.last_name
52 | , d
53 | , record.id];
54 | },
55 | failureMessage : function(e) {
56 | const status = 'E';
57 | let message = 'Failed to update User ' + e;
58 |
59 | return {status:status,message:message};
60 | }
61 |
62 | },
63 | updatePassword : {
64 | sql : 'UPDATE USERS SET password = $1 , updated = $2 WHERE id = $3',
65 | params : function(record) {
66 |
67 | const d = new Date();
68 | return [record.password
69 | , d
70 | , record.id];
71 | },
72 | failureMessage : function(e) {
73 | const status = 'E';
74 | let message = 'Failed to update User PAssword ' + e;
75 |
76 | return {status:status,message:message};
77 | }
78 |
79 | },
80 | updateEnabledFlag : {
81 | sql : 'UPDATE USERS SET enabled_flag = $1 , updated = $2 WHERE id = $3',
82 | params : function(record) {
83 |
84 | const d = new Date();
85 | return [record.enabled_flag
86 | , d
87 | , record.id];
88 | },
89 | failureMessage : function(e) {
90 | const status = 'E';
91 | let message = 'Failed to update User PAssword ' + e;
92 |
93 | return {status:status,message:message};
94 | }
95 | },
96 | delete : {
97 | sql : 'DELETE FROM USERS WHERE id = $1',
98 | params : function(record) {
99 | return [record.id];
100 | },
101 | failureMessage : function(e) {
102 | const status = 'E';
103 | let message = 'Failed to delete function ' + e;
104 |
105 | return {status:status,message:message};
106 | }
107 | },
108 | fetch : {
109 | sql : 'SELECT a.* FROM USERS a',
110 | params : function(record) {
111 | return [];
112 | },
113 | failureMessage : function(e) {
114 | return {};
115 | }
116 | },
117 | fetchById : {
118 | sql : 'SELECT a.* FROM USERS a WHERE a.id = $1',
119 | params : function(record) {
120 | return [record.id];
121 | },
122 | failureMessage : function(e) {
123 | return {};
124 | }
125 | },
126 | fetchByIdUser : {
127 | sql : 'SELECT id , username , first_name , last_name FROM USERS a WHERE a.id = $1',
128 | params : function(record) {
129 | return [record.id];
130 | },
131 | failureMessage : function(e) {
132 | return {};
133 | }
134 | },
135 | fetchByUsername : {
136 | sql : 'SELECT a.* FROM USERS a WHERE a.username = $1',
137 | params : function(record) {
138 | return [record.username];
139 | },
140 | failureMessage : function(e) {
141 | return {};
142 | }
143 | },
144 | insertArchive: {
145 | sql : 'INSERT INTO deleted_users (id , username , first_name , last_name , created , cwho) VALUES ($1,$2,$3,$4,$5,$6)',
146 | params : function(record) {
147 | let uuid = "";
148 |
149 | if (!record["id"]) {
150 | uuid = utils.getUUID();
151 | } else {
152 | uuid = record["id"];
153 | }
154 |
155 | const d = new Date();
156 |
157 | if (!record["created_by"]) {
158 | record["created_by"] = 0;
159 | }
160 |
161 | return [uuid,record.username,record.first_name,record.last_name,d,record.cwho];
162 | },
163 | failureMessage : function(e) {
164 | const status = 'E';
165 | let message = 'Failed to create User Archive ' + e;
166 |
167 | return {status:status,message:message};
168 | }
169 | },
170 | insertToken: {
171 | sql : 'INSERT INTO tokens( token , start_time , user_id , timeout_time , created , updated ) VALUES ($1, $2, $3, $4, $5, $6)',
172 | params : function(record) {
173 | const d = new Date();
174 | let timeoutTime = new Date();
175 | timeoutTime.setMinutes(timeoutTime.getMinutes() + 60);
176 | return [record.token,d, record.user_id, timeoutTime, d, d];
177 | },
178 | failureMessage : function(e) {
179 | const status = 'E';
180 | let message = 'Failed to create Token record ' + e;
181 |
182 | return {status:status,message:message};
183 | }
184 | },
185 | fetchToken : {
186 | sql : 'SELECT a.* FROM TOKENS a WHERE a.token = $1',
187 | params : function(record) {
188 | return [record.token];
189 | },
190 | failureMessage : function(e) {
191 | return {};
192 | }
193 | },
194 | updateToken: {
195 | sql : 'UPDATE tokens SET timeout_time = $1 , updated = $2 WHERE token = $3',
196 | params : function(record) {
197 | const d = new Date();
198 | let timeoutTime = new Date();
199 | timeoutTime.setMinutes(timeoutTime.getMinutes() + 60);
200 | return [timeoutTime,d, record.token];
201 | },
202 | failureMessage : function(e) {
203 | const status = 'E';
204 | let message = 'Failed to create Token record ' + e;
205 |
206 | return {status:status,message:message};
207 | }
208 | },
209 | validateSession: {
210 | sql : "SELECT validate_session($1) as result",
211 | params : function(record) {
212 | return [record.token];
213 | },
214 | failureMessage : function(e) {
215 | const status = 'E';
216 | let message = 'Invalid Session Information ' + e;
217 |
218 | return {status:status,message:message};
219 | }
220 | }
221 | }
222 |
223 |
224 | const validate = async function(record, mode, custom, pool) {
225 | let status = "S";
226 | let message = "OK";
227 | const model = utils.getModelMetadata(modelName);
228 | const newRecord = utils.handleDefaults(model,record,mode);
229 |
230 | if (mode === "U" || mode === "D") {
231 | // check the id information first
232 | const existCount = await utils.checkId(modelName,record["id"]);
233 | if (existCount === 0) {
234 | status = 'E';
235 | message = 'No Data found for column [id]';
236 | return {status: status , message:message};
237 | }
238 |
239 | }
240 | switch(mode) {
241 | case 'I' :
242 | if (!!record) {
243 | const validateRequiredFields = utils.validateRequiredColumns(model,mode,newRecord);
244 |
245 | if (validateRequiredFields.status === "E") {
246 | return {status: validateRequiredFields.status , message: validateRequiredFields.message};
247 | }
248 | let validateDatatypes = utils.validateDatatypes(model,mode,newRecord);
249 |
250 | if (validateDatatypes.status === "E") {
251 | return {status: validateDatatypes.status , message: validateDatatypes.message};
252 | }
253 |
254 | const validateConstraints = await utils.validateConstraints(model,mode,newRecord,pool);
255 |
256 | if (validateConstraints.status === "E") {
257 | return {status: validateConstraints.status , message: validateConstraints.message};
258 | }
259 |
260 | const validateTableConstraints = await utils.validateTableConstraints(model,mode,newRecord,pool);
261 |
262 | if (validateTableConstraints.status === "E") {
263 | return {status: validateTableConstraints.status , message: validateTableConstraints.message};
264 | }
265 |
266 | // write your custom logic here
267 | if (custom) {
268 |
269 | }
270 |
271 | return {status: status , message:message, record: newRecord};
272 |
273 |
274 | } else {
275 | status = 'E';
276 | message = 'Missing Record Information';
277 | return {status: status , message:message};
278 | }
279 | case 'U':
280 | if (!!record) {
281 | const validateRequiredFields = utils.validateRequiredColumns(model,mode,newRecord);
282 | if (validateRequiredFields.status === "E") {
283 | return {status: validateRequiredFields.status , message: validateRequiredFields.message};
284 | }
285 |
286 | const validateDatatypes = utils.validateDatatypes(model,mode,newRecord);
287 |
288 | if (validateDatatypes.status === "E") {
289 | return {status: validateDatatypes.status , message: validateDatatypes.message};
290 | }
291 |
292 | const validateConstraints = await utils.validateConstraints(model,mode,newRecord);
293 |
294 | if (validateConstraints.status === "E") {
295 | return {status: validateConstraints.status , message: validateConstraints.message};
296 | }
297 |
298 | const validateTableConstraints = await utils.validateTableConstraints(model,mode,newRecord,pool);
299 |
300 | if (validateTableConstraints.status === "E") {
301 | return {status: validateTableConstraints.status , message: validateTableConstraints.message};
302 | }
303 |
304 | // write your custom logic here
305 | if (custom) {
306 |
307 | }
308 |
309 | return {status: status , message:message, record: newRecord};
310 |
311 |
312 | } else {
313 | status = 'E';
314 | message = 'Missing Record Information';
315 | return {status: status , message:message};
316 | }
317 | case 'D':
318 | // write your custom logic here
319 | return {status: status , message:message};
320 | }
321 |
322 |
323 | }
324 |
325 |
326 | const insert = async function(record) {
327 |
328 | const metaObj = metadata["insert"];
329 | try {
330 | const sql = metaObj.sql;
331 | const params = metaObj.params(record);
332 |
333 | return await utils.callSQL(sql,params);
334 |
335 | } catch (e) {
336 | return metaObj.failureMessage(e);
337 | }
338 |
339 | }
340 |
341 | const insertArchive = async function(record) {
342 |
343 | const metaObj = metadata["insertArchive"];
344 | try {
345 | const sql = metaObj.sql;
346 | const params = metaObj.params(record);
347 |
348 | return await utils.callSQL(sql,params);
349 |
350 | } catch (e) {
351 | return metaObj.failureMessage(e);
352 | }
353 |
354 | }
355 |
356 | const insertToken = async function(record) {
357 |
358 | const metaObj = metadata["insertToken"];
359 | try {
360 | const sql = metaObj.sql;
361 | const params = metaObj.params(record);
362 |
363 | return await utils.callSQL(sql,params);
364 |
365 | } catch (e) {
366 | return metaObj.failureMessage(e);
367 | }
368 |
369 | }
370 |
371 | const update = async function(record) {
372 |
373 | const metaObj = metadata["update"];
374 | try {
375 | const sql = metaObj.sql;
376 | const params = metaObj.params(record);
377 |
378 | return await utils.callSQL(sql,params);
379 |
380 | } catch (e) {
381 | return metaObj.failureMessage(e);
382 | }
383 | }
384 |
385 | const updatePassword = async function(record) {
386 |
387 | const metaObj = metadata["updatePassword"];
388 | try {
389 | const sql = metaObj.sql;
390 |
391 | const params = metaObj.params(record);
392 |
393 | return await utils.callSQL(sql,params);
394 |
395 | } catch (e) {
396 | return metaObj.failureMessage(e);
397 | }
398 | }
399 |
400 |
401 | const updateEnabledFlag = async function(record) {
402 |
403 | const metaObj = metadata["updateEnabledFlag"];
404 | try {
405 | const sql = metaObj.sql;
406 |
407 | const params = metaObj.params(record);
408 |
409 | return await utils.callSQL(sql,params);
410 |
411 | } catch (e) {
412 | return metaObj.failureMessage(e);
413 | }
414 | }
415 | const deleteRecord = async function(record) {
416 |
417 | const metaObj = metadata["delete"];
418 |
419 | try {
420 | const sql = metaObj.sql;
421 | const params = metaObj.params(record);
422 |
423 | return await utils.callSQL(sql,params);
424 |
425 | } catch (e) {
426 | return metaObj.failureMessage(e);
427 | }
428 | }
429 |
430 | const fetchAll = async function() {
431 |
432 | const metaObj = metadata["fetch"];
433 | try {
434 | const sql = metaObj.sql;
435 | const params = metaObj.params();
436 | return await utils.getSQLResults(sql,params);
437 |
438 | } catch (e) {
439 | return metaObj.failureMessage();
440 | }
441 | }
442 |
443 | const fetchByUsername = async function(username) {
444 |
445 | const metaObj = metadata["fetchByUsername"];
446 | try {
447 | const sql = metaObj.sql;
448 | const params = metaObj.params({username: username});
449 | return await utils.getSQLResultswithStatus(sql,params);
450 |
451 | } catch (e) {
452 | return metaObj.failureMessage();
453 | }
454 | }
455 |
456 |
457 |
458 | const fetchById = async function(id) {
459 |
460 | const metaObj = metadata["fetchById"];
461 | try {
462 | const sql = metaObj.sql;
463 | const params = metaObj.params({id: id});
464 | return await utils.getSQLResults(sql,params);
465 |
466 | } catch (e) {
467 | return metaObj.failureMessage();
468 | }
469 | }
470 |
471 |
472 | const fetchByIdUser = async function(id) {
473 |
474 | const metaObj = metadata["fetchByIdUser"];
475 | try {
476 | const sql = metaObj.sql;
477 | const params = metaObj.params({id: id});
478 | return await utils.getSQLResults(sql,params);
479 |
480 | } catch (e) {
481 | return metaObj.failureMessage();
482 | }
483 | }
484 |
485 | const fetchToken = async function(id) {
486 |
487 | const metaObj = metadata["fetchToken"];
488 | try {
489 | const sql = metaObj.sql;
490 | const params = metaObj.params({id: id});
491 | return await utils.getSQLResults(sql,params);
492 |
493 | } catch (e) {
494 | return metaObj.failureMessage();
495 | }
496 | }
497 | const validateSession = async function(record) {
498 |
499 | const metaObj = metadata["validateSession"];
500 | try {
501 | const sql = metaObj.sql;
502 | const params = metaObj.params(record);
503 | return await utils.getSQLResults(sql,params);
504 |
505 | } catch (e) {
506 | return metaObj.failureMessage();
507 | }
508 | }
509 |
510 | const updateToken = async function(record) {
511 |
512 | const metaObj = metadata["updateToken"];
513 | try {
514 | const sql = metaObj.sql;
515 |
516 | const params = metaObj.params(record);
517 |
518 | return await utils.callSQL(sql,params);
519 |
520 | } catch (e) {
521 | return metaObj.failureMessage(e);
522 | }
523 | }
524 |
525 |
526 | module.exports = {
527 | validate: validate,
528 | insert: insert,
529 | insertArchive: insertArchive,
530 | insertToken: insertToken,
531 | update: update,
532 | delete: deleteRecord,
533 | fetchAll: fetchAll,
534 | fetchById: fetchById,
535 | fetchByUsername: fetchByUsername,
536 | fetchToken: fetchToken,
537 | fetchByIdUser: fetchByIdUser,
538 | updatePassword: updatePassword,
539 | updateEnabledFlag: updateEnabledFlag,
540 | updateToken: updateToken,
541 | validateSession: validateSession
542 | }
--------------------------------------------------------------------------------
/admin/install/db/DB.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS CONNECTIONS
2 | ( id text NOT NULL
3 | , name text NOT NULL
4 | , host text NOT NULL
5 | , port integer NOT NULL
6 | , database text NOT NULL
7 | , username text NOT NULL
8 | , password text NOT NULL
9 | , ref_source_id text
10 | , config_flag text NOT NULL
11 | , created timestamp with time zone NOT NULL
12 | , created_by text
13 | , updated timestamp with time zone NOT NULL
14 | , updated_by text
15 | , UNIQUE (name)
16 | );
17 |
18 | CREATE TABLE IF NOT EXISTS FUNCTIONS
19 | ( id text NOT NULL
20 | , name text NOT NULL
21 | , connection_id text NOT NULL
22 | , db_method text NOT NULL
23 | , ref_source_id text
24 | , created timestamp with time zone NOT NULL
25 | , created_by text
26 | , updated timestamp with time zone NOT NULL
27 | , updated_by text
28 | , UNIQUE (name)
29 | );
30 |
31 | CREATE TABLE IF NOT EXISTS ROUTES
32 | ( id text NOT NULL
33 | , name text NOT NULL
34 | , function_id text NOT NULL
35 | , route_method text NOT NULL
36 | , route_url text NOT NULL
37 | , enabled_flag text NOT NULL
38 | , description text
39 | , sample_request text
40 | , sample_response text
41 | , ref_source_id text
42 | , created timestamp with time zone NOT NULL
43 | , created_by text
44 | , updated timestamp with time zone NOT NULL
45 | , updated_by text
46 | , UNIQUE (name)
47 | );
48 |
49 | CREATE TABLE IF NOT EXISTS USERS
50 | ( id text NOT NULL
51 | , username text NOT NULL
52 | , first_name text
53 | , last_name text
54 | , password text NOT NULL
55 | , ref_user_id text
56 | , enabled_flag text NOT NULL
57 | , created timestamp with time zone NOT NULL
58 | , created_by text
59 | , updated timestamp with time zone NOT NULL
60 | , updated_by text
61 | , UNIQUE (username)
62 | );
63 |
64 | CREATE TABLE IF NOT EXISTS DELETED_USERS
65 | ( id text NOT NULL
66 | , username text NOT NULL
67 | , first_name text
68 | , last_name text
69 | , created timestamp with time zone NOT NULL
70 | , created_by text
71 | , updated timestamp with time zone NOT NULL
72 | , updated_by text
73 | , UNIQUE (username)
74 | );
75 |
76 | CREATE TABLE IF NOT EXISTS tokens
77 | (
78 | token text NOT NULL
79 | , start_time timestamp with time zone NOT NULL
80 | , user_id text NOT NULL
81 | , timeout_time timestamp with time zone NOT NULL
82 | , created timestamp with time zone NOT NULL
83 | , created_by text
84 | , updated timestamp with time zone NOT NULL
85 | , updated_by text
86 | , UNIQUE (token)
87 | );
88 |
89 | CREATE TABLE IF NOT EXISTS applications
90 | (
91 | id text NOT NULL
92 | , name text NOT NULL
93 | , app_short_code text
94 | , created timestamp with time zone NOT NULL
95 | , created_by text
96 | , updated timestamp with time zone NOT NULL
97 | , updated_by text
98 | , UNIQUE (name)
99 | , UNIQUE (app_short_code)
100 | );
101 |
102 | CREATE TABLE IF NOT EXISTS current_version
103 | (
104 | created timestamp with time zone NOT NULL
105 | , version text NOT NULL
106 | );
--------------------------------------------------------------------------------
/admin/install/db/database.json:
--------------------------------------------------------------------------------
1 | {
2 | "connections" : {
3 | "name" : "connections",
4 | "overwrite" : false ,
5 | "columns" : {
6 | "name" : {
7 | "datatype" : "string",
8 | "datalength": -1,
9 | "constraints" : ["UNIQUE"],
10 | "validate" : { "I" : ["UNIQUE","REQUIRED"] , "U" : ["UNIQUE_EXCLUDE","REQUIRED"], "D" : []},
11 | "insertable" : true,
12 | "updatable" : true,
13 | "selectable" : true,
14 | "primary" : false
15 | },
16 | "id" : {
17 | "datatype" : "string",
18 | "datalength": -1,
19 | "constraints" : ["PRIMARY"],
20 | "validate" : { "I" : ["REQUIRED"] , "U" : ["EXISTS" , "REQUIRED"], "D" : ["EXISTS","REQUIRED"]},
21 | "insertable" : true,
22 | "updatable" : false,
23 | "selectable" : true,
24 | "default" : {"I" : {"value": "UUID" , "overwrite" : false } },
25 | "primary" : true
26 | },
27 | "host" : {
28 | "datatype" : "string",
29 | "datalength": -1,
30 | "constraints" : ["REQUIRED"],
31 | "validate" : { "I" : ["REQUIRED"] , "U" : ["REQUIRED"]},
32 | "insertable" : true,
33 | "updatable" : true,
34 | "selectable" : true,
35 | "primary" : false
36 | },
37 | "port" : {
38 | "datatype" : "number",
39 | "datalength": -1,
40 | "constraints" : ["REQUIRED"],
41 | "validate" : { "I" : ["REQUIRED","NUMBER"] , "U" : ["REQUIRED","NUMBER"]},
42 | "insertable" : true,
43 | "updatable" : true,
44 | "selectable" : true,
45 | "primary" : false
46 | },
47 | "database" : {
48 | "datatype" : "string",
49 | "datalength": -1,
50 | "constraints" : ["REQUIRED"],
51 | "validate" : { "I" : ["REQUIRED"] , "U" : ["REQUIRED"]},
52 | "insertable" : true,
53 | "updatable" : true,
54 | "selectable" : true,
55 | "primary" : false
56 | },
57 | "username" : {
58 | "datatype" : "string",
59 | "datalength": -1,
60 | "constraints" : ["REQUIRED"],
61 | "validate" : { "I" : ["REQUIRED"] , "U" : ["REQUIRED"]},
62 | "insertable" : true,
63 | "updatable" : true,
64 | "selectable" : true,
65 | "primary" : false
66 | },
67 | "password" : {
68 | "datatype" : "string",
69 | "datalength": -1,
70 | "constraints" : ["REQUIRED"],
71 | "validate" : { "I" : ["REQUIRED"] , "U" : ["REQUIRED"]},
72 | "insertable" : true,
73 | "updatable" : true,
74 | "selectable" : false,
75 | "primary" : false,
76 | "encrypt" : true
77 | },
78 | "ref_source_id" : {
79 | "datatype" : "string",
80 | "datalength": -1,
81 | "constraints" : [],
82 | "insertable" : true,
83 | "updatable" : true,
84 | "selectable" : true,
85 | "primary" : false
86 | },
87 | "config_flag" : {
88 | "datatype" : "string",
89 | "datalength": -1,
90 | "constraints" : [],
91 | "insertable" : true,
92 | "updatable" : true,
93 | "selectable" : true,
94 | "primary" : false
95 | },
96 | "created" : {
97 | "datatype" : "timestamp",
98 | "tz_enabled" : true,
99 | "datalength": -1,
100 | "constraints" : ["REQUIRED"],
101 | "validate" : { "I" : ["REQUIRED","DATE"]},
102 | "insertable" : true,
103 | "updatable" : false,
104 | "selectable" : false,
105 | "primary" : false,
106 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
107 | "encrypt" : false
108 | },
109 | "updated" : {
110 | "datatype" : "timestamp",
111 | "tz_enabled" : true,
112 | "datalength": -1,
113 | "constraints" : ["REQUIRED"],
114 | "validate" : { "I" : ["REQUIRED","DATE"] , "U" : ["REQUIRED","DATE"]},
115 | "insertable" : true,
116 | "updatable" : false,
117 | "selectable" : false,
118 | "primary" : false,
119 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
120 | "encrypt" : false
121 | }
122 | }
123 | },
124 | "functions" : {
125 | "name" : "functions",
126 | "overwrite" : false ,
127 | "columns" : {
128 | "name" : {
129 | "datatype" : "string",
130 | "datalength": -1,
131 | "constraints" : ["PRIMARY"],
132 | "validate" : { "I" : ["UNIQUE","REQUIRED"] , "U" : ["UNIQUE_EXCLUDE","REQUIRED"], "D" : []},
133 | "insertable" : true,
134 | "updatable" : true,
135 | "selectable" : true,
136 | "primary" : false
137 | },
138 | "id" : {
139 | "datatype" : "string",
140 | "datalength": -1,
141 | "constraints" : ["PRIMARY"],
142 | "validate" : { "I" : ["REQUIRED"] , "U" : ["EXISTS" , "REQUIRED"], "D" : ["EXISTS","REQUIRED"]},
143 | "insertable" : true,
144 | "updatable" : false,
145 | "selectable" : true,
146 | "default" : {"I" : {"value": "UUID" , "overwrite" : false } },
147 | "primary" : true
148 | },
149 | "connection_id" : {
150 | "datatype" : "string",
151 | "datalength": -1,
152 | "constraints" : ["PRIMARY","$REF.CONNECTIONS(ID)"],
153 | "validate" : { "I" : ["REQUIRED","$REF.CONNECTIONS-id,connection_id"] , "U" : ["REQUIRED","$REF.CONNECTIONS-id,connection_id"], "D" : []},
154 | "insertable" : true,
155 | "updatable" : true,
156 | "selectable" : true,
157 | "primary" : false
158 | },
159 | "db_method" : {
160 | "datatype" : "string",
161 | "datalength": -1,
162 | "constraints" : ["REQUIRED"],
163 | "validate" : { "I" : ["REQUIRED"] , "U" : ["REQUIRED"], "D" : []},
164 | "insertable" : true,
165 | "updatable" : false,
166 | "selectable" : true,
167 | "primary" : false
168 | },
169 | "ref_source_id" : {
170 | "datatype" : "string",
171 | "datalength": -1,
172 | "constraints" : [],
173 | "insertable" : true,
174 | "updatable" : true,
175 | "selectable" : true,
176 | "primary" : false
177 | },
178 | "created" : {
179 | "datatype" : "timestamp",
180 | "tz_enabled" : true,
181 | "datalength": -1,
182 | "constraints" : ["REQUIRED"],
183 | "validate" : { "I" : ["REQUIRED","DATE"]},
184 | "insertable" : true,
185 | "updatable" : false,
186 | "selectable" : false,
187 | "primary" : false,
188 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
189 | "encrypt" : false
190 | },
191 | "updated" : {
192 | "datatype" : "timestamp",
193 | "tz_enabled" : true,
194 | "datalength": -1,
195 | "constraints" : ["REQUIRED"],
196 | "validate" : { "I" : ["REQUIRED","DATE"] , "U" : ["REQUIRED","DATE"]},
197 | "insertable" : true,
198 | "updatable" : false,
199 | "selectable" : false,
200 | "primary" : false,
201 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
202 | "encrypt" : false
203 | }
204 | }
205 | },
206 | "routes" : {
207 | "name" : "routes",
208 | "overwrite" : false ,
209 | "validate" : {"I" : ["UNIQUE(route_method,route_url)"],"U" : ["UNIQUE_EXCLUDE(route_method,route_url)"]},
210 | "columns" : {
211 | "name" : {
212 | "datatype" : "string",
213 | "datalength": -1,
214 | "constraints" : ["PRIMARY"],
215 | "validate" : { "I" : ["UNIQUE","REQUIRED"] , "U" : ["UNIQUE_EXCLUDE","REQUIRED"], "D" : []},
216 | "insertable" : true,
217 | "updatable" : true,
218 | "selectable" : true,
219 | "primary" : false
220 | },
221 | "id" : {
222 | "datatype" : "string",
223 | "datalength": -1,
224 | "constraints" : ["PRIMARY"],
225 | "validate" : { "I" : ["REQUIRED"] , "U" : ["EXISTS" , "REQUIRED"], "D" : ["EXISTS","REQUIRED"]},
226 | "insertable" : true,
227 | "updatable" : false,
228 | "selectable" : true,
229 | "default" : {"I" : {"value": "UUID" , "overwrite" : false } },
230 | "primary" : true
231 | },
232 | "function_id" : {
233 | "datatype" : "string",
234 | "datalength": -1,
235 | "constraints" : ["PRIMARY","$REF.FUNCTIONS(ID)"],
236 | "validate" : { "I" : ["REQUIRED","$REF.FUNCTIONS-id,function_id"] , "U" : ["REQUIRED","$REF.FUNCTIONS-id,function_id"], "D" : []},
237 | "insertable" : true,
238 | "updatable" : true,
239 | "selectable" : true,
240 | "primary" : false
241 | },
242 | "route_method" : {
243 | "datatype" : "string",
244 | "datalength": -1,
245 | "constraints" : ["REQUIRED"],
246 | "validate" : { "I" : ["REQUIRED", "LIST-GET;POST"] , "U" : ["REQUIRED", "LIST-GET;POST"], "D" : []},
247 | "insertable" : true,
248 | "updatable" : true,
249 | "selectable" : true,
250 | "primary" : false
251 | },
252 | "enabled_flag" : {
253 | "datatype" : "string",
254 | "datalength": -1,
255 | "constraints" : ["REQUIRED"],
256 | "validate" : { "I" : [] , "U" : ["REQUIRED"], "D" : []},
257 | "insertable" : true,
258 | "updatable" : true,
259 | "selectable" : true,
260 | "primary" : false
261 | },
262 | "route_url" : {
263 | "datatype" : "string",
264 | "datalength": -1,
265 | "constraints" : ["REQUIRED"],
266 | "validate" : { "I" : ["REQUIRED","URL","UNIQUE"] , "U" : ["REQUIRED","URL","UNIQUE_EXCLUDE"], "D" : []},
267 | "insertable" : true,
268 | "updatable" : true,
269 | "selectable" : true,
270 | "primary" : false
271 | },
272 | "ref_source_id" : {
273 | "datatype" : "string",
274 | "datalength": -1,
275 | "constraints" : [],
276 | "insertable" : true,
277 | "updatable" : true,
278 | "selectable" : true,
279 | "primary" : false
280 | },
281 | "description" : {
282 | "datatype" : "string",
283 | "datalength": -1,
284 | "constraints" : [],
285 | "insertable" : true,
286 | "updatable" : true,
287 | "selectable" : true,
288 | "primary" : false
289 | },
290 | "sample_response" : {
291 | "datatype" : "string",
292 | "datalength": -1,
293 | "constraints" : [],
294 | "insertable" : true,
295 | "updatable" : true,
296 | "selectable" : true,
297 | "primary" : false
298 | },
299 | "sample_request" : {
300 | "datatype" : "string",
301 | "datalength": -1,
302 | "constraints" : [],
303 | "insertable" : true,
304 | "updatable" : true,
305 | "selectable" : true,
306 | "primary" : false
307 | },
308 | "created" : {
309 | "datatype" : "timestamp",
310 | "tz_enabled" : true,
311 | "datalength": -1,
312 | "constraints" : ["REQUIRED"],
313 | "validate" : { "I" : ["REQUIRED","DATE"]},
314 | "insertable" : true,
315 | "updatable" : false,
316 | "selectable" : false,
317 | "primary" : false,
318 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
319 | "encrypt" : false
320 | },
321 | "updated" : {
322 | "datatype" : "timestamp",
323 | "tz_enabled" : true,
324 | "datalength": -1,
325 | "constraints" : ["REQUIRED"],
326 | "validate" : { "I" : ["REQUIRED","DATE"] , "U" : ["REQUIRED","DATE"]},
327 | "insertable" : true,
328 | "updatable" : false,
329 | "selectable" : false,
330 | "primary" : false,
331 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
332 | "encrypt" : false
333 | }
334 | }
335 | },
336 | "users" : {
337 | "name" : "users",
338 | "overwrite" : false ,
339 | "validate" : {"I" : ["UNIQUE(username)"],"U" : []},
340 | "columns" : {
341 | "username" : {
342 | "datatype" : "string",
343 | "datalength": -1,
344 | "constraints" : ["PRIMARY"],
345 | "validate" : { "I" : ["UNIQUE","REQUIRED"] , "U" : [], "D" : []},
346 | "insertable" : true,
347 | "updatable" : false,
348 | "selectable" : true,
349 | "primary" : false
350 | },
351 | "id" : {
352 | "datatype" : "string",
353 | "datalength": -1,
354 | "constraints" : ["PRIMARY"],
355 | "validate" : { "I" : ["REQUIRED"] , "U" : ["EXISTS" , "REQUIRED"], "D" : ["EXISTS","REQUIRED"]},
356 | "insertable" : true,
357 | "updatable" : false,
358 | "selectable" : true,
359 | "default" : {"I" : {"value": "UUID" , "overwrite" : false } },
360 | "primary" : true
361 | },
362 | "first_name" : {
363 | "datatype" : "string",
364 | "datalength": -1,
365 | "constraints" : [],
366 | "validate" : { "I" : [] , "U" : [], "D" : []},
367 | "insertable" : true,
368 | "updatable" : true,
369 | "selectable" : true,
370 | "primary" : false
371 | },
372 | "last_name" : {
373 | "datatype" : "string",
374 | "datalength": -1,
375 | "constraints" : [],
376 | "validate" : { "I" : [] , "U" : [], "D" : []},
377 | "insertable" : true,
378 | "updatable" : true,
379 | "selectable" : true,
380 | "primary" : false
381 | },
382 | "password" : {
383 | "datatype" : "string",
384 | "datalength": -1,
385 | "constraints" : ["REQUIRED"],
386 | "validate" : { "I" : ["REQUIRED"] , "U" : [], "D" : []},
387 | "insertable" : true,
388 | "updatable" : true,
389 | "selectable" : true,
390 | "primary" : false
391 | },
392 | "ref_user_id" : {
393 | "datatype" : "string",
394 | "datalength": -1,
395 | "constraints" : [],
396 | "insertable" : true,
397 | "updatable" : true,
398 | "selectable" : true,
399 | "primary" : false
400 | },
401 | "created" : {
402 | "datatype" : "timestamp",
403 | "tz_enabled" : true,
404 | "datalength": -1,
405 | "constraints" : ["REQUIRED"],
406 | "validate" : { "I" : ["REQUIRED","DATE"]},
407 | "insertable" : true,
408 | "updatable" : false,
409 | "selectable" : false,
410 | "primary" : false,
411 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
412 | "encrypt" : false
413 | },
414 | "updated" : {
415 | "datatype" : "timestamp",
416 | "tz_enabled" : true,
417 | "datalength": -1,
418 | "constraints" : ["REQUIRED"],
419 | "validate" : { "I" : ["REQUIRED","DATE"] , "U" : ["REQUIRED","DATE"]},
420 | "insertable" : true,
421 | "updatable" : false,
422 | "selectable" : false,
423 | "primary" : false,
424 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
425 | "encrypt" : false
426 | }
427 | }
428 | },
429 | "tokens" : {
430 | "name" : "users",
431 | "overwrite" : false ,
432 | "validate" : {"I" : ["UNIQUE(username)"],"U" : []},
433 | "columns" : {
434 | "token" : {
435 | "datatype" : "string",
436 | "datalength": -1,
437 | "constraints" : ["PRIMARY"],
438 | "validate" : { "I" : ["REQUIRED"] , "U" : ["EXISTS" , "REQUIRED"], "D" : ["EXISTS","REQUIRED"]},
439 | "insertable" : true,
440 | "updatable" : false,
441 | "selectable" : true,
442 | "primary" : true
443 | },
444 | "start_time" : {
445 | "datatype" : "timestamp",
446 | "tz_enabled" : true,
447 | "datalength": -1,
448 | "constraints" : ["REQUIRED"],
449 | "validate" : { "I" : ["REQUIRED","DATE"]},
450 | "insertable" : true,
451 | "updatable" : false,
452 | "selectable" : false,
453 | "primary" : false,
454 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
455 | "encrypt" : false
456 | },
457 | "user_id" : {
458 | "datatype" : "string",
459 | "tz_enabled" : true,
460 | "datalength": -1,
461 | "constraints" : ["REQUIRED"],
462 | "validate" : { "I" : ["REQUIRED"]},
463 | "insertable" : true,
464 | "updatable" : false,
465 | "selectable" : false,
466 | "primary" : false,
467 | "encrypt" : false
468 | },
469 | "timeout_time" : {
470 | "datatype" : "timestamp",
471 | "tz_enabled" : true,
472 | "datalength": -1,
473 | "constraints" : ["REQUIRED"],
474 | "validate" : { "I" : ["REQUIRED","DATE"] , "U" : ["REQUIRED","DATE"]},
475 | "insertable" : true,
476 | "updatable" : false,
477 | "selectable" : false,
478 | "primary" : false,
479 | "encrypt" : false
480 | },
481 | "created" : {
482 | "datatype" : "timestamp",
483 | "tz_enabled" : true,
484 | "datalength": -1,
485 | "constraints" : ["REQUIRED"],
486 | "validate" : { "I" : ["REQUIRED","DATE"]},
487 | "insertable" : true,
488 | "updatable" : false,
489 | "selectable" : false,
490 | "primary" : false,
491 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
492 | "encrypt" : false
493 | },
494 | "updated" : {
495 | "datatype" : "timestamp",
496 | "tz_enabled" : true,
497 | "datalength": -1,
498 | "constraints" : ["REQUIRED"],
499 | "validate" : { "I" : ["REQUIRED","DATE"] , "U" : ["REQUIRED","DATE"]},
500 | "insertable" : true,
501 | "updatable" : false,
502 | "selectable" : false,
503 | "primary" : false,
504 | "default" : {"I" : {"value": "NOW" , "overwrite" : false } , "U" : {"value": "NOW" , "overwrite" : false } },
505 | "encrypt" : false
506 | }
507 | }
508 | }
509 | }
--------------------------------------------------------------------------------
/admin/install/db/functions/add_admin_user.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION add_admin_user( p_id text , p_hash text , p_password text)
2 | RETURNS json AS
3 | $BODY$
4 | DECLARE
5 | l_out json;
6 | l_id text;
7 | BEGIN
8 | SELECT id
9 | INTO l_id
10 | FROM USERS
11 | WHERE username = 'admin';
12 | IF l_id IS NULL OR l_id = '' THEN
13 | INSERT INTO USERS
14 | ( id
15 | , username
16 | , password
17 | , enabled_flag
18 | , created
19 | , updated
20 | )
21 | VALUES (
22 | p_id
23 | , 'admin'
24 | , p_password
25 | , 'Y'
26 | , now()
27 | , now()
28 | );
29 | END IF;
30 | RETURN '{"status" : "SUCCESS" , "message" : "OK"}';
31 | END
32 | $BODY$
33 | LANGUAGE plpgsql;
--------------------------------------------------------------------------------
/admin/install/db/functions/install_application.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION install_application(p_data json )
2 | RETURNS json AS
3 | $BODY$
4 | DECLARE
5 | l_out json;
6 | l_message_text text;
7 | l_exception_detail text;
8 | l_exception_hint text;
9 | l_connection_id text;
10 | l_functions_json json;
11 | l_routes_json json;
12 |
13 | functions_c CURSOR FOR SELECT json_array_elements(p_data->'functions');
14 | routes_c CURSOR(p_functions json) FOR SELECT json_array_elements(p_functions->'routes');
15 | l_function_record json;
16 | l_db_method text;
17 | l_name text;
18 | l_db_name text;
19 | l_datatype text;
20 | l_arguments text;
21 | l_id uuid;
22 | l_route_name text;
23 | l_route_method text;
24 | l_route_url text;
25 | l_sample_request text;
26 | l_sample_response text;
27 | l_application json;
28 | l_app_id text;
29 | l_app_name text;
30 | l_route_id uuid;
31 | l_function_id uuid;
32 |
33 | BEGIN
34 | SELECT id
35 | INTO l_connection_id
36 | FROM connections
37 | WHERE config_flag = 'Y'
38 | LIMIT 1;
39 |
40 | IF l_connection_id IS NULL OR l_connection_id = '' THEN
41 | RETURN '{"status":"E", "message" : "Unable to find default configuration"}';
42 | END IF;
43 |
44 | BEGIN
45 | l_functions_json := (p_data->>'functions')::json;
46 | EXCEPTION WHEN OTHERS THEN
47 | RETURN '{"status":"E", "message" : "Invalid json input for functions tag"}';
48 | END;
49 |
50 | BEGIN
51 | l_application := (p_data->>'application')::json;
52 | EXCEPTION WHEN OTHERS THEN
53 | RETURN '{"status":"E", "message" : "Invalid json input for application tag"}';
54 | END;
55 |
56 | IF l_application IS NULL THEN
57 | RETURN '{"status":"E", "message" : "Invalid Application File. Missing Application Info"}';
58 | END IF;
59 |
60 | BEGIN
61 | l_app_id := (l_application->>'identifier')::text;
62 | EXCEPTION WHEN OTHERS THEN
63 | RETURN '{"status":"E", "message" : "Invalid uuid input for application identifier tag"}';
64 | END;
65 |
66 | l_app_name := (l_application->>'name')::text;
67 |
68 | IF l_app_id IS NULL OR l_app_id = '' THEN
69 | RETURN '{"status" : "E" , "message" : "Invalid Application File. Missing Application Identifier"}';
70 | END IF;
71 |
72 | IF l_app_name IS NULL OR l_app_name = '' THEN
73 | RETURN '{"status" : "E" , "message" : "Invalid Application File. Missing Application Name"}';
74 | END IF;
75 |
76 | IF EXISTS ( SELECT 1 FROM applications WHERE id = l_app_id) THEN
77 | RETURN '{"status" : "E" , "message" : "This Application ['|| l_app_name|| '] is already installed. If you want to re-install please delete record from the table applications for this identifier to re install the application."}';
78 | END IF;
79 |
80 | IF l_functions_json IS NULL THEN
81 | RETURN '{"status" : "S" , "message" : "OK"}';
82 | END IF;
83 |
84 | OPEN functions_c;
85 |
86 | LOOP
87 | -- fetch row into the film
88 | FETCH functions_c INTO l_function_record;
89 | -- exit when no more row to fetch
90 | EXIT WHEN NOT FOUND;
91 |
92 | RAISE INFO '%',l_function_record;
93 |
94 | l_name := (l_function_record->>'name')::text;
95 | l_db_method := (l_function_record->>'db_method')::text;
96 |
97 | IF l_name IS NULL OR l_name = '' THEN
98 | RETURN '{"status" : "E" , "message" : "Function Name need to be provided"}';
99 | END IF;
100 |
101 | IF l_db_method IS NULL OR l_db_method = '' THEN
102 | RETURN '{"status" : "E" , "message" : "Database Function name need to be provided"}';
103 | END IF;
104 |
105 | SELECT p.proname as name,
106 | pg_catalog.pg_get_function_result(p.oid) as result_datatype,
107 | pg_catalog.pg_get_function_arguments(p.oid) as arguments
108 | INTO l_db_name , l_datatype , l_arguments
109 | FROM pg_catalog.pg_proc p
110 | LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
111 | WHERE pg_catalog.pg_function_is_visible(p.oid)
112 | AND n.nspname <> 'pg_catalog'
113 | AND n.nspname <> 'information_schema'
114 | AND LOWER(p.proname) = LOWER(l_db_method);
115 |
116 | IF l_db_name IS NULL OR l_db_name = '' THEN
117 | RETURN '{"status" : "E" , "message" : "Function ' ||l_db_method ||' does not exist"}';
118 | END IF;
119 |
120 | IF LOWER(l_datatype) <> 'json' THEN
121 | RETURN '{"status" : "E" , "message" : "Function Return Type must be json"}';
122 | END IF;
123 |
124 | IF l_arguments LIKE '%,%' THEN
125 | RETURN '{"status" : "E" , "message" : "Function Argument must contain only one argument and the datatype must be json"}';
126 | END IF;
127 |
128 | OPEN routes_c(l_function_record);
129 |
130 | LOOP
131 | FETCH routes_c INTO l_routes_json;
132 | -- exit when no more row to fetch
133 | EXIT WHEN NOT FOUND;
134 |
135 | l_route_name := l_routes_json->>'name';
136 | l_route_url := l_routes_json->>'route_url';
137 | l_route_method := l_routes_json->>'route_method';
138 |
139 | IF l_route_name IS NULL OR l_route_name = '' THEN
140 | RETURN '{"status" : "E" , "message" : "Route name must be provided"}';
141 | END IF;
142 |
143 | IF l_route_url IS NULL OR l_route_url = '' THEN
144 | RETURN '{"status" : "E" , "message" : "Route url must be provided"}';
145 | END IF;
146 |
147 | IF l_route_method IS NULL OR l_route_method = '' THEN
148 | RETURN '{"status" : "E" , "message" : "Route Method must be provided"}';
149 | ELSE
150 | IF l_route_method NOT IN ('GET','POST') THEN
151 | RETURN '{"status" : "E" , "message" : "Invalid Route Method value. Only GET,POST is supported."}';
152 | END IF;
153 | END IF;
154 |
155 | l_route_id := NULL;
156 |
157 | SELECT id
158 | INTO l_route_id
159 | FROM routes
160 | WHERE name = l_route_name;
161 |
162 | IF l_route_id IS NOT NULL THEN
163 | RETURN '{"status" : "E" , "message" : "Route Name alread exist. Please use different route name ['||l_route_name||']"}';
164 | END IF;
165 |
166 | l_route_id := NULL;
167 |
168 | SELECT id
169 | INTO l_route_id
170 | FROM routes
171 | WHERE route_method = l_route_method
172 | AND route_url = l_route_url;
173 |
174 | IF l_route_id IS NOT NULL THEN
175 | RETURN '{"status" : "E" , "message" : "Route Url and the Route Method alread exist. Please use different route url or route method ['||l_route_url||','||l_route_method||']"}';
176 | END IF;
177 |
178 | END LOOP;
179 |
180 | -- Close the cursor
181 | CLOSE routes_c;
182 |
183 | END LOOP;
184 |
185 | -- Close the cursor
186 | CLOSE functions_c;
187 |
188 | OPEN functions_c;
189 |
190 | LOOP
191 | -- fetch row into the film
192 | FETCH functions_c INTO l_function_record;
193 | -- exit when no more row to fetch
194 | EXIT WHEN NOT FOUND;
195 |
196 | RAISE INFO '%',l_function_record;
197 |
198 | l_function_id := md5(random()::text || clock_timestamp()::text)::uuid;
199 | l_name := (l_function_record->>'name')::text;
200 | l_db_method := (l_function_record->>'db_method')::text;
201 |
202 |
203 | INSERT INTO functions
204 | ( id
205 | , name
206 | , connection_id
207 | , db_method
208 | , created
209 | , updated
210 | ) VALUES (
211 | l_function_id
212 | , l_name
213 | , l_connection_id
214 | , l_db_method
215 | , NOW()
216 | , NOW()
217 | );
218 |
219 | OPEN routes_c(l_function_record);
220 |
221 | LOOP
222 | FETCH routes_c INTO l_routes_json;
223 | -- exit when no more row to fetch
224 | EXIT WHEN NOT FOUND;
225 |
226 | l_route_name := l_routes_json->>'name';
227 | l_route_url := l_routes_json->>'route_url';
228 | l_route_method := l_routes_json->>'route_method';
229 | l_route_id := md5(random()::text || clock_timestamp()::text)::uuid;
230 | l_sample_request := l_routes_json->>'sample_request';
231 | l_sample_response := l_routes_json->>'sample_response';
232 |
233 | INSERT INTO routes
234 | ( id
235 | , name
236 | , function_id
237 | , route_method
238 | , route_url
239 | , enabled_flag
240 | , sample_request
241 | , sample_response
242 | , created
243 | , updated
244 | ) VALUES
245 | (
246 | l_route_id
247 | , l_route_name
248 | , l_function_id
249 | , l_route_method
250 | , l_route_url
251 | , 'Y'
252 | , l_sample_request
253 | , l_sample_response
254 | , NOW()
255 | , NOW()
256 | );
257 | END LOOP;
258 |
259 | -- Close the cursor
260 | CLOSE routes_c;
261 |
262 | END LOOP;
263 |
264 | -- Close the cursor
265 | CLOSE functions_c;
266 |
267 | INSERT INTO applications
268 | (
269 | id
270 | , name
271 | , created
272 | , updated
273 | ) VALUES (
274 | l_app_id
275 | , l_app_name
276 | , NOW()
277 | , NOW()
278 | );
279 |
280 |
281 |
282 | RETURN '{"status" : "S" , "message" : "OK"}';
283 | EXCEPTION WHEN OTHERS THEN
284 | GET STACKED DIAGNOSTICS l_message_text = MESSAGE_TEXT,
285 | l_exception_detail = PG_EXCEPTION_DETAIL,
286 | l_exception_hint = PG_EXCEPTION_HINT;
287 | l_out := '{ "status" : "E" , "message" : "' || REPLACE(l_message_text, '"', E'\\"') || '" }';
288 | return l_out;
289 | END
290 | $BODY$
291 | LANGUAGE plpgsql;
--------------------------------------------------------------------------------
/admin/install/db/functions/validate_session.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION validate_session( p_token text
2 | )
3 | RETURNS json AS
4 | $BODY$
5 | DECLARE
6 | l_out json;
7 | l_token text;
8 | l_expire_time timestamp;
9 | l_user_id text;
10 | l_enabled_flag text;
11 | l_start_time timestamp;
12 | text_var1 text;
13 | text_var2 text;
14 | text_var3 text;
15 | l_detail text;
16 | BEGIN
17 | l_token := p_token;
18 |
19 | if (l_token IS NULL OR l_token = '' ) THEN
20 | l_out := '{ "status" : "E" , "message" : "SESSION_BAD_INPUT" }';
21 | RETURN l_out;
22 |
23 | END IF;
24 |
25 | RAISE INFO '1 ' ;
26 |
27 | SELECT start_time , timeout_time , user_id
28 | INTO l_start_time , l_expire_time , l_user_id
29 | FROM tokens
30 | WHERE token = l_token;
31 |
32 | IF l_start_time IS NULL THEN
33 | l_out := '{ "status" : "E" , "message" : "SESSION_INVALID" }';
34 | RETURN l_out;
35 | END IF;
36 |
37 |
38 | IF l_expire_time < now() THEN
39 | l_out := '{ "status" : "E" , "message" : "SESSION_EXPIRED" }';
40 | RETURN l_out;
41 |
42 | END IF;
43 |
44 |
45 |
46 | SELECT enabled_flag
47 | INTO l_enabled_flag
48 | FROM USERS
49 | WHERE id = l_user_id;
50 |
51 | IF l_enabled_flag IS NULL OR l_enabled_flag = 'N' THEN
52 | l_out := '{ "status" : "E" , "message" : "INVALID_USER" }';
53 | RETURN l_out;
54 |
55 | END IF;
56 |
57 |
58 | UPDATE tokens
59 | SET timeout_time = NOW() + interval '1h' * 1
60 | , updated = NOW()
61 | WHERE token = l_token;
62 |
63 | l_out := '{ "status" : "SUCCESS" , "message" : "OK"}';
64 | return l_out;
65 | EXCEPTION WHEN OTHERS THEN
66 | GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
67 | text_var2 = PG_EXCEPTION_DETAIL,
68 | text_var3 = PG_EXCEPTION_HINT;
69 | l_out := '{ "status" : "ERROR" , "message" : "' || REPLACE(text_var1, '"', E'\\"') || '" }';
70 | return l_out;
71 | END
72 | $BODY$
73 | LANGUAGE plpgsql;
--------------------------------------------------------------------------------
/admin/install/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const { Client } = require('pg')
21 | const utils = require('../Utils');
22 | const path = require('path')
23 | const fs = require('fs');
24 | const connectionController = require('../controllers/Connection');
25 | const colors = require('colors');
26 |
27 | process.env.VERSION = process.env.VERSION || "1.0.0";
28 |
29 | const addAdminUser = async function () {
30 | const passwordHash = utils.encryptPassword("admin");
31 | const uuid = utils.getUUID();
32 | let sql = "SELECT add_admin_user($1, $2, $3) as result";
33 | let params = [uuid,'',passwordHash];
34 | let response = await utils.callSQL(sql,params);
35 | return response;
36 | }
37 |
38 | const startLog = function(filename) {
39 | // console.log("Compiling File : " + filename);
40 | }
41 |
42 | const endLog = function(filename) {
43 | //console.log("File compilation completed : " + filename);
44 | }
45 |
46 | const errorLog = function(filename) {
47 | console.log(`Error compiling File: ${filename}`.blue);
48 | }
49 |
50 | const loadDB = async function (demo) {
51 |
52 | console.log("pgAPI - Compiling admin table script...".blue)
53 |
54 | await utils.loadDDL (path.resolve(__dirname, './db/DB.sql'),startLog, endLog, errorLog);
55 |
56 | console.log("pgAPI - Compiling admin database functions...".blue)
57 |
58 | await utils.executeDBFunctionsFromDir(path.resolve(__dirname, './db/functions'));
59 |
60 | let response = await utils.getSQLResults("SELECT * FROM current_version",[]);
61 |
62 | if (response.length === 0) {
63 | let response = await utils.callSQL("INSERT INTO current_version(created,version) VALUES(NOW(),$1)",[process.env.VERSION]);
64 | await addAdminUser ();
65 | console.log("pgAPI - Adding default connection...".blue)
66 | await connectionController.addDefaultConnection();
67 |
68 | if (process.env.DEMO_INSTALL === "Y") {
69 | const demoAppName = "tasks";
70 | let response = await utils.installApplication(demoAppName);
71 | if (response.status === "S") {
72 | console.log(`pgAPI - Successfully installed application [${demoAppName}]`.green)
73 | } else {
74 | console.log(`pgAPI - Application installation failed.. [${demoAppName}] - ${response.message}`.yellow)
75 | }
76 | }
77 | }
78 | }
79 |
80 | module.exports = {
81 | loadDB: loadDB
82 |
83 | }
--------------------------------------------------------------------------------
/admin/models/Connection.js:
--------------------------------------------------------------------------------
1 | const utils = require('../Utils');
2 | const coreModel = require('../core/models/Connection');
3 |
4 |
5 | const isValidDBConnection = function(record) {
6 | const client = utils.getClientbyRecord(record);
7 | client.connect();
8 | }
9 |
10 | /*
11 | This file is part of pgAPI.
12 | pgAPI - Database as a service
13 | Copyright (C) 2018 Praveen Muralidhar
14 |
15 | pgAPI is a free software: you can redistribute it and/or modify
16 | it under the terms of the GNU General Public License as published by
17 | the Free Software Foundation, either version 3 of the License, or
18 | any later version.
19 |
20 | pgAPI is distributed in the hope that it will be useful,
21 | but WITHOUT ANY WARRANTY; without even the implied warranty of
22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 | GNU General Public License for more details.
24 |
25 | You should have received a copy of the GNU General Public License
26 | along with this program. If not, see .
27 | */
28 |
29 | const validate = async function(record,mode, custom, pool) {
30 |
31 | const response = await coreModel.validate(record,mode,custom,pool);
32 |
33 | // write your custom code here
34 |
35 | return response;
36 |
37 | }
38 |
39 |
40 | const insert = async function(record) {
41 |
42 | // Before Insert: write your custom code here
43 |
44 | const response = await coreModel.insert(record);
45 |
46 | // After Insert: write your custom code here
47 |
48 | return response;
49 |
50 | }
51 |
52 | const update = async function(record) {
53 |
54 | // Before Update: write your custom code here
55 |
56 | const response = await coreModel.update(record);
57 |
58 | // After Update: write your custom code here
59 |
60 | return response;
61 | }
62 |
63 | const deleteRecord = async function(record) {
64 |
65 | //Before Delete: write your custom code here
66 |
67 | const response = await coreModel.delete(record);
68 |
69 | //After Delete: write your custom code here
70 |
71 | return response;
72 | }
73 |
74 | const fetchAll = async function() {
75 |
76 | //Before Fetch: write your custom code here
77 |
78 | const response = await coreModel.fetchAll();
79 |
80 | //After Fetch: write your custom code here
81 |
82 | return response;
83 | }
84 |
85 | module.exports = {
86 | isValidDBConnection: isValidDBConnection,
87 | validate: validate,
88 | insert: insert,
89 | update: update,
90 | delete: deleteRecord,
91 | fetchAll: fetchAll
92 | }
--------------------------------------------------------------------------------
/admin/models/Function.js:
--------------------------------------------------------------------------------
1 | const utils = require('../Utils');
2 | const coreModel = require('../core/models/Function');
3 |
4 |
5 | const validate = async function(record, mode, custom, pool) {
6 |
7 | const response = await coreModel.validate(record,mode, custom, pool);
8 |
9 | // write your custom code here
10 |
11 | return response;
12 |
13 | }
14 |
15 |
16 | const insert = async function(record) {
17 |
18 | // Before Insert: write your custom code here
19 |
20 | const response = await coreModel.insert(record);
21 |
22 | // After Insert: write your custom code here
23 |
24 | return response;
25 |
26 | }
27 |
28 | const update = async function(record) {
29 |
30 | // Before Update: write your custom code here
31 |
32 | const response = await coreModel.update(record);
33 |
34 | // After Update: write your custom code here
35 |
36 | return response;
37 | }
38 |
39 | const deleteRecord = async function(record) {
40 |
41 | //Before Delete: write your custom code here
42 |
43 | const response = await coreModel.delete(record);
44 |
45 | //After Delete: write your custom code here
46 |
47 | return response;
48 | }
49 |
50 | const fetchAll = async function() {
51 |
52 | //Before Fetch: write your custom code here
53 |
54 | const response = await coreModel.fetchAll();
55 |
56 | //After Fetch: write your custom code here
57 |
58 | return response;
59 | }
60 |
61 | module.exports = {
62 | validate: validate,
63 | insert: insert,
64 | update: update,
65 | delete: deleteRecord,
66 | fetchAll: fetchAll
67 | }
--------------------------------------------------------------------------------
/admin/models/Route.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const utils = require('../Utils');
21 | const coreModel = require('../core/models/Route');
22 |
23 |
24 | const validate = async function(record,mode,custom,pool) {
25 |
26 | const response = await coreModel.validate(record,mode,custom,pool);
27 |
28 | let sql = "";
29 | let params = "";
30 | let status = "S";
31 | let message = "OK";
32 |
33 | // write your custom code here
34 | if (custom) {
35 | if (response.status === "S" && ( mode === "I" || mode === "U")) {
36 | if (mode === "I") {
37 | sql = "SELECT 1 FROM routes WHERE route_method = $1 AND route_url = $2";
38 | params = [record.route_method,record.route_url];
39 | } else if (mode === "U") {
40 | sql = "SELECT 1 FROM routes WHERE route_method = $1 AND route_url = $2 AND id!= $3";
41 | params = [record.route_method,record.route_url, record.id];
42 | }
43 | const resCount = await utils.checkAttribute(sql,params);
44 | if (resCount > 0) {
45 | status = "E";
46 | message = "Unique Validation failed for the columns[route_method,route_url]";
47 | return {status: status, message: message};
48 | }
49 | }
50 | }
51 |
52 | return response;
53 |
54 | }
55 |
56 |
57 | const insert = async function(record) {
58 |
59 | // Before Insert: write your custom code here
60 |
61 | const response = await coreModel.insert(record);
62 |
63 | // After Insert: write your custom code here
64 |
65 | return response;
66 |
67 | }
68 |
69 | const update = async function(record) {
70 |
71 | // Before Update: write your custom code here
72 |
73 | const response = await coreModel.update(record);
74 |
75 | // After Update: write your custom code here
76 |
77 | return response;
78 | }
79 |
80 | const deleteRecord = async function(record) {
81 |
82 | //Before Delete: write your custom code here
83 |
84 | const response = await coreModel.delete(record);
85 |
86 | //After Delete: write your custom code here
87 |
88 | return response;
89 | }
90 |
91 | const fetchAll = async function() {
92 |
93 | //Before Fetch: write your custom code here
94 |
95 | const response = await coreModel.fetchAll();
96 |
97 | //After Fetch: write your custom code here
98 |
99 | return response;
100 | }
101 |
102 | const fetchById = async function(id) {
103 |
104 | //Before Fetch: write your custom code here
105 |
106 | const response = await coreModel.fetchById(id);
107 |
108 | //After Fetch: write your custom code here
109 |
110 | return response;
111 | }
112 |
113 | const getRoutes = async function() {
114 | const sql = "select r.id route_id , r.enabled_flag, 'json' as content_type , r.route_method , r.route_url , f.db_method as route_callback, c.database , c.host , c.username , c.port , c.password , c.name as connection_name " +
115 | " from routes r " +
116 | " , functions f " +
117 | " , connections c " +
118 | " where r.function_id = f.id " +
119 | " and c.id = f.connection_id ";
120 |
121 | let out = {};
122 |
123 | try {
124 |
125 | return await utils.getSQLResultswithStatus(sql,[]);
126 | } catch (e) {
127 | console.log("Error");
128 | return e;
129 | }
130 | }
131 |
132 | const getRoutesByUrl = async function(url) {
133 | const sql = "select r.id route_id , 'json' as content_type , r.route_method , r.route_url , f.db_method as route_callback, c.database , c.host , c.username , c.port , c.password , c.name as connection_name " +
134 | " from routes r " +
135 | " , functions f " +
136 | " , connections c " +
137 | " where r.function_id = f.id " +
138 | " and c.id = f.connection_id and r.route_url = $1";
139 |
140 | let out = {};
141 |
142 | try {
143 | return await utils.getSQLResultswithStatus(sql,[url]);
144 | } catch (e) {
145 | console.log("Error");
146 | return e;
147 | }
148 | }
149 |
150 |
151 | module.exports = {
152 | validate: validate,
153 | insert: insert,
154 | update: update,
155 | delete: deleteRecord,
156 | fetchAll: fetchAll,
157 | getRoutes: getRoutes,
158 | fetchById: fetchById,
159 | getRoutesByUrl: getRoutesByUrl
160 | }
--------------------------------------------------------------------------------
/admin/models/User.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const utils = require('../Utils');
21 | const coreModel = require('../core/models/User');
22 |
23 | const validate = async function(record, mode, custom, pool) {
24 |
25 | const response = await coreModel.validate(record,mode, custom, pool);
26 |
27 | // write your custom code here
28 |
29 | return response;
30 |
31 | }
32 |
33 | const insert = async function(record) {
34 |
35 | // Before Insert: write your custom code here
36 |
37 | const response = await coreModel.insert(record);
38 |
39 | // After Insert: write your custom code here
40 |
41 | return response;
42 |
43 | }
44 |
45 | const insertArchive = async function(record) {
46 |
47 | // Before Insert: write your custom code here
48 |
49 | const response = await coreModel.insertArchive(record);
50 |
51 | // After Insert: write your custom code here
52 |
53 | return response;
54 |
55 | }
56 |
57 | const insertToken = async function(record) {
58 |
59 | // Before Insert: write your custom code here
60 |
61 | const response = await coreModel.insertToken(record);
62 |
63 | // After Insert: write your custom code here
64 |
65 | return response;
66 |
67 | }
68 |
69 | const update = async function(record) {
70 |
71 | // Before Update: write your custom code here
72 |
73 | const response = await coreModel.update(record);
74 |
75 | // After Update: write your custom code here
76 |
77 | return response;
78 | }
79 |
80 | const updatePassword = async function(record) {
81 |
82 | // Before Update: write your custom code here
83 |
84 | const response = await coreModel.updatePassword(record);
85 |
86 | // After Update: write your custom code here
87 |
88 | return response;
89 | }
90 |
91 | const updateToken = async function(record) {
92 |
93 | // Before Update: write your custom code here
94 |
95 | const response = await coreModel.updateToken(record);
96 |
97 | // After Update: write your custom code here
98 |
99 | return response;
100 | }
101 |
102 | const updateEnabledFlag = async function(record) {
103 |
104 | // Before Update: write your custom code here
105 |
106 | const response = await coreModel.updateEnabledFlag(record);
107 |
108 | // After Update: write your custom code here
109 |
110 | return response;
111 | }
112 |
113 | const deleteRecord = async function(record) {
114 |
115 | //Before Delete: write your custom code here
116 |
117 | const response = await coreModel.delete(record);
118 |
119 | //After Delete: write your custom code here
120 |
121 | return response;
122 | }
123 |
124 | const fetchAll = async function() {
125 |
126 | //Before Fetch: write your custom code here
127 |
128 | const response = await coreModel.fetchAll();
129 |
130 | //After Fetch: write your custom code here
131 |
132 | return response;
133 | }
134 |
135 | const fetchById = async function(id) {
136 |
137 | //Before Fetch: write your custom code here
138 |
139 | const response = await coreModel.fetchById(id);
140 |
141 | //After Fetch: write your custom code here
142 |
143 | return response;
144 | }
145 |
146 |
147 | const fetchByIdUser = async function(id) {
148 |
149 | //Before Fetch: write your custom code here
150 |
151 | const response = await coreModel.fetchByIdUser(id);
152 |
153 | //After Fetch: write your custom code here
154 |
155 | return response;
156 | }
157 |
158 | const fetchByUsername = async function(username) {
159 |
160 | //Before Fetch: write your custom code here
161 |
162 | const response = await coreModel.fetchByUsername(username);
163 |
164 | //After Fetch: write your custom code here
165 |
166 | return response;
167 | }
168 |
169 | const fetchToken = async function(token) {
170 |
171 | //Before Fetch: write your custom code here
172 |
173 | const response = await coreModel.fetchToken({token:token});
174 |
175 | //After Fetch: write your custom code here
176 |
177 | return response;
178 | }
179 |
180 |
181 | const validateSession = async function(record) {
182 |
183 | //Before Fetch: write your custom code here
184 |
185 | const response = await coreModel.validateSession(record);
186 |
187 | //After Fetch: write your custom code here
188 |
189 | return response;
190 | }
191 |
192 | module.exports = {
193 | insert: insert,
194 | insertArchive: insertArchive,
195 | insertToken: insertToken,
196 | update: update,
197 | updatePassword: updatePassword,
198 | updateToken: updateToken,
199 | delete: deleteRecord,
200 | fetchAll: fetchAll,
201 | fetchById: fetchById,
202 | fetchToken: fetchToken,
203 | fetchByUsername: fetchByUsername,
204 | fetchByIdUser: fetchByIdUser,
205 | validate: validate,
206 | updateEnabledFlag: updateEnabledFlag,
207 | validateSession: validateSession
208 | }
--------------------------------------------------------------------------------
/admin/router/index.js:
--------------------------------------------------------------------------------
1 | var express = require('express'),
2 | router = express.Router();
3 |
4 |
5 | var connection = require('../controllers/Connection');
6 | var _function = require('../controllers/Function');
7 | var routes = require('../controllers/Route');
8 | var dashboard = require('../controllers/Dashboard');
9 | let user = require('../controllers/User');
10 | const dbUtils = require('../controllers/dbUtils');
11 | const utils = require('../Utils');
12 |
13 | router.use(async function(req, res, next) {
14 |
15 | // Website you wish to allow to connect
16 | res.setHeader('Access-Control-Allow-Origin', '*');
17 | // Request methods you wish to allow
18 | res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE');
19 |
20 | // Request headers you wish to allow
21 | res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization');
22 |
23 | res.setHeader("Access-Control-Allow-Credentials", "true");
24 |
25 | let authRequired = true;
26 |
27 | if (req.originalUrl === '/admin/api/login') {
28 | authRequired = false;
29 | }
30 |
31 | if (authRequired) {
32 | if (!req.headers.authorization) {
33 | return res.status(403).json({ error: 'No credentials sent!' });
34 | }
35 |
36 | if (!!req.headers.authorization) {
37 | let token = req.headers.authorization;
38 | token = token.replace("Bearer",'').trim();
39 | let response = await user.validateSession(token);
40 |
41 | if (!!response.decoded && !!response.decoded.claims) {
42 | req.claims = response.decoded.claims;
43 | }
44 |
45 | if (response.status === "E") {
46 | return res.status(403).json({ error: response.code });
47 | }
48 |
49 | }
50 | }
51 |
52 | next();
53 | });
54 |
55 | router.get('/connections', connection.fetch );
56 | router.put('/connection/:id', connection.update);
57 | router.post('/connection', connection.createAPI);
58 | router.delete('/connection/:id', connection.delete);
59 | router.get('/connection/test', connection.testDBConnection);
60 | router.get('/connections/status', connection.testDBConnections);
61 |
62 | router.get('/functions', _function.fetch );
63 | router.put('/function/:id', _function.update);
64 | router.post('/function', _function.createAPI);
65 | router.delete('/function/:id', _function.delete);
66 | router.get('/functions/status', _function.testDBFunctions );
67 |
68 | router.get('/routes', routes.fetch );
69 | router.put('/route/:id', routes.update);
70 | router.post('/route', routes.createAPI);
71 | router.post('/routes/reload', routes.refreshRoutes);
72 | router.delete('/route/:id', routes.delete);
73 |
74 | router.get('/export', dashboard.exportConfig );
75 | router.post('/import', dashboard.importConfig );
76 | router.post('/delete', dashboard.deleteConfig );
77 |
78 | router.post('/login', user.loginAPI );
79 | router.post('/generatetoken', user.sessionAPI );
80 | router.get('/user', user.fetchAPI );
81 | router.put('/user', user.updateUserAPI );
82 | router.post('/password/reset', user.resetPasswordAPI );
83 |
84 | router.get('/db/function/code', dbUtils.getDBFunction);
85 | router.post('/db/function/execute', dbUtils.executeFunction);
86 | router.post('/db/sql/save', dbUtils.saveSQL);
87 | router.get('/db/sql/get', dbUtils.getSQL);
88 |
89 | module.exports = router;
--------------------------------------------------------------------------------
/admin/sql/main.sql:
--------------------------------------------------------------------------------
1 | CREATE OR REPLACE FUNCTION install_task_demo(p_data json )
2 | RETURNS json AS
3 | $BODY$
4 | DECLARE
5 | l_out json;
6 | l_connection_id text;
7 | l_functions_json json;
8 | l_routes_json json;
9 |
10 | functions_c CURSOR FOR SELECT json_array_elements(p_data->'functions');
11 | routes_c CURSOR FOR SELECT json_array_elements(p_data->'routes');
12 | l_function_record json;
13 | l_db_method text;
14 | l_name text;
15 | l_db_name text;
16 | l_datatype text;
17 | l_arguments text;
18 | l_id uuid;
19 | l_route_name text;
20 | l_route_method text;
21 | l_route_url text;
22 | l_route_id uuid;
23 |
24 | BEGIN
25 | SELECT id
26 | INTO l_connection_id
27 | FROM connections
28 | WHERE config_flag = 'Y'
29 | LIMIT 1;
30 |
31 | IF l_connection_id IS NULL OR l_connection_id = '' THEN
32 | RETURN '{"status":"E", "message" : "Unable to find default configuration"}';
33 | END IF;
34 |
35 | l_functions_json := (p_data->>'functions')::json;
36 |
37 | RAISE INFO '%',l_functions_json;
38 |
39 | IF l_functions_json IS NULL THEN
40 | RETURN '{"status" : "S" , "message" : "OK"}';
41 | END IF;
42 |
43 | OPEN functions_c;
44 |
45 | LOOP
46 | -- fetch row into the film
47 | FETCH functions_c INTO l_function_record;
48 | -- exit when no more row to fetch
49 | EXIT WHEN NOT FOUND;
50 |
51 | RAISE INFO '%',l_function_record;
52 |
53 | ç := (l_function_record->>'name')::text;
54 | l_db_method := (l_function_record->>'db_method')::text;
55 |
56 | IF l_name IS NULL OR l_name = '' THEN
57 | RETURN '{"status" : "E" , "message" : "Function Name need to be provided"}';
58 | END IF;
59 |
60 | IF l_db_method IS NULL OR l_db_method = '' THEN
61 | RETURN '{"status" : "E" , "message" : "Function Name need to be provided"}';
62 | END IF;
63 |
64 | SELECT p.proname as name,
65 | pg_catalog.pg_get_function_result(p.oid) as result_datatype,
66 | pg_catalog.pg_get_function_arguments(p.oid) as arguments
67 | INTO l_db_name , l_datatype , l_arguments
68 | FROM pg_catalog.pg_proc p
69 | LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
70 | WHERE pg_catalog.pg_function_is_visible(p.oid)
71 | AND n.nspname <> 'pg_catalog'
72 | AND n.nspname <> 'information_schema'
73 | AND LOWER(p.proname) = LOWER(l_db_method);
74 |
75 | IF l_db_name IS NULL OR l_db_name = '' THEN
76 | RETURN '{"status" : "E" , "message" : "Function ' ||l_db_method ||' does not exist"}';
77 | END IF;
78 |
79 | IF LOWER(l_datatype) <> 'json' THEN
80 | RETURN '{"status" : "E" , "message" : "Function Return Type must be json"}';
81 | END IF;
82 |
83 | IF ',' IN l_arguments THEN
84 | RETURN '{"status" : "E" , "message" : "Function Argument must contain only one argument and the datatype must be json"}';
85 | END IF;
86 |
87 |
88 | END LOOP;
89 |
90 | -- Close the cursor
91 | CLOSE functions_c;
92 |
93 | OPEN routes_c;
94 |
95 | LOOP
96 | FETCH routes_c INTO l_routes_json;
97 | -- exit when no more row to fetch
98 | EXIT WHEN NOT FOUND;
99 |
100 | l_route_name := l_routes_json->>'name';
101 | l_route_url := l_routes_json->>'route_url';
102 | l_route_method := l_routes_json->>'route_method';
103 |
104 | IF l_route_name IS NULL OR l_route_name = '' THEN
105 | RETURN '{"status" : "E" , "message" : "Route name must be provided"}';
106 | END IF;
107 |
108 | IF l_route_url IS NULL OR l_route_url = '' THEN
109 | RETURN '{"status" : "E" , "message" : "Route url must be provided"}';
110 | END IF;
111 |
112 | IF l_route_method IS NULL OR l_route_method = '' THEN
113 | RETURN '{"status" : "E" , "message" : "Route Method must be provided"}';
114 | ELSE
115 | IF l_route_method IN ('GET','POST') THEN
116 | RETURN '{"status" : "E" , "message" : "Invalid Route Method value. Only GET,POST is supported."}';
117 | END IF;
118 | END IF;
119 |
120 | l_route_id := NULL;
121 |
122 | SELECT id
123 | INTO l_route_id
124 | FROM routes
125 | WHERE name = l_route_name;
126 |
127 | IF l_route_id IS NOT NULL THEN
128 | RETURN '{"status" : "E" , "message" : "Route Name alread exist. Please use different route name ['||l_route_name||']"}';
129 | END IF;
130 |
131 | l_route_id := NULL;
132 |
133 | SELECT id
134 | INTO l_route_id
135 | FROM routes
136 | WHERE route_method = l_route_method
137 | AND route_url = l_route_url;
138 |
139 | IF l_route_id IS NOT NULL THEN
140 | RETURN '{"status" : "E" , "message" : "Route Url and the Route Method alread exist. Please use different route url or route method ['||l_route_url||','||l_route_method||']"}';
141 | END IF;
142 |
143 | SELECT
144 |
145 | END LOOP;
146 |
147 | -- Close the cursor
148 | CLOSE routes_c;
149 |
150 | l_id := md5(random()::text || clock_timestamp()::text)::uuid;
151 |
152 |
153 |
154 | RETURN '{"status" : "S" , "message" : "OK"}';
155 | END
156 | $BODY$
157 | LANGUAGE plpgsql;
158 |
159 | select install_task_demo('{"functions" : [{"name" : "sdsd"}]}')
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/dist/admin/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | pgAPI - Database as a Service
7 |
8 |
9 |
10 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/dist/admin/pgAPI-icon.5a767025.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thrinz/pgapi/e27510461c95017e357f8a46dbd76a7376ac206f/dist/admin/pgAPI-icon.5a767025.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 |
2 | /* This file is part of pgAPI.
3 | pgAPI - Database as a service
4 | Copyright (C) 2018 Praveen Muralidhar
5 |
6 | pgAPI is a free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | pgAPI is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | const path = require('path');
21 | const utils = require('./admin/Utils');
22 | const colors = require('colors');
23 | const install = require('./admin/install');
24 | const routeHandler = require('./admin/controllers/Route');
25 |
26 | const routes = () => {
27 | }
28 |
29 | const adminRouter = () => {
30 | const adminRouter = require('./admin/router');
31 | return adminRouter;
32 | }
33 |
34 | const apiRouter = (router) => {
35 | global.pool = {};
36 | global.router = router;
37 | const s = routeHandler.getRoutes();
38 | }
39 |
40 | const initialize = async (input) => {
41 | try {
42 | if (!!input && !!input.DB_HOST
43 | && !!input.DB_USER
44 | && !!input.DB_PASSWORD
45 | && !!input.DB_NAME
46 | && !!input.DB_PORT
47 | && !!input.PGAPI_SECRET_KEY
48 | ) {
49 | utils.loadRuntimeEnvVariables({
50 | DB_HOST : input.DB_HOST,
51 | DB_USER: input.DB_USER,
52 | DB_PASSWORD: input.DB_PASSWORD,
53 | DB_NAME: input.DB_NAME,
54 | DB_PORT: input.DB_PORT,
55 | PGAPI_SECRET_KEY: input.PGAPI_SECRET_KEY,
56 | DEMO_INSTALL: input.DEMO_INSTALL,
57 | SMS_PROVIDER: input.SMS_PROVIDER
58 | });
59 |
60 | // let ssl = false;
61 |
62 | // if (!!input.DB_SSL && input.DB_SSL === 'Y') {
63 | // ssl = true;
64 | // }
65 |
66 | let response = await utils.validateConnection({
67 | host : input.DB_HOST,
68 | port : input.DB_PORT,
69 | database : input.DB_NAME,
70 | username : input.DB_USER,
71 | password : input.DB_PASSWORD,
72 | });
73 |
74 | if (response.status === "E") {
75 | throw("pgAPI - failed to initialize - invalid database connection information");
76 | }
77 |
78 | await install.loadDB(true);
79 |
80 | } else {
81 | throw("pgAPI - failed to initialize - invalid input parameters");
82 | }
83 |
84 | } catch(e) {
85 | throw(e)
86 | }
87 |
88 | }
89 |
90 | const clientSourcePath = () => {
91 | return path.join(path.resolve(__dirname, './dist'));
92 | }
93 |
94 | module.exports = {
95 | routes,
96 | adminRouter,
97 | initialize,
98 | clientSourcePath,
99 | apiRouter
100 | }
101 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@thrinz/pgapi",
3 | "version": "1.0.6",
4 | "description": "pgAPI - Database as a service",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Praveen Muralidhar (thrinz@gmail.com)",
10 | "license": "GPL-3.0-or-later",
11 | "dependencies": {
12 | "axios": "^0.18.1",
13 | "babel-polyfill": "^6.26.0",
14 | "bcryptjs": "^2.4.3",
15 | "body-parser": "^1.18.3",
16 | "colors": "^1.3.2",
17 | "commander": "^2.19.0",
18 | "dotenv": "^5.0.1",
19 | "express": "^4.16.3",
20 | "find-up": "^3.0.0",
21 | "inquirer": "^6.2.0",
22 | "jsonwebtoken": "^8.3.0",
23 | "material-design-icons-iconfont": "^3.0.3",
24 | "moment": "^2.22.2",
25 | "parcel-bundler": "^1.12.3",
26 | "pg": "^8.9.0",
27 | "twilio": "^3.35.1",
28 | "uuid": "^3.3.2",
29 | "vue-highlightjs": "^1.3.3",
30 | "vue2-ace-editor": "0.0.11",
31 | "vuetify": "^1.4.0"
32 | },
33 | "devDependencies": {
34 | "@vue/component-compiler-utils": "^1.0.0",
35 | "autoprefixer": "^8.3.0",
36 | "babel-core": "^6.26.3",
37 | "babel-plugin-transform-runtime": "^6.23.0",
38 | "babel-preset-env": "^1.6.1",
39 | "nodemon": "^1.17.3",
40 | "npm-run-all": "^4.1.2",
41 | "postcss-modules": "^1.1.0",
42 | "vue": "^2.5.16",
43 | "vue-hot-reload-api": "^2.3.0",
44 | "vue-router": "^3.0.1",
45 | "vue-template-compiler": "^2.5.16",
46 | "vuex": "^3.0.1"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------