Summary: Adds preferences to orgs. There are a few flavors: * `userOrgPrefs`: these are specific to a certain user and a certain org. * `orgPrefs`: these are specific to a certain org, and apply to all users. * `userPrefs`: these are specific to a certain user, and apply to all orgs. The three flavors of prefs are reported by `GET` for an org, and can be modified by `PATCH` for an org. The user needs to have UPDATE rights to change `orgPrefs`, but can change `userOrgPrefs` and `userPrefs` without that right since the settings only affect themselves. Test Plan: added tests Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D2572pull/4/head
parent
30866c6c95
commit
6b24d496db
@ -0,0 +1,9 @@
|
||||
// A collection of preferences related to a user or org (or combination).
|
||||
export interface Prefs {
|
||||
// TODO replace this with real preferences.
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export type UserPrefs = Prefs;
|
||||
export type UserOrgPrefs = Prefs;
|
||||
export type OrgPrefs = Prefs;
|
@ -0,0 +1,31 @@
|
||||
import {Prefs} from 'app/common/Prefs';
|
||||
import {Organization} from 'app/gen-server/entity/Organization';
|
||||
import {User} from 'app/gen-server/entity/User';
|
||||
import {nativeValues} from 'app/gen-server/lib/values';
|
||||
import {Column, Entity, JoinColumn, ManyToOne, PrimaryColumn} from 'typeorm';
|
||||
|
||||
@Entity({name: 'prefs'})
|
||||
export class Pref {
|
||||
// This table may refer to users and/or orgs.
|
||||
// We pretend userId/orgId are the primary key since TypeORM insists on having
|
||||
// one, but we haven't marked them as so in the DB since the SQL standard frowns
|
||||
// on nullable primary keys (and Postgres doesn't support them). We could add
|
||||
// another primary key, but we don't actually need one.
|
||||
@PrimaryColumn({name: 'user_id'})
|
||||
public userId: number|null;
|
||||
|
||||
@PrimaryColumn({name: 'org_id'})
|
||||
public orgId: number|null;
|
||||
|
||||
@ManyToOne(type => User)
|
||||
@JoinColumn({name: 'user_id'})
|
||||
public user?: User;
|
||||
|
||||
@ManyToOne(type => Organization)
|
||||
@JoinColumn({name: 'org_id'})
|
||||
public org?: Organization;
|
||||
|
||||
// Finally, the actual preferences, in JSON.
|
||||
@Column({type: nativeValues.jsonEntityType})
|
||||
public prefs: Prefs;
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
import {nativeValues} from 'app/gen-server/lib/values';
|
||||
import {MigrationInterface, QueryRunner, Table} from 'typeorm';
|
||||
|
||||
export class Prefs1596456522124 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.createTable(new Table({
|
||||
name: 'prefs',
|
||||
columns: [
|
||||
{
|
||||
name: 'org_id',
|
||||
type: 'integer',
|
||||
isNullable: true,
|
||||
},
|
||||
{
|
||||
name: 'user_id',
|
||||
type: 'integer',
|
||||
isNullable: true,
|
||||
},
|
||||
{
|
||||
name: 'prefs',
|
||||
type: nativeValues.jsonType
|
||||
}
|
||||
],
|
||||
foreignKeys: [
|
||||
{
|
||||
columnNames: ['org_id'],
|
||||
referencedColumnNames: ['id'],
|
||||
referencedTableName: 'orgs',
|
||||
onDelete: 'CASCADE' // delete pref if linked to org that is deleted
|
||||
},
|
||||
{
|
||||
columnNames: ['user_id'],
|
||||
referencedColumnNames: ['id'],
|
||||
referencedTableName: 'users',
|
||||
onDelete: 'CASCADE' // delete pref if linked to user that is deleted
|
||||
},
|
||||
],
|
||||
indices: [
|
||||
{ columnNames: ['org_id', 'user_id'] },
|
||||
{ columnNames: ['user_id'] },
|
||||
],
|
||||
checks: [
|
||||
// Make sure pref refers to something, either a user or an org or both
|
||||
{
|
||||
columnNames: ['user_id', 'org_id'],
|
||||
expression: 'COALESCE(user_id, org_id) IS NOT NULL'
|
||||
},
|
||||
]
|
||||
}));
|
||||
// Having trouble convincing TypeORM to create an index on expressions.
|
||||
// Luckily, the SQL is identical for Sqlite and Postgres:
|
||||
await queryRunner.manager.query(
|
||||
'CREATE UNIQUE INDEX "prefs__user_id__org_id" ON "prefs" ' +
|
||||
'(COALESCE(user_id,0), COALESCE(org_id,0))'
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||
await queryRunner.dropTable('prefs');
|
||||
}
|
||||
}
|
Loading…
Reference in new issue