Files
outline/server/models/FileOperation.ts
Tom Moor a326e0ee88 chore: Rate limiter audit (#3965)
* chore: Rate limiter audit api/users

* Make requests required

* api/collections

* Remove checkRateLimit on FileOperation (now done at route level through rate limiter)

* auth rate limit

* Add metric logging when rate limit exceeded

* Refactor to shared configs

* test
2022-08-14 08:04:04 -07:00

140 lines
2.6 KiB
TypeScript

import { Op, WhereOptions } from "sequelize";
import {
ForeignKey,
DefaultScope,
Column,
BeforeDestroy,
BelongsTo,
Table,
DataType,
} from "sequelize-typescript";
import { deleteFromS3, getFileByKey } from "@server/utils/s3";
import Collection from "./Collection";
import Team from "./Team";
import User from "./User";
import IdModel from "./base/IdModel";
import Fix from "./decorators/Fix";
export enum FileOperationType {
Import = "import",
Export = "export",
}
export enum FileOperationFormat {
MarkdownZip = "outline-markdown",
Notion = "notion",
}
export enum FileOperationState {
Creating = "creating",
Uploading = "uploading",
Complete = "complete",
Error = "error",
Expired = "expired",
}
@DefaultScope(() => ({
include: [
{
model: User,
as: "user",
paranoid: false,
},
{
model: Collection,
as: "collection",
paranoid: false,
},
],
}))
@Table({ tableName: "file_operations", modelName: "file_operation" })
@Fix
class FileOperation extends IdModel {
@Column(DataType.ENUM(...Object.values(FileOperationType)))
type: FileOperationType;
@Column(DataType.STRING)
format: FileOperationFormat;
@Column(DataType.ENUM(...Object.values(FileOperationState)))
state: FileOperationState;
@Column
key: string;
@Column
url: string;
@Column
error: string | null;
@Column(DataType.BIGINT)
size: number;
expire = async function () {
this.state = "expired";
await deleteFromS3(this.key);
await this.save();
};
get buffer() {
return getFileByKey(this.key);
}
// hooks
@BeforeDestroy
static async deleteFileFromS3(model: FileOperation) {
await deleteFromS3(model.key);
}
// associations
@BelongsTo(() => User, "userId")
user: User;
@ForeignKey(() => User)
@Column(DataType.UUID)
userId: string;
@BelongsTo(() => Team, "teamId")
team: Team;
@ForeignKey(() => Team)
@Column(DataType.UUID)
teamId: string;
@BelongsTo(() => Collection, "collectionId")
collection: Collection;
@ForeignKey(() => Collection)
@Column(DataType.UUID)
collectionId: string;
/**
* Count the number of export file operations for a given team after a point
* in time.
*
* @param teamId The team id
* @param startDate The start time
* @returns The number of file operations
*/
static async countExportsAfterDateTime(
teamId: string,
startDate: Date,
where: WhereOptions<FileOperation> = {}
): Promise<number> {
return this.count({
where: {
teamId,
createdAt: {
[Op.gt]: startDate,
},
...where,
},
});
}
}
export default FileOperation;