Simple User Quota (#367)

* Simple User Quota
* 👷Fix build with OpenSearch
This commit is contained in:
Anton Shepilov
2024-02-22 10:17:25 +01:00
committed by GitHub
parent df0809ec48
commit 63f2c281c0
34 changed files with 10549 additions and 5836 deletions
@@ -33,6 +33,10 @@ import { getPublicUserRoom, getUserRoom } from "../../realtime";
import NodeCache from "node-cache";
import gr from "../../../global-resolver";
import { formatUser } from "../../../../utils/users";
import { getDefaultDriveItem } from "../../../documents/utils";
import { CompanyExecutionContext } from "../../../documents/types";
import { TYPE as DriveFileType, DriveFile } from "../../../documents/entities/drive-file";
import config from "config";
export class UserServiceImpl {
version: "1";
@@ -40,6 +44,7 @@ export class UserServiceImpl {
searchRepository: SearchRepository<User>;
companyUserRepository: Repository<CompanyUser>;
extUserRepository: Repository<ExternalUser>;
driveFileRepository: Repository<DriveFile>;
private deviceRepository: Repository<Device>;
private cache: NodeCache;
@@ -56,6 +61,7 @@ export class UserServiceImpl {
);
this.deviceRepository = await gr.database.getRepository<Device>(DeviceType, Device);
this.driveFileRepository = await gr.database.getRepository<DriveFile>(DriveFileType, DriveFile);
this.cache = new NodeCache({ stdTTL: 0.2, checkperiod: 120 });
@@ -64,6 +64,9 @@ export function formatCompany(
[CompanyFeaturesEnum.COMPANY_DISPLAY_EMAIL]: JSON.parse(
config.get("drive.featureDisplayEmail") || "true",
),
[CompanyFeaturesEnum.COMPANY_USER_QUOTA]: JSON.parse(
config.get("drive.featureUserQuota") || "false",
),
},
{
...(res.plan?.features || {}),
@@ -27,6 +27,7 @@ import {
UserObject,
UserParameters,
CompanyUsersParameters,
UserQuota,
} from "./types";
import Company from "../entities/company";
import CompanyUser from "../entities/company_user";
@@ -35,6 +36,7 @@ import { getCompanyRooms, getUserRooms } from "../realtime";
import { formatCompany, getCompanyStats } from "../utils";
import { formatUser } from "../../../utils/users";
import gr from "../../global-resolver";
import config from "config";
export class UsersCrudController
implements
@@ -318,6 +320,40 @@ export class UsersCrudController
resources: [],
};
}
async qouta(
request: FastifyRequest<{
Params: UserParameters;
Querystring: CompanyUsersParameters;
}>,
_reply: FastifyReply,
): Promise<UserQuota> {
const context = getExecutionContext(request);
let id = request.params.id;
if (request.params.id === "me") {
id = context.user.id;
}
if (id != context.user.id) {
//if admin or application wants to know user quota, it's not implemented yet
throw new Error("Not implemented yes");
}
const quota = await gr.services.documents.documents.userQuota({
...context,
company: { id: request.query.companyId || config.get("drive.defaultCompany") },
});
const total: number = config.has("drive.defaultUserQuota")
? config.get("drive.defaultUserQuota")
: NaN;
return {
total: total,
remaining: isNaN(total) ? NaN : total - quota,
used: quota,
} as UserQuota;
}
}
function getExecutionContext(request: FastifyRequest): ExecutionContext {
@@ -4,6 +4,7 @@ import {
deleteDeviceSchema,
getCompanySchema,
getDevicesSchema,
getQuotaSchema,
getUserCompaniesSchema,
getUserSchema,
getUsersSchema,
@@ -33,6 +34,15 @@ const routes: FastifyPluginCallback = (fastify: FastifyInstance, options, next)
handler: usersController.get.bind(usersController),
});
fastify.route({
method: "GET",
url: `${usersUrl}/:id/quota`,
preHandler: accessControl,
preValidation: fastify.authenticate,
schema: getQuotaSchema,
handler: usersController.qouta.bind(usersController),
});
fastify.route({
method: "POST",
url: `${usersUrl}/me/preferences`,
@@ -95,6 +95,7 @@ export const companyObjectSchema = {
[CompanyFeaturesEnum.COMPANY_SEARCH_USERS]: { type: "boolean" },
[CompanyFeaturesEnum.COMPANY_SHARED_DRIVE]: { type: "boolean" },
[CompanyFeaturesEnum.COMPANY_DISPLAY_EMAIL]: { type: "boolean" },
[CompanyFeaturesEnum.COMPANY_USER_QUOTA]: { type: "boolean" },
guests: { type: "number" }, // to rename or delete
members: { type: "number" }, // to rename or delete
storage: { type: "number" }, // to rename or delete
@@ -143,6 +144,34 @@ export const getUserSchema = {
},
};
export const getQuotaSchema = {
type: "object",
properties: {
companyId: { type: "string" },
},
response: {
"2xx": {
type: "object",
properties: {
used: { type: "number" },
remaining: { type: "number" },
total: { type: "number" },
},
},
},
tags: ["User"],
params: {
type: "object",
description: "Users",
properties: {
id: {
description: "User ID",
type: "string",
},
},
},
};
export const setUserPreferencesSchema = {
request: {
properties: {
@@ -14,7 +14,7 @@ export interface UserParameters {
}
export interface CompanyUsersParameters {
/* user id */
/* company id */
companyId: string;
}
@@ -86,6 +86,7 @@ export enum CompanyFeaturesEnum {
COMPANY_SEARCH_USERS = "company:search_users",
COMPANY_SHARED_DRIVE = "company:shared_drive",
COMPANY_DISPLAY_EMAIL = "company:display_email",
COMPANY_USER_QUOTA = "company:user_quota",
}
export type CompanyFeaturesObject = {
@@ -98,6 +99,7 @@ export type CompanyFeaturesObject = {
[CompanyFeaturesEnum.COMPANY_SEARCH_USERS]?: boolean;
[CompanyFeaturesEnum.COMPANY_SHARED_DRIVE]?: boolean;
[CompanyFeaturesEnum.COMPANY_DISPLAY_EMAIL]?: boolean;
[CompanyFeaturesEnum.COMPANY_USER_QUOTA]?: boolean;
};
export type CompanyLimitsObject = {
@@ -144,3 +146,9 @@ export interface RegisterDeviceParams {
export interface DeregisterDeviceParams {
value: "string";
}
export interface UserQuota {
used: number;
remaining: number;
total: number;
}