mirror of
https://github.com/wasp-lang/open-saas.git
synced 2025-11-23 21:56:42 +01:00
Simplify code
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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: [
|
||||||
|
|||||||
Reference in New Issue
Block a user