@saltcorn/data 0.5.5-beta.1 → 0.5.6-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/base-plugin/viewtemplates/edit.js +3 -0
- package/base-plugin/viewtemplates/filter.js +4 -0
- package/base-plugin/viewtemplates/show.js +9 -13
- package/base-plugin/viewtemplates/viewable_fields.js +6 -8
- package/db/state.js +16 -2
- package/migrations/202109201624.js +3 -0
- package/models/backup.js +7 -2
- package/models/pack.js +13 -3
- package/models/table.js +19 -5
- package/models/trigger.js +12 -1
- package/models/user.js +22 -17
- package/package.json +3 -3
- package/plugin-helper.js +1 -1
- package/tests/table.test.js +36 -0
|
@@ -522,6 +522,9 @@ const authorise_post = async ({ body, table_id, req }) => {
|
|
|
522
522
|
const field_name = await table.owner_fieldname();
|
|
523
523
|
return field_name && `${body[field_name]}` === `${user_id}`;
|
|
524
524
|
}
|
|
525
|
+
if (table.ownership_formula && user_id) {
|
|
526
|
+
return await table.is_owner(req.user, body);
|
|
527
|
+
}
|
|
525
528
|
if (table.name === "users" && `${body.id}` === `${user_id}`) return true;
|
|
526
529
|
return false;
|
|
527
530
|
};
|
|
@@ -103,6 +103,10 @@ const run = async (table_id, viewname, { columns, layout }, state, extra) => {
|
|
|
103
103
|
if (kpath.length === 3) {
|
|
104
104
|
const [jtNm, jFieldNm, lblField] = kpath;
|
|
105
105
|
const jtable = await Table.findOne({ name: jtNm });
|
|
106
|
+
if (!jtable)
|
|
107
|
+
throw new InvalidConfiguration(
|
|
108
|
+
`View ${viewname} incorrectly configured: cannot find join table ${jtNm}`
|
|
109
|
+
);
|
|
106
110
|
const jfields = await jtable.getFields();
|
|
107
111
|
const jfield = jfields.find((f) => f.name === lblField);
|
|
108
112
|
if (jfield)
|
|
@@ -344,6 +344,13 @@ const renderRows = async (
|
|
|
344
344
|
segment.contents = await view.run(state, extra);
|
|
345
345
|
}
|
|
346
346
|
});
|
|
347
|
+
const user_id = extra.req.user ? extra.req.user.id : null;
|
|
348
|
+
|
|
349
|
+
const is_owner =
|
|
350
|
+
table.ownership_formula && user_id
|
|
351
|
+
? await table.is_owner(extra.req.user, row)
|
|
352
|
+
: owner_field && user_id && row[owner_field] === user_id;
|
|
353
|
+
|
|
347
354
|
return render(
|
|
348
355
|
row,
|
|
349
356
|
fields,
|
|
@@ -352,7 +359,7 @@ const renderRows = async (
|
|
|
352
359
|
table,
|
|
353
360
|
role,
|
|
354
361
|
extra.req,
|
|
355
|
-
|
|
362
|
+
is_owner
|
|
356
363
|
);
|
|
357
364
|
});
|
|
358
365
|
};
|
|
@@ -393,18 +400,7 @@ const runMany = async (
|
|
|
393
400
|
return rendered.map((html, ix) => ({ html, row: rows[ix] }));
|
|
394
401
|
};
|
|
395
402
|
|
|
396
|
-
const render = (
|
|
397
|
-
row,
|
|
398
|
-
fields,
|
|
399
|
-
layout0,
|
|
400
|
-
viewname,
|
|
401
|
-
table,
|
|
402
|
-
role,
|
|
403
|
-
req,
|
|
404
|
-
owner_field
|
|
405
|
-
) => {
|
|
406
|
-
const user_id = req.user ? req.user.id : null;
|
|
407
|
-
const is_owner = owner_field && user_id && row[owner_field] === user_id;
|
|
403
|
+
const render = (row, fields, layout0, viewname, table, role, req, is_owner) => {
|
|
408
404
|
const evalMaybeExpr = (segment, key, fmlkey) => {
|
|
409
405
|
if (segment.isFormula && segment.isFormula[fmlkey || key]) {
|
|
410
406
|
const f = get_expression_function(segment[key], fields);
|
|
@@ -261,11 +261,7 @@ const get_viewable_fields = contract(
|
|
|
261
261
|
label: column.header_label ? text(__(column.header_label)) : "",
|
|
262
262
|
key: (r) => {
|
|
263
263
|
if (action_requires_write(column.action_name)) {
|
|
264
|
-
|
|
265
|
-
if (
|
|
266
|
-
table.min_role_write < role &&
|
|
267
|
-
(!owner_field || r[owner_field] !== user_id)
|
|
268
|
-
)
|
|
264
|
+
if (table.min_role_write < role && !table.is_owner(req.user, r))
|
|
269
265
|
return "";
|
|
270
266
|
}
|
|
271
267
|
const url = action_url(
|
|
@@ -524,9 +520,11 @@ const fill_presets = async (table, req, fixed) => {
|
|
|
524
520
|
if (fixed[k]) {
|
|
525
521
|
const fldnm = k.replace("preset_", "");
|
|
526
522
|
const fld = fields.find((f) => f.name === fldnm);
|
|
527
|
-
if (
|
|
528
|
-
|
|
529
|
-
|
|
523
|
+
if (fld) {
|
|
524
|
+
if (table.name === "users" && fld.primary_key)
|
|
525
|
+
fixed[fldnm] = req.user ? req.user.id : null;
|
|
526
|
+
else fixed[fldnm] = fld.presets[fixed[k]]({ user: req.user, req });
|
|
527
|
+
}
|
|
530
528
|
}
|
|
531
529
|
delete fixed[k];
|
|
532
530
|
} else {
|
package/db/state.js
CHANGED
|
@@ -46,6 +46,7 @@ class State {
|
|
|
46
46
|
this.viewtemplates = {};
|
|
47
47
|
this.tables = [];
|
|
48
48
|
this.types = {};
|
|
49
|
+
this.stashed_fieldviews = {};
|
|
49
50
|
this.files = {};
|
|
50
51
|
this.pages = [];
|
|
51
52
|
this.fields = [];
|
|
@@ -355,6 +356,10 @@ class State {
|
|
|
355
356
|
if (type) {
|
|
356
357
|
if (type.fieldviews) type.fieldviews[k] = v;
|
|
357
358
|
else type.fieldviews = { [k]: v };
|
|
359
|
+
} else {
|
|
360
|
+
if (!this.stashed_fieldviews[v.type])
|
|
361
|
+
this.stashed_fieldviews[v.type] = {};
|
|
362
|
+
this.stashed_fieldviews[v.type][k] = v;
|
|
358
363
|
}
|
|
359
364
|
});
|
|
360
365
|
const layout = withCfg("layout");
|
|
@@ -383,7 +388,13 @@ class State {
|
|
|
383
388
|
* @param t
|
|
384
389
|
*/
|
|
385
390
|
addType(t) {
|
|
386
|
-
this.types[t.name] = {
|
|
391
|
+
this.types[t.name] = {
|
|
392
|
+
...t,
|
|
393
|
+
fieldviews: {
|
|
394
|
+
...t.fieldviews,
|
|
395
|
+
...(this.stashed_fieldviews[t.name] || {}),
|
|
396
|
+
},
|
|
397
|
+
};
|
|
387
398
|
}
|
|
388
399
|
|
|
389
400
|
/**
|
|
@@ -405,6 +416,7 @@ class State {
|
|
|
405
416
|
async refresh_plugins(noSignal) {
|
|
406
417
|
this.viewtemplates = {};
|
|
407
418
|
this.types = {};
|
|
419
|
+
this.stashed_fieldviews = {};
|
|
408
420
|
this.fields = [];
|
|
409
421
|
this.fileviews = {};
|
|
410
422
|
this.actions = {};
|
|
@@ -431,7 +443,9 @@ class State {
|
|
|
431
443
|
this.pages.forEach((p) => strings.push(...p.getStringsForI18n()));
|
|
432
444
|
const menu = this.getConfig("menu_items", []);
|
|
433
445
|
strings.push(...menu.map(({ label }) => label));
|
|
434
|
-
return Array.from(new Set(strings)).filter(
|
|
446
|
+
return Array.from(new Set(strings)).filter(
|
|
447
|
+
(s) => s && removeAllWhiteSpace(s)
|
|
448
|
+
);
|
|
435
449
|
}
|
|
436
450
|
|
|
437
451
|
setRoomEmitter(f) {
|
package/models/backup.js
CHANGED
|
@@ -6,6 +6,7 @@ const View = require("./view");
|
|
|
6
6
|
const File = require("./file");
|
|
7
7
|
const Plugin = require("./plugin");
|
|
8
8
|
const User = require("./user");
|
|
9
|
+
const Role = require("./role");
|
|
9
10
|
const Page = require("./page");
|
|
10
11
|
const Zip = require("adm-zip");
|
|
11
12
|
const tmp = require("tmp-promise");
|
|
@@ -26,6 +27,7 @@ const {
|
|
|
26
27
|
const { is_plugin } = require("../contracts");
|
|
27
28
|
|
|
28
29
|
const { asyncMap } = require("../utils");
|
|
30
|
+
const Trigger = require("./trigger");
|
|
29
31
|
|
|
30
32
|
const create_pack = contract(
|
|
31
33
|
is.fun(is.str, is.promise(is.undefined)),
|
|
@@ -46,7 +48,9 @@ const create_pack = contract(
|
|
|
46
48
|
await Page.find({}),
|
|
47
49
|
async (v) => await page_pack(v.name)
|
|
48
50
|
);
|
|
49
|
-
|
|
51
|
+
const triggers = (await Trigger.find({})).map((tr) => tr.toJson);
|
|
52
|
+
const roles = await Role.find({});
|
|
53
|
+
var pack = { tables, views, plugins, pages, triggers, roles };
|
|
50
54
|
|
|
51
55
|
await fs.writeFile(path.join(dirpath, "pack.json"), JSON.stringify(pack));
|
|
52
56
|
}
|
|
@@ -175,7 +179,8 @@ const restore_files = contract(
|
|
|
175
179
|
//set location
|
|
176
180
|
file.location = newPath;
|
|
177
181
|
//insert in db
|
|
178
|
-
|
|
182
|
+
const { user_id, ...file_row } = file;
|
|
183
|
+
await db.insert("_sc_files", file_row);
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
186
|
}
|
package/models/pack.js
CHANGED
|
@@ -10,6 +10,8 @@ const { contract, is } = require("contractis");
|
|
|
10
10
|
const Page = require("./page");
|
|
11
11
|
const { is_pack, is_plugin } = require("../contracts");
|
|
12
12
|
const TableConstraint = require("./table_constraints");
|
|
13
|
+
const { tr } = require("@saltcorn/markup/tags");
|
|
14
|
+
const Role = require("./role");
|
|
13
15
|
|
|
14
16
|
const pack_fun = is.fun(is.str, is.promise(is.obj()));
|
|
15
17
|
|
|
@@ -21,7 +23,7 @@ const table_pack = contract(pack_fun, async (name) => {
|
|
|
21
23
|
delete o.table_id;
|
|
22
24
|
return o;
|
|
23
25
|
};
|
|
24
|
-
const triggers = await Trigger.find({ table_id: table.id });
|
|
26
|
+
//const triggers = await Trigger.find({ table_id: table.id });
|
|
25
27
|
const constraints = await TableConstraint.find({ table_id: table.id });
|
|
26
28
|
|
|
27
29
|
return {
|
|
@@ -29,8 +31,9 @@ const table_pack = contract(pack_fun, async (name) => {
|
|
|
29
31
|
min_role_read: table.min_role_read,
|
|
30
32
|
min_role_write: table.min_role_write,
|
|
31
33
|
versioned: table.versioned,
|
|
34
|
+
ownership_formula: table.ownership_formula,
|
|
32
35
|
fields: fields.map((f) => strip_ids(f.toJson)),
|
|
33
|
-
triggers: triggers.map((tr) => tr.toJson),
|
|
36
|
+
//triggers: triggers.map((tr) => tr.toJson),
|
|
34
37
|
constraints: constraints.map((c) => c.toJson),
|
|
35
38
|
ownership_field_name: table.owner_fieldname_from_fields(fields),
|
|
36
39
|
};
|
|
@@ -200,6 +203,9 @@ const install_pack = contract(
|
|
|
200
203
|
await loadAndSaveNewPlugin(p);
|
|
201
204
|
}
|
|
202
205
|
}
|
|
206
|
+
for (const role of pack.roles || []) {
|
|
207
|
+
await Role.create(role);
|
|
208
|
+
}
|
|
203
209
|
for (const tableSpec of pack.tables) {
|
|
204
210
|
if (tableSpec.name !== "users") {
|
|
205
211
|
const table = await Table.create(tableSpec.name, tableSpec);
|
|
@@ -226,7 +232,7 @@ const install_pack = contract(
|
|
|
226
232
|
}
|
|
227
233
|
}
|
|
228
234
|
for (const trigger of tableSpec.triggers || [])
|
|
229
|
-
await Trigger.create({ table, ...trigger });
|
|
235
|
+
await Trigger.create({ table, ...trigger }); //legacy, not in new packs
|
|
230
236
|
for (const constraint of tableSpec.constraints || [])
|
|
231
237
|
await TableConstraint.create({ table, ...constraint });
|
|
232
238
|
if (tableSpec.ownership_field_name) {
|
|
@@ -258,6 +264,10 @@ const install_pack = contract(
|
|
|
258
264
|
min_role: viewSpec.min_role || 10,
|
|
259
265
|
});
|
|
260
266
|
}
|
|
267
|
+
for (const triggerSpec of pack.triggers || []) {
|
|
268
|
+
await Trigger.create(triggerSpec);
|
|
269
|
+
}
|
|
270
|
+
|
|
261
271
|
for (const pageFullSpec of pack.pages || []) {
|
|
262
272
|
const { root_page_for_roles, menu_label, ...pageSpec } = pageFullSpec;
|
|
263
273
|
await Page.create(pageSpec);
|
package/models/table.js
CHANGED
|
@@ -10,6 +10,7 @@ const {
|
|
|
10
10
|
apply_calculated_fields,
|
|
11
11
|
apply_calculated_fields_stored,
|
|
12
12
|
recalculate_for_stored,
|
|
13
|
+
get_expression_function,
|
|
13
14
|
} = require("./expression");
|
|
14
15
|
const { contract, is } = require("contractis");
|
|
15
16
|
const { is_table_query } = require("../contracts");
|
|
@@ -87,6 +88,7 @@ class Table {
|
|
|
87
88
|
this.min_role_read = o.min_role_read;
|
|
88
89
|
this.min_role_write = o.min_role_write;
|
|
89
90
|
this.ownership_field_id = o.ownership_field_id;
|
|
91
|
+
this.ownership_formula = o.ownership_formula;
|
|
90
92
|
this.versioned = !!o.versioned;
|
|
91
93
|
this.external = false;
|
|
92
94
|
this.description = o.description;
|
|
@@ -178,11 +180,10 @@ class Table {
|
|
|
178
180
|
* Get owner column name
|
|
179
181
|
* @returns {Promise<string|null|*>}
|
|
180
182
|
*/
|
|
181
|
-
|
|
183
|
+
owner_fieldname() {
|
|
182
184
|
if (this.name === "users") return "id";
|
|
183
185
|
if (!this.ownership_field_id) return null;
|
|
184
|
-
|
|
185
|
-
return this.owner_fieldname_from_fields(fields);
|
|
186
|
+
return this.owner_fieldname_from_fields(this.fields);
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
/**
|
|
@@ -191,9 +192,13 @@ class Table {
|
|
|
191
192
|
* @param row - table row
|
|
192
193
|
* @returns {Promise<string|null|*|boolean>}
|
|
193
194
|
*/
|
|
194
|
-
|
|
195
|
+
is_owner(user, row) {
|
|
195
196
|
if (!user) return false;
|
|
196
|
-
|
|
197
|
+
if (this.ownership_formula) {
|
|
198
|
+
const f = get_expression_function(this.ownership_formula, this.fields);
|
|
199
|
+
return f(row, user);
|
|
200
|
+
}
|
|
201
|
+
const field_name = this.owner_fieldname();
|
|
197
202
|
return field_name && row[field_name] === user.id;
|
|
198
203
|
}
|
|
199
204
|
|
|
@@ -218,6 +223,7 @@ class Table {
|
|
|
218
223
|
min_role_read: options.min_role_read || 1,
|
|
219
224
|
min_role_write: options.min_role_write || 1,
|
|
220
225
|
ownership_field_id: options.ownership_field_id,
|
|
226
|
+
ownership_formula: options.ownership_formula,
|
|
221
227
|
description: options.description || "",
|
|
222
228
|
};
|
|
223
229
|
// insert table defintion into _sc_tables
|
|
@@ -990,10 +996,18 @@ class Table {
|
|
|
990
996
|
const throughTable = await Table.findOne({
|
|
991
997
|
name: reffield.reftable_name,
|
|
992
998
|
});
|
|
999
|
+
if (!throughTable)
|
|
1000
|
+
throw new InvalidConfiguration(
|
|
1001
|
+
`Join-through table ${reffield.reftable_name} not found`
|
|
1002
|
+
);
|
|
993
1003
|
const throughTableFields = await throughTable.getFields();
|
|
994
1004
|
const throughRefField = throughTableFields.find(
|
|
995
1005
|
(f) => f.name === through
|
|
996
1006
|
);
|
|
1007
|
+
if (!throughRefField)
|
|
1008
|
+
throw new InvalidConfiguration(
|
|
1009
|
+
`Reference field field ${through} not found in table ${throughTable.name}`
|
|
1010
|
+
);
|
|
997
1011
|
const finalTable = throughRefField.reftable_name;
|
|
998
1012
|
const jtNm1 = `${sqlsanitize(reftable)}_jt_${sqlsanitize(
|
|
999
1013
|
through
|
package/models/trigger.js
CHANGED
|
@@ -39,13 +39,19 @@ class Trigger {
|
|
|
39
39
|
* @returns {{when_trigger, configuration: any, name, description, action}}
|
|
40
40
|
*/
|
|
41
41
|
get toJson() {
|
|
42
|
+
let table_name = this.table_name;
|
|
43
|
+
if (!table_name && this.table_id) {
|
|
44
|
+
const Table = require("./table");
|
|
45
|
+
const table = Table.find(+this.table_id);
|
|
46
|
+
table_name = table.name;
|
|
47
|
+
}
|
|
42
48
|
return {
|
|
43
49
|
name: this.name,
|
|
44
50
|
description: this.description,
|
|
45
51
|
action: this.action,
|
|
46
52
|
when_trigger: this.when_trigger,
|
|
47
53
|
configuration: this.configuration,
|
|
48
|
-
|
|
54
|
+
table_name,
|
|
49
55
|
channel: this.channel,
|
|
50
56
|
min_role: this.min_role,
|
|
51
57
|
};
|
|
@@ -116,6 +122,11 @@ class Trigger {
|
|
|
116
122
|
static async create(f) {
|
|
117
123
|
const trigger = new Trigger(f);
|
|
118
124
|
const { id, table_name, ...rest } = trigger;
|
|
125
|
+
if (table_name && !rest.table_id) {
|
|
126
|
+
const Table = require("./table");
|
|
127
|
+
const table = Table.find(table_name);
|
|
128
|
+
rest.table_id = table.id;
|
|
129
|
+
}
|
|
119
130
|
const fid = await db.insert("_sc_triggers", rest);
|
|
120
131
|
trigger.id = fid;
|
|
121
132
|
await require("../db/state").getState().refresh_triggers();
|
package/models/user.js
CHANGED
|
@@ -5,6 +5,24 @@ const { v4: uuidv4 } = require("uuid");
|
|
|
5
5
|
const dumbPasswords = require("dumb-passwords");
|
|
6
6
|
const validator = require("email-validator");
|
|
7
7
|
|
|
8
|
+
const safeUserFields = (o) => {
|
|
9
|
+
const {
|
|
10
|
+
email,
|
|
11
|
+
password,
|
|
12
|
+
language,
|
|
13
|
+
_attributes,
|
|
14
|
+
api_token,
|
|
15
|
+
verification_token,
|
|
16
|
+
verified_on,
|
|
17
|
+
disabled,
|
|
18
|
+
id,
|
|
19
|
+
reset_password_token,
|
|
20
|
+
reset_password_expiry,
|
|
21
|
+
role_id,
|
|
22
|
+
...rest
|
|
23
|
+
} = o;
|
|
24
|
+
return rest;
|
|
25
|
+
};
|
|
8
26
|
/**
|
|
9
27
|
* User
|
|
10
28
|
*/
|
|
@@ -33,22 +51,7 @@ class User {
|
|
|
33
51
|
: o.reset_password_expiry || null;
|
|
34
52
|
this.role_id = o.role_id ? +o.role_id : 8;
|
|
35
53
|
|
|
36
|
-
|
|
37
|
-
email,
|
|
38
|
-
password,
|
|
39
|
-
language,
|
|
40
|
-
_attributes,
|
|
41
|
-
api_token,
|
|
42
|
-
verification_token,
|
|
43
|
-
verified_on,
|
|
44
|
-
disabled,
|
|
45
|
-
id,
|
|
46
|
-
reset_password_token,
|
|
47
|
-
reset_password_expiry,
|
|
48
|
-
role_id,
|
|
49
|
-
...rest
|
|
50
|
-
} = o;
|
|
51
|
-
Object.assign(this, rest);
|
|
54
|
+
Object.assign(this, safeUserFields(o));
|
|
52
55
|
|
|
53
56
|
contract.class(this);
|
|
54
57
|
}
|
|
@@ -149,13 +152,15 @@ class User {
|
|
|
149
152
|
* @returns {{role_id: number, language, id, email, tenant: *}}
|
|
150
153
|
*/
|
|
151
154
|
get session_object() {
|
|
152
|
-
|
|
155
|
+
const so = {
|
|
153
156
|
email: this.email,
|
|
154
157
|
id: this.id,
|
|
155
158
|
role_id: this.role_id,
|
|
156
159
|
language: this.language,
|
|
157
160
|
tenant: db.getTenantSchema(),
|
|
158
161
|
};
|
|
162
|
+
Object.assign(so, safeUserFields(this));
|
|
163
|
+
return so;
|
|
159
164
|
}
|
|
160
165
|
|
|
161
166
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/data",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6-beta.2",
|
|
4
4
|
"description": "Data models for Saltcorn, open-source no-code platform",
|
|
5
5
|
"homepage": "https://saltcorn.com",
|
|
6
6
|
"scripts": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"main": "index.js",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@saltcorn/markup": "0.5.
|
|
13
|
+
"@saltcorn/markup": "0.5.6-beta.2",
|
|
14
14
|
"acorn": "^8.0.3",
|
|
15
15
|
"adm-zip": "0.5.5",
|
|
16
16
|
"astring": "^1.4.3",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"latest-version": "^5.1.0",
|
|
31
31
|
"moment": "^2.27.0",
|
|
32
32
|
"moment-timezone": "^0.5.33",
|
|
33
|
-
"node-fetch": "
|
|
33
|
+
"node-fetch": "2.6.2",
|
|
34
34
|
"nodemailer": "^6.4.17",
|
|
35
35
|
"pg": "^8.2.1",
|
|
36
36
|
"pg-copy-streams": "^5.1.1",
|
package/plugin-helper.js
CHANGED
|
@@ -891,7 +891,7 @@ const stateFieldsToWhere = contract(
|
|
|
891
891
|
if (kpath.length === 3) {
|
|
892
892
|
const [jtNm, jFieldNm, lblField] = kpath;
|
|
893
893
|
qstate.id = [
|
|
894
|
-
...(qstate.id
|
|
894
|
+
...(qstate.id ? [qstate.id] : []),
|
|
895
895
|
{
|
|
896
896
|
// where id in (select jFieldNm from jtnm where lblField=v)
|
|
897
897
|
inSelect: {
|
package/tests/table.test.js
CHANGED
|
@@ -882,6 +882,42 @@ describe("Table with row ownership", () => {
|
|
|
882
882
|
await persons.delete();
|
|
883
883
|
});
|
|
884
884
|
});
|
|
885
|
+
describe("Table with row ownership", () => {
|
|
886
|
+
it("should create and delete table", async () => {
|
|
887
|
+
const persons = await Table.create("TableOwnedFml");
|
|
888
|
+
const name = await Field.create({
|
|
889
|
+
table: persons,
|
|
890
|
+
name: "name",
|
|
891
|
+
type: "String",
|
|
892
|
+
});
|
|
893
|
+
const age = await Field.create({
|
|
894
|
+
table: persons,
|
|
895
|
+
name: "age",
|
|
896
|
+
type: "String",
|
|
897
|
+
});
|
|
898
|
+
const owner = await Field.create({
|
|
899
|
+
table: persons,
|
|
900
|
+
name: "owner",
|
|
901
|
+
type: "Key to users",
|
|
902
|
+
});
|
|
903
|
+
await persons.update({ ownership_formula: "user.id===owner" });
|
|
904
|
+
if (!db.isSQLite) {
|
|
905
|
+
await age.update({ type: "Integer" });
|
|
906
|
+
await name.update({ name: "lastname" });
|
|
907
|
+
await persons.insertRow({ lastname: "Joe", age: 12 });
|
|
908
|
+
await persons.insertRow({ lastname: "Sam", age: 13, owner: 1 });
|
|
909
|
+
const row = await persons.getRow({ age: 12 });
|
|
910
|
+
expect(row.lastname).toBe("Joe");
|
|
911
|
+
expect(row.age).toBe(12);
|
|
912
|
+
const is_owner = await persons.is_owner({ id: 6 }, row);
|
|
913
|
+
expect(is_owner).toBe(false);
|
|
914
|
+
const row1 = await persons.getRow({ age: 13 });
|
|
915
|
+
const is_owner1 = await persons.is_owner({ id: 1 }, row1);
|
|
916
|
+
expect(is_owner1).toBe(true);
|
|
917
|
+
}
|
|
918
|
+
await persons.delete();
|
|
919
|
+
});
|
|
920
|
+
});
|
|
885
921
|
describe("Table with UUID pks", () => {
|
|
886
922
|
if (!db.isSQLite) {
|
|
887
923
|
it("should select uuid", async () => {
|