feat(companysetting): add writeonly column and mask values for GUI
This commit is contained in:
@@ -16,23 +16,24 @@ Returns a single company setting by key for the user's selected company.
|
||||
| `key` | `string` | The setting key. |
|
||||
| `[options]` | `object` | Optional options. |
|
||||
| `[options.frontendOnly]` | `boolean` | Only return the setting if it is frontend-visible. |
|
||||
| `[options.maskWriteonly]` | `boolean` | Mask writeonly settings as '***'. Defaults to `frontendOnly` (usergui gets '***', backend gets full value). |
|
||||
|
||||
**Returns**
|
||||
|
||||
`Promise<{key: string, value: string, frontend: boolean}|undefined>` — The setting, or `undefined` if not found.
|
||||
`Promise<{key: string, value: string, frontend: boolean, writeonly: boolean}|undefined>` — The setting, or `undefined` if not found.
|
||||
|
||||
**Example**
|
||||
|
||||
```js
|
||||
const setting = await store.companysetting.get(42, 'theme');
|
||||
// => { key, value, frontend }
|
||||
const setting = await store.companysetting.get(42, 'ui.theme');
|
||||
// => { key, value, frontend, writeonly }
|
||||
```
|
||||
|
||||
## `companysetting.list`
|
||||
|
||||
*Source: `src/store/companysetting/list.js`*
|
||||
|
||||
Lists the settings of the user's selected company, optionally only frontend-visible ones.
|
||||
Lists the settings of the user's selected company, optionally only frontend-visible ones. Write-only settings (such as `keys.tavily`, `keys.openrouter`) have their value masked with `'***'` by default for usergui presentation.
|
||||
|
||||
**Parameters**
|
||||
|
||||
@@ -41,23 +42,24 @@ Lists the settings of the user's selected company, optionally only frontend-visi
|
||||
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||
| `[options]` | `object` | Optional options. |
|
||||
| `[options.frontendOnly]` | `boolean` | Only return frontend-visible settings. |
|
||||
| `[options.maskWriteonly]` | `boolean` | Whether to mask writeonly settings with '***'. Defaults to `true`. |
|
||||
|
||||
**Returns**
|
||||
|
||||
`Promise<Array<{key: string, value: string, frontend: boolean}>>` — The settings.
|
||||
`Promise<Array<{key: string, value: string, frontend: boolean, writeonly: boolean}>>` — The settings.
|
||||
|
||||
**Example**
|
||||
|
||||
```js
|
||||
const settings = await store.companysetting.list(42, { frontendOnly: true });
|
||||
// => [{ key, value, frontend }]
|
||||
// => [{ key, value, frontend, writeonly }]
|
||||
```
|
||||
|
||||
## `companysetting.set`
|
||||
|
||||
*Source: `src/store/companysetting/set.js`*
|
||||
|
||||
Sets (upserts) a company setting by key for the user's selected company. Only a fixed allow-list of keys can be set: `ui.theme`, `keys.tavily`, `keys.openrouter`, `labelprinter.addr`, `labelprinter.type`.
|
||||
Sets (upserts) a company setting by key for the user's selected company. Only a fixed allow-list of keys can be set: `ui.theme`, `keys.tavily`, `keys.openrouter`, `labelprinter.addr`, `labelprinter.type`. Keys in the write-only set (`keys.tavily`, `keys.openrouter`) are stored with `writeonly = 1`; when retrieved by the GUI the value is returned as `"***"`. The backend always receives the real value.
|
||||
|
||||
**Parameters**
|
||||
|
||||
@@ -68,10 +70,11 @@ Sets (upserts) a company setting by key for the user's selected company. Only a
|
||||
| `input.key` | `string` | The setting key (must be in the allow-list). |
|
||||
| `input.value` | `string` | The setting value. |
|
||||
| `[input.frontend]` | `boolean` | Whether the setting is frontend-visible. |
|
||||
| `[input.writeonly]` | `boolean` | Whether the setting is write-only. Defaults to true for `keys.tavily` and `keys.openrouter`, false otherwise. |
|
||||
|
||||
**Returns**
|
||||
|
||||
`Promise<{key: string, value: string, frontend: boolean}>` — The upserted setting.
|
||||
`Promise<{key: string, value: string, frontend: boolean, writeonly: boolean}>` — The upserted setting.
|
||||
|
||||
**Throws**
|
||||
|
||||
@@ -81,5 +84,5 @@ Sets (upserts) a company setting by key for the user's selected company. Only a
|
||||
|
||||
```js
|
||||
const setting = await store.companysetting.set(42, { key: 'ui.theme', value: 'dark' });
|
||||
// => { key, value, frontend }
|
||||
// => { key, value, frontend, writeonly }
|
||||
```
|
||||
|
||||
12
README.md
12
README.md
@@ -160,13 +160,15 @@ Company-scoped key/value settings. Auth via selected company (`google_auth.selec
|
||||
|
||||
| Method | Signature | Returns |
|
||||
| --- | --- | --- |
|
||||
| `list` | `(googleAuthId, { frontendOnly? })` | `{ key, value, frontend }[]` |
|
||||
| `get` | `(googleAuthId, key, { frontendOnly? })` | `{ key, value, frontend } \| undefined` |
|
||||
| `set` | `(googleAuthId, { key, value, frontend? })` | `{ key, value, frontend }` |
|
||||
| `list` | `(googleAuthId, { frontendOnly?, maskWriteonly? })` | `{ key, value, frontend, writeonly }[]` |
|
||||
| `get` | `(googleAuthId, key, { frontendOnly?, maskWriteonly? })` | `{ key, value, frontend, writeonly } \| undefined` |
|
||||
| `set` | `(googleAuthId, { key, value, frontend?, writeonly? })` | `{ key, value, frontend, writeonly }` |
|
||||
|
||||
- `value` is always a string (`NVARCHAR(MAX)`).
|
||||
- `frontend: true` → readable by frontend routes (`frontendOnly: true`). Default on `set` is `false` (backend-only).
|
||||
- With `frontendOnly: true`, backend-only keys are omitted / `get` returns `undefined` (no leak via error type beyond missing).
|
||||
- `writeonly: true` → usergui gets a `"***"` scrambled version when retrieving the key (in `list`, or in `get` when `maskWriteonly` is enabled / `frontendOnly: true`). The backend receives the full value.
|
||||
- `keys.tavily` and `keys.openrouter` default to `writeonly: true` on `set`.
|
||||
- `set` only allows a fixed allow-list of keys: `ui.theme`, `keys.tavily`, `keys.openrouter`, `labelprinter.addr`, `labelprinter.type`.
|
||||
- No delete endpoint — settings are upsert / read only.
|
||||
|
||||
@@ -295,8 +297,8 @@ Maps articles to suppliers (`entity`) with purchase pricing, stock, packaging un
|
||||
| `article_id` | `INT` | FK → `article(id)` (`ON DELETE CASCADE`) |
|
||||
| `entity_id` | `INT` | FK → `entity(id)` (`ON DELETE CASCADE`) |
|
||||
| `price_id` | `INT` | FK → `price(id)` (`ON DELETE NO ACTION`), nullable |
|
||||
| `SupplierSKU` | `NVARCHAR(100)` | Supplier's SKU code, nullable |
|
||||
| `SupplierStock` | `FLOAT` | Stock available at supplier, nullable |
|
||||
| `supplierSKU` | `NVARCHAR(100)` | Supplier's SKU code, nullable |
|
||||
| `supplierStock` | `FLOAT` | Stock available at supplier, nullable |
|
||||
| `pu` | `FLOAT` | Packaging unit (Verpackungseinheit), default `1` |
|
||||
|
||||
---
|
||||
|
||||
@@ -19,7 +19,7 @@ digraph schema {
|
||||
entitycontact [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>entitycontact</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="contacttype" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">contacttype</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="contact" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">contact</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sort" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
syncpos [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>syncpos</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="paircode" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">paircode</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="token" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">token?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
entityhistory [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>entityhistory</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="companyuser_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>companyuser_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="date" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">date</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="text" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">text</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
companysetting [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>companysetting</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="key" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">key</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="value" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">value</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="frontend" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">frontend</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">BIT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
companysetting [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>companysetting</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="key" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">key</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="value" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">value</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="frontend" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">frontend</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">BIT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="writeonly" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">writeonly</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">BIT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
google_auth [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#33415c" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="1" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>google_auth</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="selected_company" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>selected_company</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="email" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">email</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(320)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="picture" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">picture?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(2048)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="picturebinary" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">picturebinary?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">VARBINARY(MAX)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sub" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">sub?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="created_at" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">created_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
}
|
||||
subgraph cluster_i18n {
|
||||
@@ -43,7 +43,7 @@ digraph schema {
|
||||
articleean [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>articleean</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="article_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>article_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="ean" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">ean</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
articlelist [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#33415c" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#33415c" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="2" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>articlelist</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
articlelistarticle [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>articlelistarticle</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="article_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>article_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="articlelist_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>articlelist_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="count" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">count</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sort" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
articlesupplier [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>articlesupplier</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="price_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>price_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="article_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>article_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="SupplierSKU" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">SupplierSKU?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="SupplierStock" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">SupplierStock?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="pu" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">pu</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
articlesupplier [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>articlesupplier</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="price_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>price_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="article_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>article_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="SupplierSKU" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">SupplierSKU?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="supplierStock" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">supplierStock?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="pu" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">pu</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">FLOAT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
optionslist [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#33415c" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#33415c" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="2" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>optionslist</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
optionslistarticle [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#3f4c5f"><TR><TD COLSPAN="2" BGCOLOR="#33415c" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#e2e8f0" POINT-SIZE="12"><B>optionslistarticle</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="article_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>article_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="optionslist_id" COLSPAN="2" BGCOLOR="#2b3a52" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9"><B>optionslist_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="count" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">count</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sort" COLSPAN="2" BGCOLOR="#2a3242" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="mandated" COLSPAN="2" BGCOLOR="#272e3d" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#d8dee9">mandated</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#8b95a7" POINT-SIZE="9">BIT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||
}
|
||||
|
||||
@@ -641,38 +641,42 @@
|
||||
<!-- companysetting -->
|
||||
<g id="node11" class="node">
|
||||
<title>companysetting</title>
|
||||
<polygon fill="#33415c" stroke="none" points="4140.66,-673.6 4140.66,-698 4269.34,-698 4269.34,-673.6 4140.66,-673.6"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-673.6 4140.66,-698 4269.34,-698 4269.34,-673.6 4140.66,-673.6"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4158.99" y="-683.2" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="12.00" fill="#e2e8f0">companysetting</text>
|
||||
<polygon fill="#2b3a52" stroke="none" points="4140.66,-646.8 4140.66,-673.6 4269.34,-673.6 4269.34,-646.8 4140.66,-646.8"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-646.8 4140.66,-673.6 4269.34,-673.6 4269.34,-646.8 4140.66,-646.8"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-657" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#d8dee9">id</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4234.84" y="-658.5" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">INT </text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4251.84" y="-658.5" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#8b95a7">PK</text>
|
||||
<polygon fill="#2b3a52" stroke="none" points="4140.66,-620 4140.66,-646.8 4269.34,-646.8 4269.34,-620 4140.66,-620"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-620 4140.66,-646.8 4269.34,-646.8 4269.34,-620 4140.66,-620"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-630.2" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#d8dee9">company_id</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4235.35" y="-631.7" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">INT </text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4252.35" y="-631.7" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#8b95a7">FK</text>
|
||||
<polygon fill="#2a3242" stroke="none" points="4140.66,-593.2 4140.66,-620 4269.34,-620 4269.34,-593.2 4140.66,-593.2"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-593.2 4140.66,-620 4269.34,-620 4269.34,-593.2 4140.66,-593.2"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-601" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#d8dee9">key</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4192.83" y="-603" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">NVARCHAR(255)</text>
|
||||
<polygon fill="#272e3d" stroke="none" points="4140.66,-566.4 4140.66,-593.2 4269.34,-593.2 4269.34,-566.4 4140.66,-566.4"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-566.4 4140.66,-593.2 4269.34,-593.2 4269.34,-566.4 4140.66,-566.4"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-574.2" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#d8dee9">value</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4188.34" y="-576.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">NVARCHAR(MAX)</text>
|
||||
<polygon fill="#2a3242" stroke="none" points="4140.66,-539.6 4140.66,-566.4 4269.34,-566.4 4269.34,-539.6 4140.66,-539.6"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-539.6 4140.66,-566.4 4269.34,-566.4 4269.34,-539.6 4140.66,-539.6"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-547.4" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#d8dee9">frontend</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4250.34" y="-549.4" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">BIT</text>
|
||||
<polygon fill="#33415c" stroke="none" points="4140.66,-687 4140.66,-711.4 4269.34,-711.4 4269.34,-687 4140.66,-687"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-687 4140.66,-711.4 4269.34,-711.4 4269.34,-687 4140.66,-687"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4158.99" y="-696.6" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="12.00" fill="#e2e8f0">companysetting</text>
|
||||
<polygon fill="#2b3a52" stroke="none" points="4140.66,-660.2 4140.66,-687 4269.34,-687 4269.34,-660.2 4140.66,-660.2"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-660.2 4140.66,-687 4269.34,-687 4269.34,-660.2 4140.66,-660.2"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-670.4" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#d8dee9">id</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4234.84" y="-671.9" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">INT </text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4251.84" y="-671.9" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#8b95a7">PK</text>
|
||||
<polygon fill="#2b3a52" stroke="none" points="4140.66,-633.4 4140.66,-660.2 4269.34,-660.2 4269.34,-633.4 4140.66,-633.4"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-633.4 4140.66,-660.2 4269.34,-660.2 4269.34,-633.4 4140.66,-633.4"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-643.6" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#d8dee9">company_id</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4235.35" y="-645.1" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">INT </text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4252.35" y="-645.1" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#8b95a7">FK</text>
|
||||
<polygon fill="#2a3242" stroke="none" points="4140.66,-606.6 4140.66,-633.4 4269.34,-633.4 4269.34,-606.6 4140.66,-606.6"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-606.6 4140.66,-633.4 4269.34,-633.4 4269.34,-606.6 4140.66,-606.6"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-614.4" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#d8dee9">key</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4192.83" y="-616.4" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">NVARCHAR(255)</text>
|
||||
<polygon fill="#272e3d" stroke="none" points="4140.66,-579.8 4140.66,-606.6 4269.34,-606.6 4269.34,-579.8 4140.66,-579.8"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-579.8 4140.66,-606.6 4269.34,-606.6 4269.34,-579.8 4140.66,-579.8"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-587.6" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#d8dee9">value</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4188.34" y="-589.6" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">NVARCHAR(MAX)</text>
|
||||
<polygon fill="#2a3242" stroke="none" points="4140.66,-553 4140.66,-579.8 4269.34,-579.8 4269.34,-553 4140.66,-553"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-553 4140.66,-579.8 4269.34,-579.8 4269.34,-553 4140.66,-553"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-560.8" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#d8dee9">frontend</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4250.34" y="-562.8" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">BIT</text>
|
||||
<polygon fill="#272e3d" stroke="none" points="4140.66,-526.2 4140.66,-553 4269.34,-553 4269.34,-526.2 4140.66,-526.2"/>
|
||||
<polygon fill="none" stroke="#3f4c5f" points="4140.66,-526.2 4140.66,-553 4269.34,-553 4269.34,-526.2 4140.66,-526.2"/>
|
||||
<text xml:space="preserve" text-anchor="start" x="4145.66" y="-534" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#d8dee9">writeonly</text>
|
||||
<text xml:space="preserve" text-anchor="start" x="4250.34" y="-536" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#8b95a7">BIT</text>
|
||||
</g>
|
||||
<!-- companysetting->company -->
|
||||
<g id="edge59" class="edge">
|
||||
<title>companysetting:w->company:n</title>
|
||||
<g id="a_edge59"><a xlink:title="FK_companysetting_company">
|
||||
<path fill="none" stroke="#ff8f66" stroke-width="1.4" d="M4139.66,-633.4C4080.56,-633.4 4144.57,-544.43 4099,-506.8 3991.54,-418.07 3485.2,-565.62 3463.5,-438.57"/>
|
||||
<polygon fill="#ff8f66" stroke="#ff8f66" stroke-width="1.4" points="3465.96,-438.69 3462.95,-431.91 3461.08,-439.09 3465.96,-438.69"/>
|
||||
<path fill="none" stroke="#ff8f66" stroke-width="1.4" d="M4139.66,-646.8C4074.86,-646.8 4148.38,-548.75 4099,-506.8 3992.8,-416.57 3485.26,-565.56 3463.5,-438.57"/>
|
||||
<polygon fill="#ff8f66" stroke="#ff8f66" stroke-width="1.4" points="3465.97,-438.69 3462.95,-431.91 3461.08,-439.09 3465.97,-438.69"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 197 KiB |
@@ -536,8 +536,8 @@ BEGIN
|
||||
article_id INT NOT NULL,
|
||||
entity_id INT NOT NULL,
|
||||
price_id INT NULL,
|
||||
SupplierSKU NVARCHAR(100) NULL,
|
||||
SupplierStock FLOAT NULL,
|
||||
supplierSKU NVARCHAR(100) NULL,
|
||||
supplierStock FLOAT NULL,
|
||||
pu FLOAT NOT NULL CONSTRAINT DF_articlesupplier_pu DEFAULT 1,
|
||||
CONSTRAINT FK_articlesupplier_article FOREIGN KEY (article_id) REFERENCES article(id) ON DELETE CASCADE,
|
||||
CONSTRAINT FK_articlesupplier_entity FOREIGN KEY (entity_id) REFERENCES entity(id) ON DELETE CASCADE,
|
||||
@@ -762,6 +762,7 @@ BEGIN
|
||||
[key] NVARCHAR(255) NOT NULL,
|
||||
value NVARCHAR(MAX) NOT NULL,
|
||||
frontend BIT NOT NULL CONSTRAINT DF_companysetting_frontend DEFAULT 0,
|
||||
writeonly BIT NOT NULL CONSTRAINT DF_companysetting_writeonly DEFAULT 0,
|
||||
CONSTRAINT UQ_companysetting_company_key UNIQUE (company_id, [key]),
|
||||
CONSTRAINT FK_companysetting_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
|
||||
);
|
||||
@@ -799,47 +800,47 @@ END
|
||||
|
||||
/** DDL scripts in dependency order for schema init. */
|
||||
export const SCHEMA_SCRIPTS = [
|
||||
INIT_META,
|
||||
INIT_LANGUAGE,
|
||||
INIT_TAX,
|
||||
INIT_CATEGORY,
|
||||
INIT_PIC,
|
||||
INIT_COMPANY,
|
||||
INIT_GOOGLE_AUTH,
|
||||
INIT_CUSTOMERGROUP,
|
||||
INIT_COMPANY_POS_CUSTOMERGROUP_FK,
|
||||
INIT_ENTITY,
|
||||
INIT_ENTITY_COMPANY_NUMBER_UQ,
|
||||
INIT_ENTITYADDRESS,
|
||||
INIT_ENTITYCONTACT,
|
||||
INIT_UNIT,
|
||||
INIT_UNITTEXT,
|
||||
INIT_OPTIONSLIST,
|
||||
INIT_ARTICLELIST,
|
||||
INIT_BRAND,
|
||||
INIT_ARTICLE,
|
||||
INIT_ARTICLEEAN,
|
||||
INIT_ARTICLEPIC,
|
||||
INIT_BRANDPIC,
|
||||
INIT_ARTICLELISTARTICLE,
|
||||
INIT_OPTIONSLISTARTICLE,
|
||||
INIT_CATEGORYARTICLE,
|
||||
INIT_CATEGORYPIC,
|
||||
INIT_CATEGORYTEXT,
|
||||
INIT_ARTICLENAME,
|
||||
INIT_PRICE,
|
||||
INIT_ARTICLE_SUPPLIER,
|
||||
INIT_MANIFEST,
|
||||
INIT_MANIFESTARTICLE,
|
||||
INIT_LEDGER,
|
||||
INIT_NUMBERS,
|
||||
INIT_GET_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
|
||||
INIT_PEEK_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
|
||||
INIT_COMPANYUSER,
|
||||
INIT_ARTICLEHISTORY,
|
||||
INIT_ENTITYHISTORY,
|
||||
INIT_SYNCPOS,
|
||||
INIT_COMPANYSETTING,
|
||||
INIT_POSTERMINAL,
|
||||
INIT_POSTERMINALCATEGORY,
|
||||
INIT_META,
|
||||
INIT_LANGUAGE,
|
||||
INIT_TAX,
|
||||
INIT_CATEGORY,
|
||||
INIT_PIC,
|
||||
INIT_COMPANY,
|
||||
INIT_GOOGLE_AUTH,
|
||||
INIT_CUSTOMERGROUP,
|
||||
INIT_COMPANY_POS_CUSTOMERGROUP_FK,
|
||||
INIT_ENTITY,
|
||||
INIT_ENTITY_COMPANY_NUMBER_UQ,
|
||||
INIT_ENTITYADDRESS,
|
||||
INIT_ENTITYCONTACT,
|
||||
INIT_UNIT,
|
||||
INIT_UNITTEXT,
|
||||
INIT_OPTIONSLIST,
|
||||
INIT_ARTICLELIST,
|
||||
INIT_BRAND,
|
||||
INIT_ARTICLE,
|
||||
INIT_ARTICLEEAN,
|
||||
INIT_ARTICLEPIC,
|
||||
INIT_BRANDPIC,
|
||||
INIT_ARTICLELISTARTICLE,
|
||||
INIT_OPTIONSLISTARTICLE,
|
||||
INIT_CATEGORYARTICLE,
|
||||
INIT_CATEGORYPIC,
|
||||
INIT_CATEGORYTEXT,
|
||||
INIT_ARTICLENAME,
|
||||
INIT_PRICE,
|
||||
INIT_ARTICLE_SUPPLIER,
|
||||
INIT_MANIFEST,
|
||||
INIT_MANIFESTARTICLE,
|
||||
INIT_LEDGER,
|
||||
INIT_NUMBERS,
|
||||
INIT_GET_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
|
||||
INIT_PEEK_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
|
||||
INIT_COMPANYUSER,
|
||||
INIT_ARTICLEHISTORY,
|
||||
INIT_ENTITYHISTORY,
|
||||
INIT_SYNCPOS,
|
||||
INIT_COMPANYSETTING,
|
||||
INIT_POSTERMINAL,
|
||||
INIT_POSTERMINALCATEGORY,
|
||||
];
|
||||
|
||||
@@ -2,7 +2,8 @@ export const LIST_BY_COMPANY = `
|
||||
SELECT
|
||||
[key],
|
||||
value,
|
||||
CAST(frontend AS INT) AS frontend
|
||||
CAST(frontend AS INT) AS frontend,
|
||||
CAST(writeonly AS INT) AS writeonly
|
||||
FROM companysetting
|
||||
WHERE company_id = @companyId
|
||||
ORDER BY [key]
|
||||
@@ -12,7 +13,8 @@ export const LIST_BY_COMPANY_FRONTEND = `
|
||||
SELECT
|
||||
[key],
|
||||
value,
|
||||
CAST(frontend AS INT) AS frontend
|
||||
CAST(frontend AS INT) AS frontend,
|
||||
CAST(writeonly AS INT) AS writeonly
|
||||
FROM companysetting
|
||||
WHERE company_id = @companyId
|
||||
AND frontend = 1
|
||||
@@ -23,7 +25,8 @@ export const GET_BY_COMPANY_AND_KEY = `
|
||||
SELECT
|
||||
[key],
|
||||
value,
|
||||
CAST(frontend AS INT) AS frontend
|
||||
CAST(frontend AS INT) AS frontend,
|
||||
CAST(writeonly AS INT) AS writeonly
|
||||
FROM companysetting
|
||||
WHERE company_id = @companyId
|
||||
AND [key] = @key
|
||||
@@ -34,8 +37,8 @@ MERGE companysetting AS target
|
||||
USING (SELECT @companyId AS company_id, @key AS [key]) AS src
|
||||
ON target.company_id = src.company_id AND target.[key] = src.[key]
|
||||
WHEN MATCHED THEN
|
||||
UPDATE SET value = @value, frontend = @frontend
|
||||
UPDATE SET value = @value, frontend = @frontend, writeonly = @writeonly
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (company_id, [key], value, frontend)
|
||||
VALUES (@companyId, @key, @value, @frontend);
|
||||
INSERT (company_id, [key], value, frontend, writeonly)
|
||||
VALUES (@companyId, @key, @value, @frontend, @writeonly);
|
||||
`;
|
||||
|
||||
@@ -12,13 +12,18 @@ export default function get(pool) {
|
||||
* @param {string} key - The setting key.
|
||||
* @param {object} [options] - Optional options.
|
||||
* @param {boolean} [options.frontendOnly] - Only return the setting if it is frontend-visible.
|
||||
* @returns {Promise<{key: string, value: string, frontend: boolean}|undefined>} The setting, or `undefined` if not found.
|
||||
* @param {boolean} [options.maskWriteonly] - Mask writeonly settings as '***'. Defaults to `frontendOnly` (usergui gets '***', backend gets full value).
|
||||
* @returns {Promise<{key: string, value: string, frontend: boolean, writeonly: boolean}|undefined>} The setting, or `undefined` if not found.
|
||||
*
|
||||
* @example
|
||||
* const setting = await store.companysetting.get(42, 'theme');
|
||||
* // => { key, value, frontend }
|
||||
* const setting = await store.companysetting.get(42, 'ui.theme');
|
||||
* // => { key, value, frontend, writeonly }
|
||||
*/
|
||||
return async (googleAuthId, key, { frontendOnly = false } = {}) => {
|
||||
return async (
|
||||
googleAuthId,
|
||||
key,
|
||||
{ frontendOnly = false, maskWriteonly } = {},
|
||||
) => {
|
||||
if (!key?.trim()) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -39,6 +44,7 @@ export default function get(pool) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return shapeSetting(row);
|
||||
const shouldMask = maskWriteonly ?? frontendOnly;
|
||||
return shapeSetting(row, { exposeValue: !shouldMask });
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,16 +11,23 @@ export default function list(pool) {
|
||||
/**
|
||||
* Lists the settings of the user's selected company, optionally only frontend-visible ones.
|
||||
*
|
||||
* Write-only settings (such as `keys.tavily`, `keys.openrouter`) have their value masked
|
||||
* with `'***'` by default for usergui presentation.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {object} [options] - Optional options.
|
||||
* @param {boolean} [options.frontendOnly] - Only return frontend-visible settings.
|
||||
* @returns {Promise<Array<{key: string, value: string, frontend: boolean}>>} The settings.
|
||||
* @param {boolean} [options.maskWriteonly] - Whether to mask writeonly settings with '***'. Defaults to `true`.
|
||||
* @returns {Promise<Array<{key: string, value: string, frontend: boolean, writeonly: boolean}>>} The settings.
|
||||
*
|
||||
* @example
|
||||
* const settings = await store.companysetting.list(42, { frontendOnly: true });
|
||||
* // => [{ key, value, frontend }]
|
||||
* // => [{ key, value, frontend, writeonly }]
|
||||
*/
|
||||
return async (googleAuthId, { frontendOnly = false } = {}) => {
|
||||
return async (
|
||||
googleAuthId,
|
||||
{ frontendOnly = false, maskWriteonly = true } = {},
|
||||
) => {
|
||||
const { companyId } = await access(googleAuthId);
|
||||
|
||||
const result = await pool
|
||||
@@ -28,6 +35,8 @@ export default function list(pool) {
|
||||
.input('companyId', companyId)
|
||||
.query(frontendOnly ? LIST_BY_COMPANY_FRONTEND : LIST_BY_COMPANY);
|
||||
|
||||
return result.recordset.map(shapeSetting);
|
||||
return result.recordset.map((row) =>
|
||||
shapeSetting(row, { exposeValue: !maskWriteonly }),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,6 +10,13 @@ const ALLOWED_KEYS = new Set([
|
||||
'labelprinter.type',
|
||||
]);
|
||||
|
||||
// Keys that are write-only by default: the GUI receives a scrambled "***"
|
||||
// placeholder when reading, but the backend always gets the real value.
|
||||
const WRITEONLY_KEYS = new Set([
|
||||
'keys.tavily',
|
||||
'keys.openrouter',
|
||||
]);
|
||||
|
||||
export default function set(pool) {
|
||||
const access = resolveSelectedCompanyAccess(pool);
|
||||
|
||||
@@ -19,17 +26,22 @@ export default function set(pool) {
|
||||
* Only a fixed allow-list of keys can be set: `ui.theme`, `keys.tavily`,
|
||||
* `keys.openrouter`, `labelprinter.addr`, `labelprinter.type`.
|
||||
*
|
||||
* Keys in the write-only set (`keys.tavily`, `keys.openrouter`) are stored
|
||||
* with `writeonly = 1`; when retrieved by the GUI the value is returned as
|
||||
* `"***"`. The backend always receives the real value.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {object} input - The setting input.
|
||||
* @param {string} input.key - The setting key (must be in the allow-list).
|
||||
* @param {string} input.value - The setting value.
|
||||
* @param {boolean} [input.frontend] - Whether the setting is frontend-visible.
|
||||
* @returns {Promise<{key: string, value: string, frontend: boolean}>} The upserted setting.
|
||||
* @param {boolean} [input.writeonly] - Whether the setting is write-only. Defaults to true for `keys.tavily` and `keys.openrouter`, false otherwise.
|
||||
* @returns {Promise<{key: string, value: string, frontend: boolean, writeonly: boolean}>} The upserted setting.
|
||||
* @throws {Error} If the input is invalid.
|
||||
*
|
||||
* @example
|
||||
* const setting = await store.companysetting.set(42, { key: 'ui.theme', value: 'dark' });
|
||||
* // => { key, value, frontend }
|
||||
* // => { key, value, frontend, writeonly }
|
||||
*/
|
||||
return async (googleAuthId, input = {}) => {
|
||||
const key = input.key?.trim();
|
||||
@@ -41,6 +53,10 @@ export default function set(pool) {
|
||||
}
|
||||
|
||||
const frontend = Boolean(input.frontend);
|
||||
const writeonly =
|
||||
input.writeonly !== undefined
|
||||
? Boolean(input.writeonly)
|
||||
: WRITEONLY_KEYS.has(key);
|
||||
const { companyId } = await access(googleAuthId);
|
||||
|
||||
await pool
|
||||
@@ -49,6 +65,7 @@ export default function set(pool) {
|
||||
.input('key', key)
|
||||
.input('value', input.value)
|
||||
.input('frontend', frontend)
|
||||
.input('writeonly', writeonly)
|
||||
.query(UPSERT);
|
||||
|
||||
const result = await pool
|
||||
@@ -57,6 +74,7 @@ export default function set(pool) {
|
||||
.input('key', key)
|
||||
.query(GET_BY_COMPANY_AND_KEY);
|
||||
|
||||
// Return the masked value to the GUI; the DB holds the real value.
|
||||
return shapeSetting(result.recordset[0]);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
function shapeSetting(row) {
|
||||
function shapeSetting(row, { exposeValue = false } = {}) {
|
||||
const writeonly = Boolean(row.writeonly);
|
||||
return {
|
||||
key: row.key,
|
||||
value: row.value,
|
||||
value: writeonly && !exposeValue ? '***' : row.value,
|
||||
frontend: Boolean(row.frontend),
|
||||
writeonly,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user