refactoring

Resolve #7779
This commit is contained in:
syuilo
2021-11-12 02:02:25 +09:00
parent 037837b551
commit 0e4a111f81
1714 changed files with 20803 additions and 11751 deletions

View File

@@ -0,0 +1,57 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
import { DriveFiles, Notes } from '@/models/index';
export const meta = {
tags: ['drive', 'notes'],
requireCredential: true as const,
kind: 'read:drive',
params: {
fileId: {
validator: $.type(ID),
}
},
res: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'Note',
}
},
errors: {
noSuchFile: {
message: 'No such file.',
code: 'NO_SUCH_FILE',
id: 'c118ece3-2e4b-4296-99d1-51756e32d232',
}
}
};
export default define(meta, async (ps, user) => {
// Fetch file
const file = await DriveFiles.findOne({
id: ps.fileId,
userId: user.id,
});
if (file == null) {
throw new ApiError(meta.errors.noSuchFile);
}
const notes = await Notes.createQueryBuilder('note')
.where(':file = ANY(note.fileIds)', { file: file.id })
.getMany();
return await Notes.packMany(notes, user, {
detail: true
});
});

View File

@@ -0,0 +1,31 @@
import $ from 'cafy';
import define from '../../../define';
import { DriveFiles } from '@/models/index';
export const meta = {
tags: ['drive'],
requireCredential: true as const,
kind: 'read:drive',
params: {
md5: {
validator: $.str,
}
},
res: {
type: 'boolean' as const,
optional: false as const, nullable: false as const,
},
};
export default define(meta, async (ps, user) => {
const file = await DriveFiles.findOne({
md5: ps.md5,
userId: user.id,
});
return file != null;
});

View File

@@ -0,0 +1,89 @@
import * as ms from 'ms';
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import create from '@/services/drive/add-file';
import define from '../../../define';
import { apiLogger } from '../../../logger';
import { ApiError } from '../../../error';
import { DriveFiles } from '@/models/index';
export const meta = {
tags: ['drive'],
requireCredential: true as const,
limit: {
duration: ms('1hour'),
max: 120
},
requireFile: true,
kind: 'write:drive',
params: {
folderId: {
validator: $.optional.nullable.type(ID),
default: null,
},
name: {
validator: $.optional.nullable.str,
default: null,
},
isSensitive: {
validator: $.optional.either($.bool, $.str),
default: false,
transform: (v: any): boolean => v === true || v === 'true',
},
force: {
validator: $.optional.either($.bool, $.str),
default: false,
transform: (v: any): boolean => v === true || v === 'true',
}
},
res: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'DriveFile',
},
errors: {
invalidFileName: {
message: 'Invalid file name.',
code: 'INVALID_FILE_NAME',
id: 'f449b209-0c60-4e51-84d5-29486263bfd4'
}
}
};
export default define(meta, async (ps, user, _, file, cleanup) => {
// Get 'name' parameter
let name = ps.name || file.originalname;
if (name !== undefined && name !== null) {
name = name.trim();
if (name.length === 0) {
name = null;
} else if (name === 'blob') {
name = null;
} else if (!DriveFiles.validateFileName(name)) {
throw new ApiError(meta.errors.invalidFileName);
}
} else {
name = null;
}
try {
// Create file
const driveFile = await create(user, file.path, name, null, ps.folderId, ps.force, false, null, null, ps.isSensitive);
return await DriveFiles.pack(driveFile, { self: true });
} catch (e) {
apiLogger.error(e);
throw new ApiError();
} finally {
cleanup!();
}
});

View File

@@ -0,0 +1,53 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import { deleteFile } from '@/services/drive/delete-file';
import { publishDriveStream } from '@/services/stream';
import define from '../../../define';
import { ApiError } from '../../../error';
import { DriveFiles } from '@/models/index';
export const meta = {
tags: ['drive'],
requireCredential: true as const,
kind: 'write:drive',
params: {
fileId: {
validator: $.type(ID),
}
},
errors: {
noSuchFile: {
message: 'No such file.',
code: 'NO_SUCH_FILE',
id: '908939ec-e52b-4458-b395-1025195cea58'
},
accessDenied: {
message: 'Access denied.',
code: 'ACCESS_DENIED',
id: '5eb8d909-2540-4970-90b8-dd6f86088121'
},
}
};
export default define(meta, async (ps, user) => {
const file = await DriveFiles.findOne(ps.fileId);
if (file == null) {
throw new ApiError(meta.errors.noSuchFile);
}
if (!user.isAdmin && !user.isModerator && (file.userId !== user.id)) {
throw new ApiError(meta.errors.accessDenied);
}
// Delete
await deleteFile(file);
// Publish fileDeleted event
publishDriveStream(user.id, 'fileDeleted', file.id);
});

View File

@@ -0,0 +1,36 @@
import $ from 'cafy';
import define from '../../../define';
import { DriveFiles } from '@/models/index';
export const meta = {
tags: ['drive'],
requireCredential: true as const,
kind: 'read:drive',
params: {
md5: {
validator: $.str,
}
},
res: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'DriveFile',
}
},
};
export default define(meta, async (ps, user) => {
const files = await DriveFiles.find({
md5: ps.md5,
userId: user.id,
});
return await DriveFiles.packMany(files, { self: true });
});

View File

@@ -0,0 +1,43 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { DriveFiles } from '@/models/index';
export const meta = {
requireCredential: true as const,
tags: ['drive'],
kind: 'read:drive',
params: {
name: {
validator: $.str
},
folderId: {
validator: $.optional.nullable.type(ID),
default: null,
},
},
res: {
type: 'array' as const,
optional: false as const, nullable: false as const,
items: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'DriveFile',
}
},
};
export default define(meta, async (ps, user) => {
const files = await DriveFiles.find({
name: ps.name,
userId: user.id,
folderId: ps.folderId
});
return await Promise.all(files.map(file => DriveFiles.pack(file, { self: true })));
});

View File

@@ -0,0 +1,84 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
import { DriveFile } from '@/models/entities/drive-file';
import { DriveFiles } from '@/models/index';
export const meta = {
tags: ['drive'],
requireCredential: true as const,
kind: 'read:drive',
params: {
fileId: {
validator: $.optional.type(ID),
},
url: {
validator: $.optional.str,
}
},
res: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'DriveFile',
},
errors: {
noSuchFile: {
message: 'No such file.',
code: 'NO_SUCH_FILE',
id: '067bc436-2718-4795-b0fb-ecbe43949e31'
},
accessDenied: {
message: 'Access denied.',
code: 'ACCESS_DENIED',
id: '25b73c73-68b1-41d0-bad1-381cfdf6579f'
},
fileIdOrUrlRequired: {
message: 'fileId or url required.',
code: 'INVALID_PARAM',
id: '89674805-722c-440c-8d88-5641830dc3e4'
}
}
};
export default define(meta, async (ps, user) => {
let file: DriveFile | undefined;
if (ps.fileId) {
file = await DriveFiles.findOne(ps.fileId);
} else if (ps.url) {
file = await DriveFiles.findOne({
where: [{
url: ps.url
}, {
webpublicUrl: ps.url
}, {
thumbnailUrl: ps.url
}],
});
} else {
throw new ApiError(meta.errors.fileIdOrUrlRequired);
}
if (file == null) {
throw new ApiError(meta.errors.noSuchFile);
}
if (!user.isAdmin && !user.isModerator && (file.userId !== user.id)) {
throw new ApiError(meta.errors.accessDenied);
}
return await DriveFiles.pack(file, {
detail: true,
withUser: true,
self: true
});
});

View File

@@ -0,0 +1,116 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import { publishDriveStream } from '@/services/stream';
import define from '../../../define';
import { ApiError } from '../../../error';
import { DriveFiles, DriveFolders } from '@/models/index';
import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits';
export const meta = {
tags: ['drive'],
requireCredential: true as const,
kind: 'write:drive',
params: {
fileId: {
validator: $.type(ID),
},
folderId: {
validator: $.optional.nullable.type(ID),
default: undefined as any,
},
name: {
validator: $.optional.str.pipe(DriveFiles.validateFileName),
default: undefined as any,
},
isSensitive: {
validator: $.optional.bool,
default: undefined as any,
},
comment: {
validator: $.optional.nullable.str.max(DB_MAX_IMAGE_COMMENT_LENGTH),
default: undefined as any,
}
},
errors: {
noSuchFile: {
message: 'No such file.',
code: 'NO_SUCH_FILE',
id: 'e7778c7e-3af9-49cd-9690-6dbc3e6c972d'
},
accessDenied: {
message: 'Access denied.',
code: 'ACCESS_DENIED',
id: '01a53b27-82fc-445b-a0c1-b558465a8ed2'
},
noSuchFolder: {
message: 'No such folder.',
code: 'NO_SUCH_FOLDER',
id: 'ea8fb7a5-af77-4a08-b608-c0218176cd73'
},
},
res: {
type: 'object' as const,
optional: false as const, nullable: false as const,
ref: 'DriveFile'
}
};
export default define(meta, async (ps, user) => {
const file = await DriveFiles.findOne(ps.fileId);
if (file == null) {
throw new ApiError(meta.errors.noSuchFile);
}
if (!user.isAdmin && !user.isModerator && (file.userId !== user.id)) {
throw new ApiError(meta.errors.accessDenied);
}
if (ps.name) file.name = ps.name;
if (ps.comment !== undefined) file.comment = ps.comment;
if (ps.isSensitive !== undefined) file.isSensitive = ps.isSensitive;
if (ps.folderId !== undefined) {
if (ps.folderId === null) {
file.folderId = null;
} else {
const folder = await DriveFolders.findOne({
id: ps.folderId,
userId: user.id
});
if (folder == null) {
throw new ApiError(meta.errors.noSuchFolder);
}
file.folderId = folder.id;
}
}
await DriveFiles.update(file.id, {
name: file.name,
comment: file.comment,
folderId: file.folderId,
isSensitive: file.isSensitive
});
const fileObj = await DriveFiles.pack(file, { self: true });
// Publish fileUpdated event
publishDriveStream(user.id, 'fileUpdated', fileObj);
return fileObj;
});

View File

@@ -0,0 +1,64 @@
import $ from 'cafy';
import { ID } from '@/misc/cafy-id';
import * as ms from 'ms';
import uploadFromUrl from '@/services/drive/upload-from-url';
import define from '../../../define';
import { DriveFiles } from '@/models/index';
import { publishMainStream } from '@/services/stream';
import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits';
export const meta = {
tags: ['drive'],
limit: {
duration: ms('1hour'),
max: 60
},
requireCredential: true as const,
kind: 'write:drive',
params: {
url: {
// TODO: Validate this url
validator: $.str,
},
folderId: {
validator: $.optional.nullable.type(ID),
default: null,
},
isSensitive: {
validator: $.optional.bool,
default: false,
},
comment: {
validator: $.optional.nullable.str.max(DB_MAX_IMAGE_COMMENT_LENGTH),
default: null,
},
marker: {
validator: $.optional.nullable.str,
default: null,
},
force: {
validator: $.optional.bool,
default: false,
}
}
};
export default define(meta, async (ps, user) => {
uploadFromUrl(ps.url, user, ps.folderId, null, ps.isSensitive, ps.force, false, ps.comment).then(file => {
DriveFiles.pack(file, { self: true }).then(packedFile => {
publishMainStream(user.id, 'urlUploadFinished', {
marker: ps.marker,
file: packedFile
});
});
});
});