From a57a44847bd3dfb3d55c97f6798648c3742f445d Mon Sep 17 00:00:00 2001 From: Qmi Date: Sun, 15 Dec 2024 17:35:52 +0700 Subject: [PATCH 1/2] fix: lint issues --- server/api/files/ls.get.ts | 125 +++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 18 deletions(-) diff --git a/server/api/files/ls.get.ts b/server/api/files/ls.get.ts index a690c77..e6becf3 100644 --- a/server/api/files/ls.get.ts +++ b/server/api/files/ls.get.ts @@ -1,41 +1,130 @@ -import * as db from 'zapatos/db'; -import { dbPool } from '~/db/connection'; -import { FileLsErrorCode } from '~/lib'; -import { VirtualPath } from '~/lib/path'; -import { AccessType, canAccess, FileType, trimQuote } from '~/server/utils'; +import * as db from "zapatos/db"; +import { dbPool } from "~/db/connection"; +import { FileLsErrorCode } from "~/lib"; +import { VirtualPath } from "~/lib/path"; +import { AccessType, canAccess, FileType, trimQuote } from "~/server/utils"; export default defineEventHandler(async (event) => { const { name } = getQuery(event); - if (typeof name !== 'string') { - return { error: { code: FileLsErrorCode.INVALID_PARAM, message: 'Expect the "name" query param to be string' } }; + if (typeof name !== "string") { + return { + error: { + code: FileLsErrorCode.INVALID_PARAM, + message: 'Expect the "name" query param to be string', + }, + }; } if (!event.context.auth) { - return { error: { code: FileLsErrorCode.NOT_ENOUGH_PRIVILEGE, message: 'Should be logged in as a user with enough privilege' } }; + return { + error: { + code: FileLsErrorCode.NOT_ENOUGH_PRIVILEGE, + message: "Should be logged in as a user with enough privilege", + }, + }; } const filepath = VirtualPath.create(trimQuote(name)); if (!filepath.isValid()) { - return { error: { code: FileLsErrorCode.INVALID_PARAM, message: 'Expect the "name" query param to be valid path' } }; + return { + error: { + code: FileLsErrorCode.INVALID_PARAM, + message: 'Expect the "name" query param to be valid path', + }, + }; } try { - const { permission_bits: filePermissionBits, owner_id: fileOwnerId, group_id: fileGroupId, file_type: fileType, created_at: createdAt, updated_at: updatedAt } = await db.selectExactlyOne('files', { name: filepath.toString(), deleted_at: db.conditions.isNull }).run(dbPool); + const { + permission_bits: filePermissionBits, + owner_id: fileOwnerId, + group_id: fileGroupId, + file_type: fileType, + created_at: createdAt, + updated_at: updatedAt, + } = await db.selectExactlyOne("files", { + name: filepath.toString(), + deleted_at: db.conditions.isNull, + }).run(dbPool); if ( !canAccess( - { userId: event.context.auth.userId as number, groupId: event.context.auth.groupId as number }, - { fileType: FileType.UNKNOWN, ownerId: fileOwnerId, groupId: fileGroupId, permissionBits: filePermissionBits }, + { + userId: event.context.auth.userId as number, + groupId: event.context.auth.groupId as number, + }, + { + fileType: FileType.UNKNOWN, + ownerId: fileOwnerId, + groupId: fileGroupId, + permissionBits: filePermissionBits, + }, AccessType.EXECUTE, ) ) { - return { error: { code: FileLsErrorCode.NOT_ENOUGH_PRIVILEGE, message: 'Should be logged in as a user with enough privilege' } }; + return { + error: { + code: FileLsErrorCode.NOT_ENOUGH_PRIVILEGE, + message: "Should be logged in as a user with enough privilege", + }, + }; } - if (fileType === 'file') { - return { ok: { message: 'Fetch file meta successfully', data: { files: [{ name: filepath.toString(), ownerId: fileOwnerId, groupId: fileGroupId, fileType: fileType, createdAt, updatedAt, permissionBits: filePermissionBits }] } } }; + if (fileType === "file") { + return { + ok: { + message: "Fetch file meta successfully", + data: { + files: [{ + name: filepath.toString(), + ownerId: fileOwnerId, + groupId: fileGroupId, + fileType: fileType, + createdAt, + updatedAt, + permissionBits: filePermissionBits, + }], + }, + }, + }; } - const files = await db.select('files', { name: db.conditions.and(db.conditions.like(`${filepath.toString()}/%`), db.conditions.notLike(`${filepath.toString()}/%/%`)), deleted_at: db.conditions.isNull }).run(dbPool); + const files = await db.select("files", { + name: db.conditions.and( + db.conditions.like(`${filepath.toString()}/%`), + db.conditions.notLike(`${filepath.toString()}/%/%`), + ), + deleted_at: db.conditions.isNull, + }).run(dbPool); - return { ok: { message: 'Fetch folder\'s content successfully', data: { files: files.map(({ permission_bits, updated_at, name, file_type, created_at, owner_id, group_id }) => ({ name, fileType: file_type, createdAt: created_at, ownerId: owner_id, groupId: group_id, permissionBits: permission_bits, updatedAt: updated_at })) } } }; + return { + ok: { + message: "Fetch folder's content successfully", + data: { + files: files.map(( + { + permission_bits, + updated_at, + name, + file_type, + created_at, + owner_id, + group_id, + }, + ) => ({ + name, + fileType: file_type, + createdAt: created_at, + ownerId: owner_id, + groupId: group_id, + permissionBits: permission_bits, + updatedAt: updated_at, + })), + }, + }, + }; } catch { - return { error: { code: FileLsErrorCode.FILE_NOT_FOUND, message: 'File not found' } }; + return { + error: { + code: FileLsErrorCode.FILE_NOT_FOUND, + message: "File not found", + }, + }; } }); From dd7a48984432050036e542dd8a3bc30f819794d4 Mon Sep 17 00:00:00 2001 From: Qmi Date: Sun, 15 Dec 2024 18:43:56 +0700 Subject: [PATCH 2/2] fix: add group and user info in ls --- lib/command/impls/ls.ts | 6 +- server/api/files/ls.get.ts | 140 +++++++++---------------------------- services/files.ts | 4 ++ 3 files changed, 39 insertions(+), 111 deletions(-) diff --git a/lib/command/impls/ls.ts b/lib/command/impls/ls.ts index a7a26e9..8adaeb7 100644 --- a/lib/command/impls/ls.ts +++ b/lib/command/impls/ls.ts @@ -1,8 +1,6 @@ -import { userService } from '~/services/users'; import { formatArg } from '../utils'; import type { AsyncCommandFunc } from './types'; import { fileService } from '~/services/files'; -import { groupService } from '~/services/groups'; export const ls: AsyncCommandFunc = async function (...args) { // discard `ls` @@ -21,8 +19,8 @@ export const ls: AsyncCommandFunc = async function (...args) { for (const file of files) { const fileType = formatFileType(file.fileType as string); const filePermissionBits = formatPermissionBits(file.permission as unknown as string); - const fileOwner = (await userService.getMetaOfUser(file.ownerId)).unwrap().name; - const fileGroup = (await groupService.getMetaOfGroup(file.groupId)).unwrap().name; + const fileOwner = file.ownerName; + const fileGroup = file.groupName; fileLines.push(`${fileType}${filePermissionBits} ${fileOwner} ${fileGroup} ${file.name}`); } return [ diff --git a/server/api/files/ls.get.ts b/server/api/files/ls.get.ts index e6becf3..48cd6bd 100644 --- a/server/api/files/ls.get.ts +++ b/server/api/files/ls.get.ts @@ -1,130 +1,56 @@ -import * as db from "zapatos/db"; -import { dbPool } from "~/db/connection"; -import { FileLsErrorCode } from "~/lib"; -import { VirtualPath } from "~/lib/path"; -import { AccessType, canAccess, FileType, trimQuote } from "~/server/utils"; +import * as db from 'zapatos/db'; +import { dbPool } from '~/db/connection'; +import { FileLsErrorCode } from '~/lib'; +import { VirtualPath } from '~/lib/path'; +import { AccessType, canAccess, FileType, trimQuote } from '~/server/utils'; export default defineEventHandler(async (event) => { const { name } = getQuery(event); - if (typeof name !== "string") { - return { - error: { - code: FileLsErrorCode.INVALID_PARAM, - message: 'Expect the "name" query param to be string', - }, - }; + if (typeof name !== 'string') { + return { error: { code: FileLsErrorCode.INVALID_PARAM, message: 'Expect the "name" query param to be string' } }; } if (!event.context.auth) { - return { - error: { - code: FileLsErrorCode.NOT_ENOUGH_PRIVILEGE, - message: "Should be logged in as a user with enough privilege", - }, - }; + return { error: { code: FileLsErrorCode.NOT_ENOUGH_PRIVILEGE, message: 'Should be logged in as a user with enough privilege' } }; } const filepath = VirtualPath.create(trimQuote(name)); if (!filepath.isValid()) { - return { - error: { - code: FileLsErrorCode.INVALID_PARAM, - message: 'Expect the "name" query param to be valid path', - }, - }; + return { error: { code: FileLsErrorCode.INVALID_PARAM, message: 'Expect the "name" query param to be valid path' } }; } try { - const { - permission_bits: filePermissionBits, - owner_id: fileOwnerId, - group_id: fileGroupId, - file_type: fileType, - created_at: createdAt, - updated_at: updatedAt, - } = await db.selectExactlyOne("files", { - name: filepath.toString(), - deleted_at: db.conditions.isNull, - }).run(dbPool); + const [{ permission_bits: filePermissionBits, owner_id: fileOwnerId, owner_name: ownerName, group_name: groupName, group_id: fileGroupId, file_type: fileType, created_at: createdAt, updated_at: updatedAt }] = await db.sql` + SELECT permission_bits, ${'files'}.${'name'}, owner_id, ${'users'}.${'name'} AS owner_name, ${'files'}.${'group_id'}, ${'groups'}.${'name'} AS group_name, file_type, ${'files'}.created_at, ${'files'}.updated_at + FROM ${'files'} + JOIN ${'users'} ON ${'files'}.${'owner_id'} = ${'users'}.${'id'} + JOIN ${'groups'} ON ${'files'}.${'group_id'} = ${'groups'}.${'id'} + WHERE ${'files'}.${'deleted_at'} IS NULL + AND ${'files'}.${'name'} = ${db.param(filepath.toString())} + `.run(dbPool); if ( !canAccess( - { - userId: event.context.auth.userId as number, - groupId: event.context.auth.groupId as number, - }, - { - fileType: FileType.UNKNOWN, - ownerId: fileOwnerId, - groupId: fileGroupId, - permissionBits: filePermissionBits, - }, + { userId: event.context.auth.userId as number, groupId: event.context.auth.groupId as number }, + { fileType: FileType.UNKNOWN, ownerId: fileOwnerId, groupId: fileGroupId, permissionBits: filePermissionBits }, AccessType.EXECUTE, ) ) { - return { - error: { - code: FileLsErrorCode.NOT_ENOUGH_PRIVILEGE, - message: "Should be logged in as a user with enough privilege", - }, - }; + return { error: { code: FileLsErrorCode.NOT_ENOUGH_PRIVILEGE, message: 'Should be logged in as a user with enough privilege' } }; } - if (fileType === "file") { - return { - ok: { - message: "Fetch file meta successfully", - data: { - files: [{ - name: filepath.toString(), - ownerId: fileOwnerId, - groupId: fileGroupId, - fileType: fileType, - createdAt, - updatedAt, - permissionBits: filePermissionBits, - }], - }, - }, - }; + if (fileType === 'file') { + return { ok: { message: 'Fetch file meta successfully', data: { files: [{ name: filepath.toString(), ownerId: fileOwnerId, ownerName, groupName, groupId: fileGroupId, fileType: fileType, createdAt, updatedAt, permissionBits: filePermissionBits }] } } }; } - const files = await db.select("files", { - name: db.conditions.and( - db.conditions.like(`${filepath.toString()}/%`), - db.conditions.notLike(`${filepath.toString()}/%/%`), - ), - deleted_at: db.conditions.isNull, - }).run(dbPool); + const files = await db.sql` + SELECT permission_bits, ${'files'}.${'name'}, owner_id, ${'users'}.${'name'} AS owner_name, ${'files'}.${'group_id'}, ${'groups'}.${'name'} AS group_name, file_type, ${'files'}.created_at, ${'files'}.updated_at + FROM ${'files'} + JOIN ${'users'} ON ${'files'}.${'owner_id'} = ${'users'}.${'id'} + JOIN ${'groups'} ON ${'files'}.${'group_id'} = ${'groups'}.${'id'} + WHERE ${'files'}.${'deleted_at'} IS NULL + AND ${'files'}.${'name'} LIKE ${db.param(`${filepath.toString()}/%`)} + AND ${'files'}.${'name'} NOT LIKE ${db.param(`${filepath.toString()}/%/%`)} + `.run(dbPool); - return { - ok: { - message: "Fetch folder's content successfully", - data: { - files: files.map(( - { - permission_bits, - updated_at, - name, - file_type, - created_at, - owner_id, - group_id, - }, - ) => ({ - name, - fileType: file_type, - createdAt: created_at, - ownerId: owner_id, - groupId: group_id, - permissionBits: permission_bits, - updatedAt: updated_at, - })), - }, - }, - }; + return { ok: { message: 'Fetch folder\'s content successfully', data: { files: files.map(({ permission_bits, updated_at, name, file_type, created_at, owner_id, group_id, owner_name, group_name }) => ({ name, fileType: file_type, createdAt: created_at, ownerId: owner_id, groupId: group_id, permissionBits: permission_bits, updatedAt: updated_at, groupName: group_name, ownerName: owner_name })) } } }; } catch { - return { - error: { - code: FileLsErrorCode.FILE_NOT_FOUND, - message: "File not found", - }, - }; + return { error: { code: FileLsErrorCode.FILE_NOT_FOUND, message: 'File not found' } }; } }); diff --git a/services/files.ts b/services/files.ts index e4d0906..cffa7ad 100644 --- a/services/files.ts +++ b/services/files.ts @@ -30,7 +30,9 @@ export interface FileMeta { fullName: string; permission: FilePermission; ownerId: number; + ownerName: string; groupId: number; + groupName: string; createdAt: Date; updatedAt: Date; fileType: string; @@ -115,6 +117,8 @@ export const fileService = { createdAt: file.createdAt, updatedAt: file.updatedAt, fileType: file.fileType, + ownerName: file.ownerName, + groupName: file.groupName, }))); }, async removeFile (filename: string): Promise> {