mirror of
https://github.com/wasp-lang/open-saas.git
synced 2025-04-13 14:29:04 +02:00
Simplify code
This commit is contained in:
parent
077bede063
commit
e270084101
@ -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,
|
||||
|
@ -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,
|
||||
},
|
||||
{
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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 });
|
||||
};
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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: [
|
||||
|
Loading…
x
Reference in New Issue
Block a user