@directus/api 19.1.1 → 19.3.0
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/dist/controllers/users.js +1 -0
- package/dist/controllers/utils.js +7 -5
- package/dist/database/helpers/index.d.ts +1 -1
- package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/cockroachdb.js +13 -0
- package/dist/database/helpers/schema/dialects/mssql.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/mssql.js +9 -0
- package/dist/database/helpers/schema/dialects/mysql.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/mysql.js +17 -0
- package/dist/database/helpers/schema/dialects/oracle.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/oracle.js +9 -0
- package/dist/database/helpers/schema/dialects/postgres.d.ts +4 -0
- package/dist/database/helpers/schema/dialects/postgres.js +14 -0
- package/dist/database/helpers/schema/dialects/sqlite.d.ts +1 -0
- package/dist/database/helpers/schema/dialects/sqlite.js +9 -0
- package/dist/database/helpers/schema/index.d.ts +3 -3
- package/dist/database/helpers/schema/index.js +3 -3
- package/dist/database/helpers/schema/types.d.ts +4 -0
- package/dist/database/helpers/schema/types.js +6 -0
- package/dist/middleware/graphql.js +5 -1
- package/dist/services/extensions.js +11 -8
- package/dist/services/graphql/index.js +15 -11
- package/dist/services/graphql/utils/sanitize-gql-schema.d.ts +8 -0
- package/dist/services/graphql/utils/sanitize-gql-schema.js +80 -0
- package/dist/services/roles.d.ts +1 -0
- package/dist/services/roles.js +200 -11
- package/dist/services/users.d.ts +1 -1
- package/dist/services/users.js +86 -17
- package/dist/telemetry/lib/get-report.js +22 -10
- package/dist/telemetry/types/report.d.ts +12 -0
- package/dist/telemetry/utils/check-increased-user-limits.d.ts +7 -0
- package/dist/telemetry/utils/check-increased-user-limits.js +22 -0
- package/dist/telemetry/utils/get-extension-count.d.ts +9 -0
- package/dist/telemetry/utils/get-extension-count.js +19 -0
- package/dist/telemetry/utils/get-field-count.d.ts +6 -0
- package/dist/telemetry/utils/get-field-count.js +12 -0
- package/dist/telemetry/utils/get-item-count.d.ts +10 -6
- package/dist/telemetry/utils/get-item-count.js +13 -9
- package/dist/telemetry/utils/get-role-counts-by-roles.d.ts +6 -0
- package/dist/telemetry/utils/get-role-counts-by-roles.js +27 -0
- package/dist/telemetry/utils/get-role-counts-by-users.d.ts +11 -0
- package/dist/telemetry/utils/get-role-counts-by-users.js +34 -0
- package/dist/telemetry/utils/get-user-count.d.ts +3 -2
- package/dist/telemetry/utils/get-user-count.js +7 -4
- package/dist/telemetry/utils/get-user-counts-by-roles.d.ts +7 -0
- package/dist/telemetry/utils/get-user-counts-by-roles.js +35 -0
- package/dist/telemetry/utils/get-user-item-count.js +4 -2
- package/package.json +28 -28
|
@@ -3,13 +3,17 @@ export interface CollectionCount {
|
|
|
3
3
|
collection: string;
|
|
4
4
|
count: number;
|
|
5
5
|
}
|
|
6
|
+
export interface CollectionCountTask {
|
|
7
|
+
collection: string;
|
|
8
|
+
where?: readonly [string, string, string | boolean | number];
|
|
9
|
+
}
|
|
6
10
|
/**
|
|
7
|
-
* Get the item count of the given
|
|
11
|
+
* Get the item count of the given task in the given database
|
|
8
12
|
* @param db Knex instance to count against
|
|
9
|
-
* @param
|
|
13
|
+
* @param task Task to count rows for
|
|
10
14
|
* @returns Collection name and count
|
|
11
15
|
*/
|
|
12
|
-
export declare const countCollection: (db: Knex,
|
|
16
|
+
export declare const countCollection: (db: Knex, task: CollectionCountTask) => Promise<CollectionCount>;
|
|
13
17
|
/**
|
|
14
18
|
* Merge the given collection count in the object accumulator
|
|
15
19
|
* Intended for use with .reduce()
|
|
@@ -19,8 +23,8 @@ export declare const countCollection: (db: Knex, collection: string) => Promise<
|
|
|
19
23
|
*/
|
|
20
24
|
export declare const mergeResults: (acc: Record<string, number>, value: CollectionCount) => Record<string, number>;
|
|
21
25
|
/**
|
|
22
|
-
* Get an object of item counts for the given
|
|
26
|
+
* Get an object of item counts for the given tasks
|
|
23
27
|
* @param db Database instance to get counts in
|
|
24
|
-
* @param
|
|
28
|
+
* @param tasks Array of tasks to get count for
|
|
25
29
|
*/
|
|
26
|
-
export declare const getItemCount: <T extends readonly
|
|
30
|
+
export declare const getItemCount: <T extends readonly CollectionCountTask[]>(db: Knex, tasks: T) => Promise<Record<T[number]["collection"], number>>;
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import {} from 'knex';
|
|
2
2
|
import pLimit from 'p-limit';
|
|
3
3
|
/**
|
|
4
|
-
* Get the item count of the given
|
|
4
|
+
* Get the item count of the given task in the given database
|
|
5
5
|
* @param db Knex instance to count against
|
|
6
|
-
* @param
|
|
6
|
+
* @param task Task to count rows for
|
|
7
7
|
* @returns Collection name and count
|
|
8
8
|
*/
|
|
9
|
-
export const countCollection = async (db,
|
|
10
|
-
const
|
|
11
|
-
|
|
9
|
+
export const countCollection = async (db, task) => {
|
|
10
|
+
const query = db.count('*', { as: 'count' }).from(task.collection);
|
|
11
|
+
if (task.where) {
|
|
12
|
+
query.where(...task.where);
|
|
13
|
+
}
|
|
14
|
+
const count = await query.first();
|
|
15
|
+
return { collection: task.collection, count: Number(count?.['count'] ?? 0) };
|
|
12
16
|
};
|
|
13
17
|
/**
|
|
14
18
|
* Merge the given collection count in the object accumulator
|
|
@@ -22,15 +26,15 @@ export const mergeResults = (acc, value) => {
|
|
|
22
26
|
return acc;
|
|
23
27
|
};
|
|
24
28
|
/**
|
|
25
|
-
* Get an object of item counts for the given
|
|
29
|
+
* Get an object of item counts for the given tasks
|
|
26
30
|
* @param db Database instance to get counts in
|
|
27
|
-
* @param
|
|
31
|
+
* @param tasks Array of tasks to get count for
|
|
28
32
|
*/
|
|
29
|
-
export const getItemCount = async (db,
|
|
33
|
+
export const getItemCount = async (db, tasks) => {
|
|
30
34
|
// Counts can be a little heavy if the table is very large, so we'll only ever execute 3 of these
|
|
31
35
|
// queries simultaneously to not overload the database
|
|
32
36
|
const limit = pLimit(3);
|
|
33
|
-
const calls =
|
|
37
|
+
const calls = tasks.map((task) => limit(countCollection, db, task));
|
|
34
38
|
const results = await Promise.all(calls);
|
|
35
39
|
return results.reduce(mergeResults, {});
|
|
36
40
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { toBoolean } from '@directus/utils';
|
|
2
|
+
import {} from './get-user-count.js';
|
|
3
|
+
/**
|
|
4
|
+
* Get the role type counts by role IDs
|
|
5
|
+
*/
|
|
6
|
+
export async function getRoleCountsByRoles(db, roles) {
|
|
7
|
+
const counts = {
|
|
8
|
+
admin: 0,
|
|
9
|
+
app: 0,
|
|
10
|
+
api: 0,
|
|
11
|
+
};
|
|
12
|
+
const result = (await db.select('id', 'admin_access', 'app_access').from('directus_roles').whereIn('id', roles));
|
|
13
|
+
for (const role of result) {
|
|
14
|
+
const adminAccess = toBoolean(role.admin_access);
|
|
15
|
+
const appAccess = toBoolean(role.app_access);
|
|
16
|
+
if (adminAccess) {
|
|
17
|
+
counts.admin++;
|
|
18
|
+
}
|
|
19
|
+
else if (appAccess) {
|
|
20
|
+
counts.app++;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
counts.api++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return counts;
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PrimaryKey } from '@directus/types';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
import type { AccessTypeCount } from './get-user-count.js';
|
|
4
|
+
type CountOptions = {
|
|
5
|
+
inactiveUsers?: boolean;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Get the role type counts by user IDs
|
|
9
|
+
*/
|
|
10
|
+
export declare function getRoleCountsByUsers(db: Knex, userIds: PrimaryKey[], options?: CountOptions): Promise<AccessTypeCount>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { toBoolean } from '@directus/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Get the role type counts by user IDs
|
|
4
|
+
*/
|
|
5
|
+
export async function getRoleCountsByUsers(db, userIds, options = {}) {
|
|
6
|
+
const counts = {
|
|
7
|
+
admin: 0,
|
|
8
|
+
app: 0,
|
|
9
|
+
api: 0,
|
|
10
|
+
};
|
|
11
|
+
const result = await db
|
|
12
|
+
.count('directus_users.id', { as: 'count' })
|
|
13
|
+
.select('directus_roles.admin_access', 'directus_roles.app_access')
|
|
14
|
+
.from('directus_users')
|
|
15
|
+
.whereIn('directus_users.id', userIds)
|
|
16
|
+
.andWhere('directus_users.status', options.inactiveUsers ? '!=' : '=', 'active')
|
|
17
|
+
.leftJoin('directus_roles', 'directus_users.role', '=', 'directus_roles.id')
|
|
18
|
+
.groupBy('directus_roles.admin_access', 'directus_roles.app_access');
|
|
19
|
+
for (const record of result) {
|
|
20
|
+
const adminAccess = toBoolean(record.admin_access);
|
|
21
|
+
const appAccess = toBoolean(record.app_access);
|
|
22
|
+
const count = Number(record.count);
|
|
23
|
+
if (adminAccess) {
|
|
24
|
+
counts.admin += count;
|
|
25
|
+
}
|
|
26
|
+
else if (appAccess) {
|
|
27
|
+
counts.app += count;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
counts.api += count;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return counts;
|
|
34
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { PrimaryKey } from '@directus/types';
|
|
1
2
|
import { type Knex } from 'knex';
|
|
2
|
-
export interface
|
|
3
|
+
export interface AccessTypeCount {
|
|
3
4
|
admin: number;
|
|
4
5
|
app: number;
|
|
5
6
|
api: number;
|
|
6
7
|
}
|
|
7
|
-
export declare const getUserCount: (db: Knex) => Promise<
|
|
8
|
+
export declare const getUserCount: (db: Knex, ignoreIds?: PrimaryKey[]) => Promise<AccessTypeCount>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { toBoolean } from '@directus/utils';
|
|
2
2
|
import {} from 'knex';
|
|
3
|
-
export const getUserCount = async (db) => {
|
|
3
|
+
export const getUserCount = async (db, ignoreIds = []) => {
|
|
4
4
|
const counts = {
|
|
5
5
|
admin: 0,
|
|
6
6
|
app: 0,
|
|
@@ -10,20 +10,23 @@ export const getUserCount = async (db) => {
|
|
|
10
10
|
.count('directus_users.id', { as: 'count' })
|
|
11
11
|
.select('directus_roles.admin_access', 'directus_roles.app_access')
|
|
12
12
|
.from('directus_users')
|
|
13
|
+
.whereNotIn('directus_users.id', ignoreIds)
|
|
14
|
+
.andWhere('directus_users.status', 'active')
|
|
13
15
|
.leftJoin('directus_roles', 'directus_users.role', '=', 'directus_roles.id')
|
|
16
|
+
.where('directus_users.status', '=', 'active')
|
|
14
17
|
.groupBy('directus_roles.admin_access', 'directus_roles.app_access'));
|
|
15
18
|
for (const record of result) {
|
|
16
19
|
const adminAccess = toBoolean(record.admin_access);
|
|
17
20
|
const appAccess = toBoolean(record.app_access);
|
|
18
21
|
const count = Number(record.count);
|
|
19
22
|
if (adminAccess) {
|
|
20
|
-
counts.admin
|
|
23
|
+
counts.admin += count;
|
|
21
24
|
}
|
|
22
25
|
else if (appAccess) {
|
|
23
|
-
counts.app
|
|
26
|
+
counts.app += count;
|
|
24
27
|
}
|
|
25
28
|
else {
|
|
26
|
-
counts.api
|
|
29
|
+
counts.api += count;
|
|
27
30
|
}
|
|
28
31
|
}
|
|
29
32
|
return counts;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PrimaryKey } from '@directus/types';
|
|
2
|
+
import type { Knex } from 'knex';
|
|
3
|
+
import { type AccessTypeCount } from './get-user-count.js';
|
|
4
|
+
/**
|
|
5
|
+
* Get the user type counts by role IDs
|
|
6
|
+
*/
|
|
7
|
+
export declare function getUserCountsByRoles(db: Knex, roleIds: PrimaryKey[]): Promise<AccessTypeCount>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { toBoolean } from '@directus/utils';
|
|
2
|
+
import {} from './get-user-count.js';
|
|
3
|
+
/**
|
|
4
|
+
* Get the user type counts by role IDs
|
|
5
|
+
*/
|
|
6
|
+
export async function getUserCountsByRoles(db, roleIds) {
|
|
7
|
+
const counts = {
|
|
8
|
+
admin: 0,
|
|
9
|
+
app: 0,
|
|
10
|
+
api: 0,
|
|
11
|
+
};
|
|
12
|
+
const result = (await db
|
|
13
|
+
.count('directus_users.id', { as: 'count' })
|
|
14
|
+
.select('directus_roles.admin_access', 'directus_roles.app_access')
|
|
15
|
+
.from('directus_users')
|
|
16
|
+
.whereIn('directus_roles.id', roleIds)
|
|
17
|
+
.andWhere('directus_users.status', '=', 'active')
|
|
18
|
+
.leftJoin('directus_roles', 'directus_users.role', '=', 'directus_roles.id')
|
|
19
|
+
.groupBy('directus_roles.admin_access', 'directus_roles.app_access'));
|
|
20
|
+
for (const record of result) {
|
|
21
|
+
const adminAccess = toBoolean(record.admin_access);
|
|
22
|
+
const appAccess = toBoolean(record.app_access);
|
|
23
|
+
const count = Number(record.count);
|
|
24
|
+
if (adminAccess) {
|
|
25
|
+
counts.admin += count;
|
|
26
|
+
}
|
|
27
|
+
else if (appAccess) {
|
|
28
|
+
counts.app += count;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
counts.api += count;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return counts;
|
|
35
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { isSystemCollection } from '@directus/system-data';
|
|
1
2
|
import {} from 'knex';
|
|
2
3
|
import { getSchema } from '../../utils/get-schema.js';
|
|
3
4
|
import { getItemCount } from './get-item-count.js';
|
|
4
|
-
import { isSystemCollection } from '@directus/system-data';
|
|
5
5
|
/**
|
|
6
6
|
* Sum all passed values together. Meant to be used with .reduce()
|
|
7
7
|
*/
|
|
@@ -11,7 +11,9 @@ export const sum = (acc, val) => (acc += val);
|
|
|
11
11
|
*/
|
|
12
12
|
export const getUserItemCount = async (db) => {
|
|
13
13
|
const schema = await getSchema({ database: db });
|
|
14
|
-
const userCollections = Object.keys(schema.collections)
|
|
14
|
+
const userCollections = Object.keys(schema.collections)
|
|
15
|
+
.filter((collection) => isSystemCollection(collection) === false)
|
|
16
|
+
.map((collection) => ({ collection }));
|
|
15
17
|
const counts = await getItemCount(db, userCollections);
|
|
16
18
|
const collections = userCollections.length;
|
|
17
19
|
const items = Object.values(counts).reduce(sum, 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directus/api",
|
|
3
|
-
"version": "19.
|
|
3
|
+
"version": "19.3.0",
|
|
4
4
|
"description": "Directus is a real-time API and App dashboard for managing SQL database content",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"directus",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"@types/cookie": "0.6.0",
|
|
68
68
|
"argon2": "0.40.1",
|
|
69
69
|
"async": "3.2.5",
|
|
70
|
-
"axios": "1.
|
|
70
|
+
"axios": "1.7.2",
|
|
71
71
|
"busboy": "1.6.0",
|
|
72
72
|
"bytes": "3.1.2",
|
|
73
73
|
"camelcase": "8.0.0",
|
|
@@ -92,11 +92,11 @@
|
|
|
92
92
|
"fs-extra": "11.2.0",
|
|
93
93
|
"glob-to-regexp": "0.4.1",
|
|
94
94
|
"graphql": "16.8.1",
|
|
95
|
-
"graphql-compose": "9.0.
|
|
95
|
+
"graphql-compose": "9.0.11",
|
|
96
96
|
"graphql-ws": "5.16.0",
|
|
97
97
|
"helmet": "7.1.0",
|
|
98
98
|
"icc": "3.0.0",
|
|
99
|
-
"inquirer": "9.2.
|
|
99
|
+
"inquirer": "9.2.22",
|
|
100
100
|
"ioredis": "5.4.1",
|
|
101
101
|
"ip-matching": "2.1.2",
|
|
102
102
|
"isolated-vm": "4.7.2",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"keyv": "4.5.4",
|
|
109
109
|
"knex": "3.1.0",
|
|
110
110
|
"ldapjs": "2.3.3",
|
|
111
|
-
"liquidjs": "10.
|
|
111
|
+
"liquidjs": "10.13.1",
|
|
112
112
|
"lodash-es": "4.17.21",
|
|
113
113
|
"marked": "12.0.2",
|
|
114
114
|
"micromustache": "8.0.3",
|
|
@@ -121,14 +121,14 @@
|
|
|
121
121
|
"node-schedule": "2.1.1",
|
|
122
122
|
"nodemailer": "6.9.13",
|
|
123
123
|
"object-hash": "3.0.0",
|
|
124
|
-
"openapi3-ts": "4.3.
|
|
124
|
+
"openapi3-ts": "4.3.2",
|
|
125
125
|
"openid-client": "5.6.5",
|
|
126
126
|
"ora": "8.0.1",
|
|
127
127
|
"otplib": "12.0.1",
|
|
128
128
|
"p-limit": "5.0.0",
|
|
129
129
|
"p-queue": "8.0.1",
|
|
130
130
|
"papaparse": "5.4.1",
|
|
131
|
-
"pino": "9.
|
|
131
|
+
"pino": "9.1.0",
|
|
132
132
|
"pino-http": "9.0.0",
|
|
133
133
|
"pino-http-print": "3.1.0",
|
|
134
134
|
"pino-pretty": "11.0.0",
|
|
@@ -146,29 +146,29 @@
|
|
|
146
146
|
"ws": "8.17.0",
|
|
147
147
|
"zod": "3.23.8",
|
|
148
148
|
"zod-validation-error": "3.2.0",
|
|
149
|
+
"@directus/app": "12.1.3",
|
|
150
|
+
"@directus/env": "1.1.6",
|
|
149
151
|
"@directus/constants": "11.0.4",
|
|
150
|
-
"@directus/
|
|
151
|
-
"@directus/extensions": "1.0.
|
|
152
|
-
"@directus/
|
|
153
|
-
"@directus/extensions-registry": "1.0.5",
|
|
154
|
-
"@directus/errors": "0.3.0",
|
|
152
|
+
"@directus/errors": "0.3.2",
|
|
153
|
+
"@directus/extensions": "1.0.7",
|
|
154
|
+
"@directus/extensions-registry": "1.0.7",
|
|
155
155
|
"@directus/format-title": "10.1.2",
|
|
156
|
-
"@directus/extensions-sdk": "11.0.
|
|
157
|
-
"@directus/
|
|
158
|
-
"@directus/
|
|
156
|
+
"@directus/extensions-sdk": "11.0.7",
|
|
157
|
+
"@directus/pressure": "1.0.20",
|
|
158
|
+
"@directus/memory": "1.0.9",
|
|
159
159
|
"@directus/schema": "11.0.2",
|
|
160
|
-
"@directus/
|
|
161
|
-
"@directus/storage
|
|
162
|
-
"@directus/storage-driver-
|
|
163
|
-
"@directus/storage-driver-
|
|
164
|
-
"@directus/storage-driver-
|
|
165
|
-
"@directus/
|
|
166
|
-
"@directus/storage-driver-
|
|
167
|
-
"@directus/storage-driver-
|
|
168
|
-
"@directus/system-data": "1.0.
|
|
169
|
-
"@directus/utils": "11.0.
|
|
170
|
-
"
|
|
171
|
-
"directus": "
|
|
160
|
+
"@directus/specs": "10.2.10",
|
|
161
|
+
"@directus/storage": "10.0.13",
|
|
162
|
+
"@directus/storage-driver-azure": "10.0.22",
|
|
163
|
+
"@directus/storage-driver-cloudinary": "10.0.22",
|
|
164
|
+
"@directus/storage-driver-gcs": "10.0.23",
|
|
165
|
+
"@directus/storage-driver-local": "10.0.20",
|
|
166
|
+
"@directus/storage-driver-supabase": "1.0.14",
|
|
167
|
+
"@directus/storage-driver-s3": "10.0.23",
|
|
168
|
+
"@directus/system-data": "1.0.4",
|
|
169
|
+
"@directus/utils": "11.0.9",
|
|
170
|
+
"directus": "10.12.0",
|
|
171
|
+
"@directus/validation": "0.0.17"
|
|
172
172
|
},
|
|
173
173
|
"devDependencies": {
|
|
174
174
|
"@ngneat/falso": "7.2.0",
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
"vitest": "1.5.3",
|
|
212
212
|
"@directus/random": "0.2.8",
|
|
213
213
|
"@directus/tsconfig": "1.0.1",
|
|
214
|
-
"@directus/types": "11.1.
|
|
214
|
+
"@directus/types": "11.1.2"
|
|
215
215
|
},
|
|
216
216
|
"optionalDependencies": {
|
|
217
217
|
"@keyv/redis": "2.8.4",
|