Simplify code

This commit is contained in:
Mihovil Ilakovac 2025-02-21 20:04:20 +01:00
parent 077bede063
commit e270084101
9 changed files with 69 additions and 76 deletions

View File

@ -2,7 +2,7 @@
+++ opensaas-sh/app/src/file-upload/operations.ts
@@ -25,6 +25,18 @@
const args = ensureArgsSchemaOrThrowHttpError(createFileInputSchema, rawArgs);
const { fileType, fileName } = ensureArgsSchemaOrThrowHttpError(createFileInputSchema, rawArgs);
+ const numberOfFilesByUser = await context.entities.File.count({
+ where: {
@ -17,5 +17,5 @@
+ }
+
const { uploadUrl, key } = await getUploadFileSignedURLFromS3({
fileType: args.fileType,
fileName: args.fileName,
fileType,
fileName,

View File

@ -12,15 +12,15 @@
totalPages: number;
};
@@ -82,6 +85,7 @@
@@ -85,6 +88,7 @@
mode: 'insensitive',
},
isAdmin: args.isAdmin,
isAdmin,
+ isMockUser: true,
},
{
OR: [
@@ -105,7 +109,7 @@
@@ -108,7 +112,7 @@
username: true,
isAdmin: true,
subscriptionStatus: true,
@ -29,10 +29,10 @@
},
orderBy: {
id: 'desc',
@@ -121,6 +125,7 @@
@@ -124,6 +128,7 @@
mode: 'insensitive',
},
isAdmin: args.isAdmin,
isAdmin,
+ isMockUser: true,
},
{

View File

@ -30,14 +30,14 @@ const generateGptResponseInputSchema = z.object({
type GenerateGptResponseInput = z.infer<typeof generateGptResponseInputSchema>;
export const generateGptResponse: GenerateGptResponse<GenerateGptResponseInput, GeneratedSchedule> = async (
rawArgs: unknown,
rawArgs,
context
) => {
if (!context.user) {
throw new HttpError(401);
}
const args = ensureArgsSchemaOrThrowHttpError(generateGptResponseInputSchema, rawArgs);
const { hours } = ensureArgsSchemaOrThrowHttpError(generateGptResponseInputSchema, rawArgs);
const tasks = await context.entities.Task.findMany({
where: {
@ -89,9 +89,7 @@ export const generateGptResponse: GenerateGptResponse<GenerateGptResponseInput,
},
{
role: 'user',
content: `I will work ${
args.hours
} hours today. Here are the tasks I have to complete: ${JSON.stringify(
content: `I will work ${hours} hours today. Here are the tasks I have to complete: ${JSON.stringify(
parsedTasks
)}. Please help me plan my day by breaking the tasks down into actionable subtasks with time and priority status.`,
},
@ -199,16 +197,16 @@ const createTaskInputSchema = z.object({
type CreateTaskInput = z.infer<typeof createTaskInputSchema>;
export const createTask: CreateTask<CreateTaskInput, Task> = async (rawArgs: unknown, context) => {
export const createTask: CreateTask<CreateTaskInput, Task> = async (rawArgs, context) => {
if (!context.user) {
throw new HttpError(401);
}
const args = ensureArgsSchemaOrThrowHttpError(createTaskInputSchema, rawArgs);
const { description } = ensureArgsSchemaOrThrowHttpError(createTaskInputSchema, rawArgs);
const task = await context.entities.Task.create({
data: {
description: args.description,
description: description,
user: { connect: { id: context.user.id } },
},
});
@ -224,20 +222,20 @@ const updateTaskInputSchema = z.object({
type UpdateTaskInput = z.infer<typeof updateTaskInputSchema>;
export const updateTask: UpdateTask<UpdateTaskInput, Task> = async (rawArgs: unknown, context) => {
export const updateTask: UpdateTask<UpdateTaskInput, Task> = async (rawArgs, context) => {
if (!context.user) {
throw new HttpError(401);
}
const args = ensureArgsSchemaOrThrowHttpError(updateTaskInputSchema, rawArgs);
const { id, isDone, time } = ensureArgsSchemaOrThrowHttpError(updateTaskInputSchema, rawArgs);
const task = await context.entities.Task.update({
where: {
id: args.id,
id: id,
},
data: {
isDone: args.isDone,
time: args.time,
isDone: isDone,
time: time,
},
});
@ -250,16 +248,16 @@ const deleteTaskInputSchema = z.object({
type DeleteTaskInput = z.infer<typeof deleteTaskInputSchema>;
export const deleteTask: DeleteTask<DeleteTaskInput, Task> = async (rawArgs: unknown, context) => {
export const deleteTask: DeleteTask<DeleteTaskInput, Task> = async (rawArgs, context) => {
if (!context.user) {
throw new HttpError(401);
}
const args = ensureArgsSchemaOrThrowHttpError(deleteTaskInputSchema, rawArgs);
const { id } = ensureArgsSchemaOrThrowHttpError(deleteTaskInputSchema, rawArgs);
const task = await context.entities.Task.delete({
where: {
id: args.id,
id,
},
});

View File

@ -2,7 +2,12 @@ import { cn } from '../client/cn';
import { useState, useEffect, FormEvent } from 'react';
import type { File } from 'wasp/entities';
import { useQuery, getAllFilesByUser, getDownloadFileSignedURL } from 'wasp/client/operations';
import { type FileUploadError, parseValidFile, uploadFileWithProgress } from './fileUploading';
import {
type FileWithValidType,
type FileUploadError,
validateFile,
uploadFileWithProgress,
} from './fileUploading';
import { ALLOWED_FILE_TYPES } from './validation';
export default function FileUploadPage() {
@ -65,12 +70,13 @@ export default function FileUploadPage() {
return;
}
const validFileResult = parseValidFile(file);
if (validFileResult.kind === 'error') {
setUploadError(validFileResult.error);
const fileValidationError = validateFile(file);
if (fileValidationError !== null) {
setUploadError(fileValidationError);
return;
}
await uploadFileWithProgress({ file: validFileResult.file, setUploadProgressPercent });
await uploadFileWithProgress({ file: file as FileWithValidType, setUploadProgressPercent });
formElement.reset();
allUserFiles.refetch();
} catch (error) {

View File

@ -3,8 +3,8 @@ import { createFile } from 'wasp/client/operations';
import axios from 'axios';
import { ALLOWED_FILE_TYPES, MAX_FILE_SIZE } from './validation';
export type FileWithValidType = Omit<File, 'type'> & { type: AllowedFileType };
type AllowedFileType = (typeof ALLOWED_FILE_TYPES)[number];
type FileWithValidType = Omit<File, 'type'> & { type: AllowedFileType };
interface FileUploadProgress {
file: FileWithValidType;
setUploadProgressPercent: Dispatch<SetStateAction<number>>;
@ -30,38 +30,22 @@ export interface FileUploadError {
code: 'NO_FILE' | 'INVALID_FILE_TYPE' | 'FILE_TOO_LARGE' | 'UPLOAD_FAILED';
}
type FileParseResult =
| { kind: 'success'; file: FileWithValidType }
| {
kind: 'error';
error: { message: string; code: 'INVALID_FILE_TYPE' | 'FILE_TOO_LARGE' };
};
export function parseValidFile(file: File): FileParseResult {
export function validateFile(file: File) {
if (file.size > MAX_FILE_SIZE) {
return {
kind: 'error',
error: {
message: `File size exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,
code: 'FILE_TOO_LARGE',
},
message: `File size exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`,
code: 'FILE_TOO_LARGE' as const,
};
}
if (!isAllowedFileType(file.type)) {
return {
kind: 'error',
error: {
message: `File type '${file.type}' is not supported.`,
code: 'INVALID_FILE_TYPE',
},
message: `File type '${file.type}' is not supported.`,
code: 'INVALID_FILE_TYPE' as const,
};
}
return {
kind: 'success',
file: file as FileWithValidType,
};
return null;
}
function isAllowedFileType(fileType: string): fileType is AllowedFileType {

View File

@ -18,25 +18,25 @@ const createFileInputSchema = z.object({
type CreateFileInput = z.infer<typeof createFileInputSchema>;
export const createFile: CreateFile<CreateFileInput, File> = async (rawArgs: unknown, context) => {
export const createFile: CreateFile<CreateFileInput, File> = async (rawArgs, context) => {
if (!context.user) {
throw new HttpError(401);
}
const args = ensureArgsSchemaOrThrowHttpError(createFileInputSchema, rawArgs);
const { fileType, fileName } = ensureArgsSchemaOrThrowHttpError(createFileInputSchema, rawArgs);
const { uploadUrl, key } = await getUploadFileSignedURLFromS3({
fileType: args.fileType,
fileName: args.fileName,
fileType,
fileName,
userId: context.user.id,
});
return await context.entities.File.create({
data: {
name: args.fileName,
name: fileName,
key,
uploadUrl,
type: args.fileType,
type: fileType,
user: { connect: { id: context.user.id } },
},
});
@ -65,7 +65,7 @@ type GetDownloadFileSignedURLInput = z.infer<typeof getDownloadFileSignedURLInpu
export const getDownloadFileSignedURL: GetDownloadFileSignedURL<
GetDownloadFileSignedURLInput,
string
> = async (rawArgs: unknown, _context) => {
const args = ensureArgsSchemaOrThrowHttpError(getDownloadFileSignedURLInputSchema, rawArgs);
return await getDownloadFileSignedURLFromS3({ key: args.key });
> = async (rawArgs, _context) => {
const { key } = ensureArgsSchemaOrThrowHttpError(getDownloadFileSignedURLInputSchema, rawArgs);
return await getDownloadFileSignedURLFromS3({ key });
};

View File

@ -1,4 +1,5 @@
export const MAX_FILE_SIZE = 5 * 1024 * 1024; // Set this to the max file size you want to allow (currently 5MB).
// Set this to the max file size you want to allow (currently 5MB).
export const MAX_FILE_SIZE = 5 * 1024 * 1024;
export const ALLOWED_FILE_TYPES = [
'image/jpeg',
'image/png',

View File

@ -1,7 +1,7 @@
import { HttpError } from 'wasp/server';
import * as z from 'zod';
export function ensureArgsSchemaOrThrowHttpError<Schema extends z.ZodType<any, any>>(
export function ensureArgsSchemaOrThrowHttpError<Schema extends z.ZodType>(
schema: Schema,
rawArgs: unknown
): z.infer<Schema> {
@ -9,6 +9,7 @@ export function ensureArgsSchemaOrThrowHttpError<Schema extends z.ZodType<any, a
if (!parseResult.success) {
console.error(parseResult.error);
throw new HttpError(400, 'Operation arguments validation failed', { errors: parseResult.error.errors });
} else {
return parseResult.data;
}
return parseResult.data;
}

View File

@ -15,10 +15,10 @@ const updateUserAdminByIdInputSchema = z.object({
type UpdateUserAdminByIdInput = z.infer<typeof updateUserAdminByIdInputSchema>;
export const updateIsUserAdminById: UpdateIsUserAdminById<UpdateUserAdminByIdInput, User> = async (
rawArgs: unknown,
rawArgs,
context
) => {
const args = ensureArgsSchemaOrThrowHttpError(updateUserAdminByIdInputSchema, rawArgs);
const { id, data } = ensureArgsSchemaOrThrowHttpError(updateUserAdminByIdInputSchema, rawArgs);
if (!context.user) {
throw new HttpError(401);
@ -30,10 +30,10 @@ export const updateIsUserAdminById: UpdateIsUserAdminById<UpdateUserAdminByIdInp
const updatedUser = await context.entities.User.update({
where: {
id: args.id,
id: id,
},
data: {
isAdmin: args.data.isAdmin,
isAdmin: data.isAdmin,
},
});
@ -56,32 +56,35 @@ const getPaginatorArgsSchema = z.object({
type GetPaginatedUsersInput = z.infer<typeof getPaginatorArgsSchema>;
export const getPaginatedUsers: GetPaginatedUsers<GetPaginatedUsersInput, GetPaginatedUsersOutput> = async (
rawArgs: unknown,
rawArgs,
context
) => {
const args = ensureArgsSchemaOrThrowHttpError(getPaginatorArgsSchema, rawArgs);
const { skip, cursor, emailContains, isAdmin, subscriptionStatus } = ensureArgsSchemaOrThrowHttpError(
getPaginatorArgsSchema,
rawArgs
);
if (!context.user?.isAdmin) {
throw new HttpError(401);
}
const allSubscriptionStatusOptions = args.subscriptionStatus;
const allSubscriptionStatusOptions = subscriptionStatus;
const hasNotSubscribed = allSubscriptionStatusOptions?.find((status) => status === null);
let subscriptionStatusStrings = allSubscriptionStatusOptions?.filter((status) => status !== null) as
| string[]
| undefined;
const queryResults = await context.entities.User.findMany({
skip: args.skip,
skip,
take: 10,
where: {
AND: [
{
email: {
contains: args.emailContains || undefined,
contains: emailContains || undefined,
mode: 'insensitive',
},
isAdmin: args.isAdmin,
isAdmin,
},
{
OR: [
@ -117,10 +120,10 @@ export const getPaginatedUsers: GetPaginatedUsers<GetPaginatedUsersInput, GetPag
AND: [
{
email: {
contains: args.emailContains || undefined,
contains: emailContains || undefined,
mode: 'insensitive',
},
isAdmin: args.isAdmin,
isAdmin,
},
{
OR: [