u
This commit is contained in:
@@ -119,6 +119,11 @@ Backend mapping:
|
|||||||
| `updateParentId` | `(id, parentId)` | `void` |
|
| `updateParentId` | `(id, parentId)` | `void` |
|
||||||
| `delete` | `(id)` | `void` — blocked by FK if `categoryarticle` (or child categories) still reference it |
|
| `delete` | `(id)` | `void` — blocked by FK if `categoryarticle` (or child categories) still reference it |
|
||||||
| `getTree` | `(rootId)` | `{ id, parentId, sort }[]` |
|
| `getTree` | `(rootId)` | `{ id, parentId, sort }[]` |
|
||||||
|
| `getTreeForCompany` | `(authId, companyId)` | `{ id, parentId, sort }[]` — membership check + company root |
|
||||||
|
|
||||||
|
`getTreeForCompany` throws `Not authorized` if `authId` is not a `companyuser` of `companyId`, and `Company not found` if the company is missing or has no `root_category_id`. Reuses `GET_TREE` after access check.
|
||||||
|
|
||||||
|
`getTree(rootId)` stays for low-level use (tests, internal) when the root id is already known.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -131,6 +136,7 @@ Backend mapping:
|
|||||||
| `PATCH /api/company/:id` | `company.update(id, { iso639, name, taxrate, reducedtaxrate })` |
|
| `PATCH /api/company/:id` | `company.update(id, { iso639, name, taxrate, reducedtaxrate })` |
|
||||||
| `DELETE /api/company/:id` | `company.delete(id)` |
|
| `DELETE /api/company/:id` | `company.delete(id)` |
|
||||||
| `PUT /api/auth/selected-company` | `google_auth.setSelectedCompany(authId, companyId)` |
|
| `PUT /api/auth/selected-company` | `google_auth.setSelectedCompany(authId, companyId)` |
|
||||||
|
| `GET /api/category/tree?companyId=` | `category.getTreeForCompany(authId, companyId)` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ const MENU = {
|
|||||||
{ value: 'category.updateParentId', label: 'updateParentId', hint: 'id, parentId' },
|
{ value: 'category.updateParentId', label: 'updateParentId', hint: 'id, parentId' },
|
||||||
{ value: 'category.delete', label: 'delete', hint: 'id' },
|
{ value: 'category.delete', label: 'delete', hint: 'id' },
|
||||||
{ value: 'category.getTree', label: 'getTree', hint: 'rootId → rows' },
|
{ value: 'category.getTree', label: 'getTree', hint: 'rootId → rows' },
|
||||||
|
{ value: 'category.getTreeForCompany', label: 'getTreeForCompany', hint: 'authId, companyId → rows' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
companyuser: {
|
companyuser: {
|
||||||
@@ -338,6 +339,16 @@ async function runMethod(client, action) {
|
|||||||
if (rootId == null) return;
|
if (rootId == null) return;
|
||||||
return ['rows', await client.category.getTree(Number(rootId))];
|
return ['rows', await client.category.getTree(Number(rootId))];
|
||||||
}
|
}
|
||||||
|
case 'category.getTreeForCompany': {
|
||||||
|
const authId = await askInt('google_auth id');
|
||||||
|
if (authId == null) return;
|
||||||
|
const companyId = await askInt('company id');
|
||||||
|
if (companyId == null) return;
|
||||||
|
return [
|
||||||
|
'rows',
|
||||||
|
await client.category.getTreeForCompany(Number(authId), Number(companyId)),
|
||||||
|
];
|
||||||
|
}
|
||||||
case 'companyuser.add': {
|
case 'companyuser.add': {
|
||||||
const companyId = await askInt('Company id');
|
const companyId = await askInt('Company id');
|
||||||
if (companyId == null) return;
|
if (companyId == null) return;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import companyUpdate from './store/company/update.js';
|
|||||||
import companyDelete from './store/company/delete.js';
|
import companyDelete from './store/company/delete.js';
|
||||||
import companyList from './store/company/list.js';
|
import companyList from './store/company/list.js';
|
||||||
import categoryGetTree from './store/category/getTree.js';
|
import categoryGetTree from './store/category/getTree.js';
|
||||||
|
import categoryGetTreeForCompany from './store/category/getTreeForCompany.js';
|
||||||
import categoryCreate from './store/category/create.js';
|
import categoryCreate from './store/category/create.js';
|
||||||
import categoryUpdateParentId from './store/category/updateParentId.js';
|
import categoryUpdateParentId from './store/category/updateParentId.js';
|
||||||
import categoryDelete from './store/category/delete.js';
|
import categoryDelete from './store/category/delete.js';
|
||||||
@@ -45,6 +46,7 @@ export default class LibDashStore {
|
|||||||
|
|
||||||
this.category = {
|
this.category = {
|
||||||
getTree: categoryGetTree(pool),
|
getTree: categoryGetTree(pool),
|
||||||
|
getTreeForCompany: categoryGetTreeForCompany(pool),
|
||||||
create: categoryCreate(pool),
|
create: categoryCreate(pool),
|
||||||
updateParentId: categoryUpdateParentId(pool),
|
updateParentId: categoryUpdateParentId(pool),
|
||||||
delete: categoryDelete(pool),
|
delete: categoryDelete(pool),
|
||||||
|
|||||||
@@ -5,6 +5,16 @@ INNER JOIN google_auth ga ON ga.id = cu.google_auth_id
|
|||||||
WHERE ga.email = @email
|
WHERE ga.email = @email
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const GET_COMPANY_ACCESS = `
|
||||||
|
SELECT
|
||||||
|
c.root_category_id AS rootCategoryId,
|
||||||
|
cu.id AS companyuserId
|
||||||
|
FROM company c
|
||||||
|
LEFT JOIN companyuser cu
|
||||||
|
ON cu.company_id = c.id AND cu.google_auth_id = @authId
|
||||||
|
WHERE c.id = @companyId
|
||||||
|
`;
|
||||||
|
|
||||||
export const ADD = `
|
export const ADD = `
|
||||||
INSERT INTO companyuser (google_auth_id, company_id)
|
INSERT INTO companyuser (google_auth_id, company_id)
|
||||||
OUTPUT INSERTED.id
|
OUTPUT INSERTED.id
|
||||||
|
|||||||
17
src/store/category/getTreeForCompany.js
Normal file
17
src/store/category/getTreeForCompany.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { GET_TREE } from '../../sql/category.js';
|
||||||
|
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
||||||
|
|
||||||
|
export default function getTreeForCompany(pool) {
|
||||||
|
const access = resolveCompanyAccess(pool);
|
||||||
|
|
||||||
|
return async (authId, companyId) => {
|
||||||
|
const { rootCategoryId } = await access(authId, companyId);
|
||||||
|
|
||||||
|
const result = await pool
|
||||||
|
.request()
|
||||||
|
.input('rootId', rootCategoryId)
|
||||||
|
.query(GET_TREE);
|
||||||
|
|
||||||
|
return result.recordset;
|
||||||
|
};
|
||||||
|
}
|
||||||
24
src/store/companyuser/resolveCompanyAccess.js
Normal file
24
src/store/companyuser/resolveCompanyAccess.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { GET_COMPANY_ACCESS } from '../../sql/companyuser.js';
|
||||||
|
|
||||||
|
export default function resolveCompanyAccess(pool) {
|
||||||
|
return async (authId, companyId) => {
|
||||||
|
const result = await pool
|
||||||
|
.request()
|
||||||
|
.input('authId', authId)
|
||||||
|
.input('companyId', companyId)
|
||||||
|
.query(GET_COMPANY_ACCESS);
|
||||||
|
|
||||||
|
const row = result.recordset[0];
|
||||||
|
if (!row) {
|
||||||
|
throw new Error('Company not found');
|
||||||
|
}
|
||||||
|
if (!row.companyuserId) {
|
||||||
|
throw new Error('Not authorized');
|
||||||
|
}
|
||||||
|
if (!row.rootCategoryId) {
|
||||||
|
throw new Error('Company not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { rootCategoryId: row.rootCategoryId };
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user