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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
import { HttpError } from 'wasp/server'; import { HttpError } from 'wasp/server';
import * as z from 'zod'; import * as z from 'zod';
export function ensureArgsSchemaOrThrowHttpError<Schema extends z.ZodType<any, any>>( export function ensureArgsSchemaOrThrowHttpError<Schema extends z.ZodType>(
schema: Schema, schema: Schema,
rawArgs: unknown rawArgs: unknown
): z.infer<Schema> { ): z.infer<Schema> {
@@ -9,6 +9,7 @@ export function ensureArgsSchemaOrThrowHttpError<Schema extends z.ZodType<any, a
if (!parseResult.success) { if (!parseResult.success) {
console.error(parseResult.error); console.error(parseResult.error);
throw new HttpError(400, 'Operation arguments validation failed', { errors: parseResult.error.errors }); 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>; type UpdateUserAdminByIdInput = z.infer<typeof updateUserAdminByIdInputSchema>;
export const updateIsUserAdminById: UpdateIsUserAdminById<UpdateUserAdminByIdInput, User> = async ( export const updateIsUserAdminById: UpdateIsUserAdminById<UpdateUserAdminByIdInput, User> = async (
rawArgs: unknown, rawArgs,
context context
) => { ) => {
const args = ensureArgsSchemaOrThrowHttpError(updateUserAdminByIdInputSchema, rawArgs); const { id, data } = ensureArgsSchemaOrThrowHttpError(updateUserAdminByIdInputSchema, rawArgs);
if (!context.user) { if (!context.user) {
throw new HttpError(401); throw new HttpError(401);
@@ -30,10 +30,10 @@ export const updateIsUserAdminById: UpdateIsUserAdminById<UpdateUserAdminByIdInp
const updatedUser = await context.entities.User.update({ const updatedUser = await context.entities.User.update({
where: { where: {
id: args.id, id: id,
}, },
data: { data: {
isAdmin: args.data.isAdmin, isAdmin: data.isAdmin,
}, },
}); });
@@ -56,32 +56,35 @@ const getPaginatorArgsSchema = z.object({
type GetPaginatedUsersInput = z.infer<typeof getPaginatorArgsSchema>; type GetPaginatedUsersInput = z.infer<typeof getPaginatorArgsSchema>;
export const getPaginatedUsers: GetPaginatedUsers<GetPaginatedUsersInput, GetPaginatedUsersOutput> = async ( export const getPaginatedUsers: GetPaginatedUsers<GetPaginatedUsersInput, GetPaginatedUsersOutput> = async (
rawArgs: unknown, rawArgs,
context context
) => { ) => {
const args = ensureArgsSchemaOrThrowHttpError(getPaginatorArgsSchema, rawArgs); const { skip, cursor, emailContains, isAdmin, subscriptionStatus } = ensureArgsSchemaOrThrowHttpError(
getPaginatorArgsSchema,
rawArgs
);
if (!context.user?.isAdmin) { if (!context.user?.isAdmin) {
throw new HttpError(401); throw new HttpError(401);
} }
const allSubscriptionStatusOptions = args.subscriptionStatus; const allSubscriptionStatusOptions = subscriptionStatus;
const hasNotSubscribed = allSubscriptionStatusOptions?.find((status) => status === null); const hasNotSubscribed = allSubscriptionStatusOptions?.find((status) => status === null);
let subscriptionStatusStrings = allSubscriptionStatusOptions?.filter((status) => status !== null) as let subscriptionStatusStrings = allSubscriptionStatusOptions?.filter((status) => status !== null) as
| string[] | string[]
| undefined; | undefined;
const queryResults = await context.entities.User.findMany({ const queryResults = await context.entities.User.findMany({
skip: args.skip, skip,
take: 10, take: 10,
where: { where: {
AND: [ AND: [
{ {
email: { email: {
contains: args.emailContains || undefined, contains: emailContains || undefined,
mode: 'insensitive', mode: 'insensitive',
}, },
isAdmin: args.isAdmin, isAdmin,
}, },
{ {
OR: [ OR: [
@@ -117,10 +120,10 @@ export const getPaginatedUsers: GetPaginatedUsers<GetPaginatedUsersInput, GetPag
AND: [ AND: [
{ {
email: { email: {
contains: args.emailContains || undefined, contains: emailContains || undefined,
mode: 'insensitive', mode: 'insensitive',
}, },
isAdmin: args.isAdmin, isAdmin,
}, },
{ {
OR: [ OR: [