Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(be): implement image upload #1514

Merged
merged 33 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d5906cd
feat(be): implement image upload to S3
Jaehyeon1020 Feb 27, 2024
3113831
docs(be): add upload image api docs
Jaehyeon1020 Feb 27, 2024
3444125
chore(be): modify image bucket baseurl
Jaehyeon1020 Feb 27, 2024
2088b0d
docs(be): add assert
Jaehyeon1020 Feb 27, 2024
ec52997
chore(be): add alt property to return type of image-upload api
Jaehyeon1020 Feb 28, 2024
14aa19c
chore(infra): rename testcase to storage
k1g99 Feb 29, 2024
89ff0f7
feat(infra): add env for media bucket
k1g99 Feb 29, 2024
e611dd9
chore(be): add sample image and modify return object
Jaehyeon1020 Mar 1, 2024
5d2d4fc
Optimised images with calibre/image-actions
github-actions[bot] Mar 1, 2024
048191f
chore(be): add s3-media-provider to test code
Jaehyeon1020 Mar 1, 2024
b27dbde
chore(be): use relative path for sample image
Jaehyeon1020 Mar 2, 2024
e1aff45
chore(be): replace client with media-client
Jaehyeon1020 Mar 4, 2024
800e5b3
feat(be): add delete-image function
Jaehyeon1020 Mar 4, 2024
061d5ba
refactor: combine bucket setup scripts
k1g99 Mar 7, 2024
7ee87a9
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 Mar 20, 2024
76ee2b9
fix(be): modify modify image size calculating logic
Jaehyeon1020 Mar 20, 2024
8b2b397
chore(be): modify filename to use uuid only
Jaehyeon1020 Mar 20, 2024
6966894
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 Mar 30, 2024
6331762
chore(be): remove duplicated import lines
Jaehyeon1020 Mar 30, 2024
0d32955
Merge branch 'main' into 1495-implement-image-upload
cho-to Mar 31, 2024
af56564
chore(be): remove file extension
Jaehyeon1020 Apr 1, 2024
a1237e4
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 Apr 1, 2024
4a50f98
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 Apr 5, 2024
095c345
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 Apr 6, 2024
fd79060
feat(be): add delete-image and improve image upload, delete logic
Jaehyeon1020 Apr 6, 2024
e5233fe
docs(be): add delete-image api docs
Jaehyeon1020 Apr 6, 2024
06e1cbd
chore(be): parallelize deleting image logic
Jaehyeon1020 Apr 9, 2024
dbc5dfc
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 May 5, 2024
cedef4a
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 May 14, 2024
209c2f9
chore(be): parallelize image-delete api
Jaehyeon1020 May 14, 2024
5f22f91
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 May 27, 2024
f6e48e5
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 May 27, 2024
faa68b4
Merge branch 'main' into 1495-implement-image-upload
Jaehyeon1020 May 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"database",
"cache",
"rabbitmq",
"testcase",
"storage",
"test-database"
],
"workspaceFolder": "/workspace",
Expand Down
11 changes: 10 additions & 1 deletion .env.stage
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,26 @@ RABBITMQ_CONSUMER_CONNECTION_NAME=iris-consumer
RABBITMQ_CONSUMER_TAG=consumer
RABBITMQ_PRODUCER_CONNECTION_NAME=iris-producer

# Storage
STORAGE_BUCKET_ENDPOINT_URL=http://127.0.0.1:9000
# Testcase Endpoint
TESTCASE_BUCKET_NAME=test-bucket
TESTCASE_ENDPOINT_URL=http://127.0.0.1:9000
# TESTCASE_ENDPOINT_URL=http://127.0.0.1:9000
TESTCASE_ACCESS_KEY=skku
TESTCASE_SECRET_KEY=skku1234

# Media Upload Endpoint
MEDIA_BUCKET_NAME=image-bucket
# MEDIA_BUCKET_BASE_URL=http://127.0.0.1:9000/image-bucket/
MEDIA_ACCESS_KEY=skku
MEDIA_SECRET_KEY=skku1234

REDIS_HOST=127.0.0.1
REDIS_PORT=6380

DATABASE_URL=postgresql://postgres:[email protected]:5433/skkuding?schema=public
TEST_DATABASE_URL=postgresql://postgres:[email protected]:5434/skkuding?schema=public


# TODO: Add information where each of these variables are used
# TODO: I want to edit values after the container is created...
2 changes: 1 addition & 1 deletion .gitpod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ports:
- port: 15672 # RabbitMQ Dashboard
onOpen: ignore

- port: 30000 # Testcase Server
- port: 30000 # Storage Server
onOpen: ignore

tasks:
Expand Down
7 changes: 7 additions & 0 deletions apps/backend/apps/admin/src/problem/model/image.output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Field, ObjectType } from '@nestjs/graphql'

@ObjectType({ description: 'image' })
export class ImageSource {
@Field(() => String)
src: string
}
3 changes: 2 additions & 1 deletion apps/backend/apps/admin/src/problem/problem.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Module } from '@nestjs/common'
import { ConfigModule } from '@nestjs/config'
import { StorageModule } from '@admin/storage/storage.module'
import { ProblemTagResolver, TagResolver } from './problem-tag.resolver'
import {
Expand All @@ -9,7 +10,7 @@ import {
import { ProblemService } from './problem.service'

@Module({
imports: [StorageModule],
imports: [StorageModule, ConfigModule],
providers: [
ProblemResolver,
ProblemTagResolver,
Expand Down
40 changes: 40 additions & 0 deletions apps/backend/apps/admin/src/problem/problem.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ import {
} from '@nestjs/graphql'
import {
ContestProblem,
Image,
Problem,
ProblemTag,
ProblemTestcase,
WorkbookProblem
} from '@generated'
import { Prisma } from '@prisma/client'
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'
import { AuthenticatedRequest } from '@libs/auth'
import { OPEN_SPACE_ID } from '@libs/constants'
import {
Expand All @@ -33,6 +35,7 @@ import {
UnprocessableDataException
} from '@libs/exception'
import { CursorValidationPipe, GroupIDPipe, RequiredIntPipe } from '@libs/pipe'
import { ImageSource } from './model/image.output'
import {
CreateProblemInput,
UploadFileInput,
Expand Down Expand Up @@ -105,6 +108,43 @@ export class ProblemResolver {
}
}

@Mutation(() => ImageSource)
async uploadImage(
@Args('input') input: UploadFileInput,
@Context('req') req: AuthenticatedRequest
) {
try {
return await this.problemService.uploadImage(input, req.user.id)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
}

@Mutation(() => Image)
async deleteImage(
@Args('filename') filename: string,
@Context('req') req: AuthenticatedRequest
) {
try {
return await this.problemService.deleteImage(filename, req.user.id)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw error.convert2HTTPException()
} else if (
error instanceof PrismaClientKnownRequestError &&
error.code == 'P2025'
) {
throw new NotFoundException(error.message)
Jaehyeon1020 marked this conversation as resolved.
Show resolved Hide resolved
}
this.logger.error(error)
throw new InternalServerErrorException()
}
}

@Query(() => [Problem])
async getProblems(
@Args(
Expand Down
3 changes: 2 additions & 1 deletion apps/backend/apps/admin/src/problem/problem.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
UnprocessableDataException
} from '@libs/exception'
import { PrismaService } from '@libs/prisma'
import { S3Provider } from '@admin/storage/s3.provider'
import { S3MediaProvider, S3Provider } from '@admin/storage/s3.provider'
import { StorageService } from '@admin/storage/storage.service'
import {
exampleContest,
Expand Down Expand Up @@ -96,6 +96,7 @@ describe('ProblemService', () => {
StorageService,
ConfigService,
S3Provider,
S3MediaProvider,
{ provide: CACHE_MANAGER, useValue: { del: () => null } }
]
}).compile()
Expand Down
Loading
Loading