From ce44d49289ad906ff2d87c9beba4d4e4377f8916 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sat, 1 Feb 2025 17:31:24 +0900 Subject: [PATCH 01/67] =?UTF-8?q?Feat:=20=ED=95=99=EB=B6=80=20=EA=B3=B5?= =?UTF-8?q?=EC=A7=80=EC=82=AC=ED=95=AD=20=EB=B0=8F=20=EC=B7=A8=EC=97=85=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20API=20=EA=B0=9C=EB=B0=9C=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C=20Controller,=20Repository,=20Service,=20DTO=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C=20=EC=99=84=EB=A3=8C=20=EB=B0=8F=20FastAPI?= =?UTF-8?q?=20=EC=97=B0=EB=8F=99=20=ED=81=B4=EB=9D=BC=EC=9D=B4=EC=96=B8?= =?UTF-8?q?=ED=8A=B8=20=EA=B0=9C=EB=B0=9C=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hs_err_pid44980.jfr | Bin 212053 -> 0 bytes hs_err_pid44980.log | 1100 ----------------- .../scheduler/EmploymentNoticeScheduler.java | 26 + .../controller/EmploymentController.java | 37 + .../response/EmploymentNoticeResponseDTO.java | 27 + ...astAPIEmploymentNoticeResponseListDTO.java | 12 + .../PageEmploymentNoticeResponseDTO.java | 16 + .../model/entity/EmploymentNotice.java | 51 + .../EmploymentNoticeRepository.java | 10 + .../service/EmploymentNoticeService.java | 101 ++ .../global/infrastructure/FastApiClient.java | 55 + .../controller/MajorEventController.java | 17 +- .../repository/MajorEventRepository.java | 22 +- .../majorEvent/service/MajorEventService.java | 84 +- .../config/scheduler/MajorScheduler.java | 25 + .../controller/MajorNoticeController.java | 35 + .../FastAPIMajorNoticesResponseListDTO.java | 11 + .../dto/response/MajorNoticeResponseDTO.java | 27 + .../response/PageMajorNoticeResponseDTO.java | 16 + .../majorNotice/model/entity/MajorNotice.java | 52 + .../repository/MajorNoticeRepository.java | 10 + .../service/MajorNoticeService.java | 94 ++ .../member/controller/MemberController.java | 9 +- .../member/model/dto/response/MemberDTO.java | 11 - .../MemberInformationResponseDTO.java | 27 + .../domain/member/model/entity/Member.java | 9 +- .../service/CustomOAuthMemberService.java | 2 +- .../domain/member/service/MemberService.java | 10 +- 28 files changed, 713 insertions(+), 1183 deletions(-) delete mode 100644 hs_err_pid44980.jfr delete mode 100644 hs_err_pid44980.log create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/FastAPIEmploymentNoticeResponseListDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/PageEmploymentNoticeResponseDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/config/scheduler/MajorScheduler.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/FastAPIMajorNoticesResponseListDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/PageMajorNoticeResponseDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java diff --git a/hs_err_pid44980.jfr b/hs_err_pid44980.jfr deleted file mode 100644 index 87dc5cfe2cd91dbd757781dbe34fdc5255fb5c5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 212053 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/github/cdimascio/dotenv/internal/DotenvReader;ZZ)V+26 -j io.github.cdimascio.dotenv.DotenvBuilder.load()Lio/github/cdimascio/dotenv/Dotenv;+27 -j io.github.cdimascio.dotenv.Dotenv$Instance.load()Lio/github/cdimascio/dotenv/Dotenv;+7 -j io.github.cdimascio.dotenv.Dotenv.load()Lio/github/cdimascio/dotenv/Dotenv;+3 -j com.ComNCheck.ComNCheck.ComNCheckApplication.main([Ljava/lang/String;)V+0 -v ~StubRoutines::call_stub -V [libjvm.dylib+0x473abc] JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x390 -V [libjvm.dylib+0x4d8ab0] jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, JavaThread*)+0x110 -V [libjvm.dylib+0x4dc0cc] jni_CallStaticVoidMethod+0x130 -C [libjli.dylib+0x77e8] JavaMain+0xa80 -C [libjli.dylib+0x9ab8] ThreadJavaMain+0xc -C [libsystem_pthread.dylib+0x6f94] _pthread_start+0x88 - -Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) -j java.util.zip.Inflater.inflateBytesBytes(J[BII[BII)J+0 java.base@17.0.8.1 -j java.util.zip.Inflater.inflate([BII)I+77 java.base@17.0.8.1 -j java.util.zip.InflaterInputStream.read([BII)I+53 java.base@17.0.8.1 -j jdk.internal.loader.Resource.getBytes()[B+117 java.base@17.0.8.1 -j jdk.internal.loader.URLClassPath$JarLoader$2.getBytes()[B+1 java.base@17.0.8.1 -j jdk.internal.loader.BuiltinClassLoader.defineClass(Ljava/lang/String;Ljdk/internal/loader/Resource;)Ljava/lang/Class;+84 java.base@17.0.8.1 -j jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(Ljava/lang/String;)Ljava/lang/Class;+37 java.base@17.0.8.1 -j jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(Ljava/lang/String;Z)Ljava/lang/Class;+111 java.base@17.0.8.1 -j jdk.internal.loader.BuiltinClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;+3 java.base@17.0.8.1 -j jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;+36 java.base@17.0.8.1 -j java.lang.ClassLoader.loadClass(Ljava/lang/String;)Ljava/lang/Class;+3 java.base@17.0.8.1 -v ~StubRoutines::call_stub -j io.github.cdimascio.dotenv.internal.DotenvParser.(Lio/github/cdimascio/dotenv/internal/DotenvReader;ZZ)V+26 -j io.github.cdimascio.dotenv.DotenvBuilder.load()Lio/github/cdimascio/dotenv/Dotenv;+27 -j io.github.cdimascio.dotenv.Dotenv$Instance.load()Lio/github/cdimascio/dotenv/Dotenv;+7 -j io.github.cdimascio.dotenv.Dotenv.load()Lio/github/cdimascio/dotenv/Dotenv;+3 -j com.ComNCheck.ComNCheck.ComNCheckApplication.main([Ljava/lang/String;)V+0 -v ~StubRoutines::call_stub - -siginfo: si_signo: 10 (SIGBUS), si_code: 1 (BUS_ADRALN), si_addr: 0x00000001248014e4 - -Register to memory mapping: - - x0=0x0000007000259000 is pointing into metadata - x1=0x00000000cafebabe is an unknown value - x2=0x0 is NULL - x3=0x0 is NULL - x4=0x000000016db8d230 is pointing into the stack for thread: 0x000000010e042e00 - x5=0x000000016db8d230 is pointing into the stack for thread: 0x000000010e042e00 - x6=0xffffffffffffff97 is an unknown value - x7=0x000000000000006e is an unknown value - x8=0x00000001248014e0 is at begin+0 in a stub -StubRoutines::SafeFetch32 [0x00000001248014e0, 0x00000001248014ec] (12 bytes) - x9=0x0000000000000450 is an unknown value -x10=0x0000000124805600 is pointing into interpreter code (not bytecode specific) -x11=0x00000000000000ab is an unknown value -x12=0x00000000000000ab is an unknown value -x13=0x0 is NULL -x14=0x0 is NULL -x15=0x0000000787a315c8 is pointing into object: [B -{0x0000000787a31548} - klass: {type array byte} - - length: 1024 -x16=0x000000019d7a9da4: pthread_getspecific+0 in /usr/lib/system/libsystem_pthread.dylib at 0x000000019d7a8000 -x17=0x0000600004ac7870 points into unknown readable memory: 0xfffffffffffffffe | fe ff ff ff ff ff ff ff -x18=0x0 is NULL -x19=0x0000007000259000 is pointing into metadata -x20=0x000000010e042e00 is a thread -x21=0x0000000000000001 is an unknown value -x22={method} {0x0000007000259e10} 'inflateBytesBytes' '(J[BII[BII)J' in 'java/util/zip/Inflater' -x23=0x00000001046a3a40: _ZN12StubRoutines18_safefetch32_entryE+0 in /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/server/libjvm.dylib at 0x0000000103a34000 -x24=0x00000000cafebabe is an unknown value -x25=0x000000010e0430b0 points into unknown readable memory: 0x00000001046669f8 | f8 69 66 04 01 00 00 00 -x26=0x000000016db8cfb0 is pointing into the stack for thread: 0x000000010e042e00 -x27=0x0000000110014390 points into unknown readable memory: 0x000000000000014d | 4d 01 00 00 00 00 00 00 -x28=0x00000001026b0890: inflate_fast+0x33c in /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libzip.dylib at 0x00000001026a4000 - - -Registers: - x0=0x0000007000259000 x1=0x00000000cafebabe x2=0x0000000000000000 x3=0x0000000000000000 - x4=0x000000016db8d230 x5=0x000000016db8d230 x6=0xffffffffffffff97 x7=0x000000000000006e - x8=0x00000001248014e0 x9=0x0000000000000450 x10=0x0000000124805600 x11=0x00000000000000ab -x12=0x00000000000000ab x13=0x0000000000000000 x14=0x0000000000000000 x15=0x0000000787a315c8 -x16=0x000000019d7a9da4 x17=0x0000600004ac7870 x18=0x0000000000000000 x19=0x0000007000259000 -x20=0x000000010e042e00 x21=0x0000000000000001 x22=0x0000007000259e10 x23=0x00000001046a3a40 -x24=0x00000000cafebabe x25=0x000000010e0430b0 x26=0x000000016db8cfb0 x27=0x0000000110014390 -x28=0x00000001026b0890 fp=0x000000016db8c400 lr=0x00000001041fc290 sp=0x000000016db8c3d0 -pc=0x00000001248014e4 cpsr=0x0000000060001000 -Top of Stack: (sp=0x000000016db8c3d0) -0x000000016db8c3d0: 000000010e042e00 00000000000007ff -0x000000016db8c3e0: 0000007000259e10 000000010e042e00 -0x000000016db8c3f0: 0000007000259000 0000007000259e68 -0x000000016db8c400: 000000016db8c420 00000001041fc890 -0x000000016db8c410: 0000000000000800 0000007000259e10 -0x000000016db8c420: 000000016db8c440 00000001041a931c -0x000000016db8c430: 0000000000000800 000000016db8d190 -0x000000016db8c440: 000000016db8d0b0 0000000103d93bb8 -0x000000016db8c450: 0000000000000000 0000000000000000 -0x000000016db8c460: 0000000000000000 0000000000000000 -0x000000016db8c470: 0000000000000000 0000000000000000 -0x000000016db8c480: 0000000000000000 0000000000000000 -0x000000016db8c490: 0000000000000000 0000000000000000 -0x000000016db8c4a0: 0000000000000000 0000000000000000 -0x000000016db8c4b0: 0000000000000000 0000000000000000 -0x000000016db8c4c0: 0000000000000000 0000000000000000 -0x000000016db8c4d0: 0000000000000000 0000000000000000 -0x000000016db8c4e0: 0000000000000000 0000000000000000 -0x000000016db8c4f0: 0000000000000000 0000000000000000 -0x000000016db8c500: 0000000000000000 0000000000000000 -0x000000016db8c510: 0000000000000000 0000000000000000 -0x000000016db8c520: 0000000000000000 0000000000000000 -0x000000016db8c530: 0000000000000000 0000000000000000 -0x000000016db8c540: 0000000000000000 0000000000000000 -0x000000016db8c550: 0000000000000000 0000000000000000 -0x000000016db8c560: 0000000000000000 0000000000000000 -0x000000016db8c570: 0000000000000000 0000000000000000 -0x000000016db8c580: 0000000000000000 0000000000000000 -0x000000016db8c590: 0000000000000000 0000000000000000 -0x000000016db8c5a0: 000000010361d7a0 0000000000000000 -0x000000016db8c5b0: 0000000122a47ab0 0000000000000000 -0x000000016db8c5c0: 0000000000000000 0000000000000000 - -Instructions: (pc=0x00000001248014e4) -0x00000001248013e4: 1e614000 1400003a d2923809 f2a08ce9 -0x00000001248013f4: f2c00029 6d425935 1e640886 0c402d31 -0x0000000124801404: 1e6408c7 1f5654d0 1e6c1017 1f5050d0 -0x0000000124801414: 1f504cd0 1f5048d0 1e650af6 1f50d8f6 -0x0000000124801424: 1f5694d6 1f5158f6 1e762880 36000501 -0x0000000124801434: 1e614000 14000026 2e251ca5 d2924009 -0x0000000124801444: f2a08ce9 f2c00029 6d425d36 1e600806 -0x0000000124801454: 0c402d32 1f5758c7 1e6c101a 1f4754c7 -0x0000000124801464: 1e650805 1f4750c7 d2866668 f2a7fa68 -0x0000000124801474: 1f474cc7 1e6608c0 1f4748c7 1e6e1019 -0x0000000124801484: eb08007f 540000ac 1f479400 1f460340 -0x0000000124801494: 1e603b20 1400000e d2a7fd29 eb09007f -0x00000001248014a4: 540000ac 51480069 d3607d29 9e670121 -0x00000001248014b4: 14000002 1e6a5001 1f679417 1f668742 -0x00000001248014c4: 1e613b23 1e773857 1e773860 a8c17ff3 -0x00000001248014d4: 910003bf a8c17bfd d65f03c0 b9400001 -0x00000001248014e4: aa0103e0 d65f03c0 f9400001 aa0103e0 -0x00000001248014f4: d65f03c0 00000000 00000000 00000000 -0x0000000124801504: 00000000 00000000 00000000 00000000 -0x0000000124801514: 00000000 00000000 00000000 00000000 -0x0000000124801524: 00000000 00000000 00000000 00000000 -0x0000000124801534: 00000000 00000000 00000000 00000000 -0x0000000124801544: 00000000 00000000 00000000 00000000 -0x0000000124801554: 00000000 00000000 00000000 00000000 -0x0000000124801564: 00000000 00000000 00000000 00000000 -0x0000000124801574: 00000000 00000000 00000000 00000000 -0x0000000124801584: 00000000 00000000 00000000 00000000 -0x0000000124801594: 00000000 00000000 00000000 00000000 -0x00000001248015a4: 00000000 00000000 00000000 00000000 -0x00000001248015b4: 00000000 00000000 00000000 00000000 -0x00000001248015c4: 00000000 00000000 00000000 00000000 -0x00000001248015d4: 00000000 00000000 00000000 00000000 - - -Stack slot to memory mapping: -stack at sp + 0 slots: 0x000000010e042e00 is a thread -stack at sp + 1 slots: 0x00000000000007ff is an unknown value -stack at sp + 2 slots: {method} {0x0000007000259e10} 'inflateBytesBytes' '(J[BII[BII)J' in 'java/util/zip/Inflater' -stack at sp + 3 slots: 0x000000010e042e00 is a thread -stack at sp + 4 slots: 0x0000007000259000 is pointing into metadata -stack at sp + 5 slots: 0x0000007000259e68 is pointing into metadata -stack at sp + 6 slots: 0x000000016db8c420 is pointing into the stack for thread: 0x000000010e042e00 -stack at sp + 7 slots: 0x00000001041fc890: _ZN2os17is_readable_rangeEPKvS1_+0x2c in /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/server/libjvm.dylib at 0x0000000103a34000 - -StubRoutines::SafeFetch32 [0x00000001248014e0, 0x00000001248014ec] (12 bytes) -[MachCode] - 0x00000001248014e0: 0100 40b9 | e003 01aa | c003 5fd6 -[/MachCode] - ---------------- P R O C E S S --------------- - -Threads class SMR info: -_java_thread_list=0x000060000299b7a0, length=17, elements={ -0x000000010e042e00, 0x000000010e055600, 0x000000010e057e00, 0x000000010e058400, -0x00000001228fb800, 0x0000000123908600, 0x0000000123908c00, 0x000000010c860e00, -0x000000010e098a00, 0x000000010e099000, 0x0000000122936a00, 0x000000010c848c00, -0x0000000123909800, 0x000000010d097e00, 0x000000010d0ac800, 0x000000012219c400, -0x000000010da13800 -} - -Java Threads: ( => current thread ) -=>0x000000010e042e00 JavaThread "main" [_thread_in_native, id=8707, stack(0x000000016d98c000,0x000000016db8f000)] - 0x000000010e055600 JavaThread "Reference Handler" daemon [_thread_blocked, id=18947, stack(0x000000016e7e0000,0x000000016e9e3000)] - 0x000000010e057e00 JavaThread "Finalizer" daemon [_thread_blocked, id=19715, stack(0x000000016e9ec000,0x000000016ebef000)] - 0x000000010e058400 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=31235, stack(0x000000016ed10000,0x000000016ef13000)] - 0x00000001228fb800 JavaThread "Service Thread" daemon [_thread_blocked, id=23299, stack(0x000000016ef1c000,0x000000016f11f000)] - 0x0000000123908600 JavaThread "Monitor Deflation Thread" daemon [_thread_blocked, id=30723, stack(0x000000016f128000,0x000000016f32b000)] - 0x0000000123908c00 JavaThread "C1 CompilerThread0" daemon [_thread_in_native, id=30467, stack(0x000000016f334000,0x000000016f537000)] - 0x000000010c860e00 JavaThread "Sweeper thread" daemon [_thread_blocked, id=29955, stack(0x000000016f540000,0x000000016f743000)] - 0x000000010e098a00 JavaThread "Common-Cleaner" daemon [_thread_blocked, id=24323, stack(0x000000016f74c000,0x000000016f94f000)] - 0x000000010e099000 JavaThread "Attach Listener" daemon [_thread_blocked, id=29443, stack(0x000000016f958000,0x000000016fb5b000)] - 0x0000000122936a00 JavaThread "Monitor Ctrl-Break" daemon [_thread_in_native, id=24835, stack(0x000000016fb64000,0x000000016fd67000)] - 0x000000010c848c00 JavaThread "JFR Recorder Thread" daemon [_thread_blocked, id=28931, stack(0x000000016fd70000,0x000000016ff73000)] - 0x0000000123909800 JavaThread "JFR Periodic Tasks" daemon [_thread_blocked, id=28675, stack(0x000000016ff7c000,0x000000017017f000)] - 0x000000010d097e00 JavaThread "RMI TCP Accept-0" daemon [_thread_in_native, id=27907, stack(0x00000001707ac000,0x00000001709af000)] - 0x000000010d0ac800 JavaThread "Async-profiler Timer" daemon [_thread_in_native, id=27139, stack(0x0000000170a44000,0x0000000170c47000)] - 0x000000012219c400 JavaThread "Notification Thread" daemon [_thread_blocked, id=43267, stack(0x0000000170c50000,0x0000000170e53000)] - 0x000000010da13800 JavaThread "RMI TCP Connection(1)-127.0.0.1" daemon [_thread_in_vm, id=33027, stack(0x0000000171068000,0x000000017126b000)] - -Other Threads: - 0x0000000121f6b3b0 VMThread "VM Thread" [stack: 0x000000016e5d4000,0x000000016e7d7000] [id=20227] - 0x0000000102837da0 WatcherThread [stack: 0x0000000170e5c000,0x000000017105f000] [id=42755] - 0x000000010282ba30 GCTaskThread "GC Thread#0" [stack: 0x000000016db98000,0x000000016dd9b000] [id=14339] - 0x0000000103735f40 GCTaskThread "GC Thread#1" [stack: 0x0000000170188000,0x000000017038b000] [id=25603] - 0x00000001037367b0 GCTaskThread "GC Thread#2" [stack: 0x0000000170394000,0x0000000170597000] [id=28163] - 0x0000000121f73800 GCTaskThread "GC Thread#3" [stack: 0x00000001705a0000,0x00000001707a3000] [id=26371] - 0x000000010282c0e0 ConcurrentGCThread "G1 Main Marker" [stack: 0x000000016dda4000,0x000000016dfa7000] [id=13059] - 0x000000010361dfb0 ConcurrentGCThread "G1 Conc#0" [stack: 0x000000016dfb0000,0x000000016e1b3000] [id=13827] - 0x000000010361e820 ConcurrentGCThread "G1 Refine#0" [stack: 0x000000016e1bc000,0x000000016e3bf000] [id=16643] - 0x0000000121e7c260 ConcurrentGCThread "G1 Service" [stack: 0x000000016e3c8000,0x000000016e5cb000] [id=21251] - -Threads with active compile tasks: -C1 CompilerThread0 4268 1269 1 java.lang.reflect.AccessibleObject::checkCanSetAccessible (368 bytes) - -VM state: not at safepoint (normal execution) - -VM Mutex/Monitor currently owned by a thread: None - -Heap address: 0x0000000780000000, size: 2048 MB, Compressed Oops mode: Zero based, Oop shift amount: 3 - -CDS archive(s) mapped at: [0x0000007000000000-0x0000007000be0000-0x0000007000be0000), size 12451840, SharedBaseAddress: 0x0000007000000000, ArchiveRelocationMode: 1. -Compressed class space mapped at: 0x0000007001000000-0x0000007041000000, reserved size: 1073741824 -Narrow klass base: 0x0000007000000000, Narrow klass shift: 0, Narrow klass range: 0x100000000 - -GC Precious Log: - CPUs: 8 total, 8 available - Memory: 8192M - Large Page Support: Disabled - NUMA Support: Disabled - Compressed Oops: Enabled (Zero based) - Heap Region Size: 1M - Heap Min Capacity: 8M - Heap Initial Capacity: 128M - Heap Max Capacity: 2G - Pre-touch: Disabled - Parallel Workers: 8 - Concurrent Workers: 2 - Concurrent Refinement Workers: 8 - Periodic GC: Disabled - -Heap: - garbage-first heap total 133120K, used 14944K [0x0000000780000000, 0x0000000800000000) - region size 1024K, 9 young (9216K), 3 survivors (3072K) - Metaspace used 6500K, committed 6720K, reserved 1114112K - class space used 807K, committed 896K, reserved 1048576K - -Heap Regions: E=young(eden), S=young(survivor), O=old, HS=humongous(starts), HC=humongous(continues), CS=collection set, F=free, OA=open archive, CA=closed archive, TAMS=top-at-mark-start (previous, next) -| 0|0x0000000780000000, 0x0000000780100000, 0x0000000780100000|100%|HS| |TAMS 0x0000000780000000, 0x0000000780000000| Complete -| 1|0x0000000780100000, 0x0000000780200000, 0x0000000780200000|100%|HS| |TAMS 0x0000000780100000, 0x0000000780100000| Complete -| 2|0x0000000780200000, 0x0000000780300000, 0x0000000780300000|100%| O| |TAMS 0x0000000780200000, 0x0000000780200000| Untracked -| 3|0x0000000780300000, 0x0000000780400000, 0x0000000780400000|100%| O| |TAMS 0x0000000780300000, 0x0000000780300000| Untracked -| 4|0x0000000780400000, 0x0000000780500000, 0x0000000780500000|100%| O| |TAMS 0x0000000780400000, 0x0000000780400000| Untracked -| 5|0x0000000780500000, 0x00000007805a0000, 0x0000000780600000| 62%| O| |TAMS 0x0000000780500000, 0x0000000780500000| Untracked -| 6|0x0000000780600000, 0x0000000780600000, 0x0000000780700000| 0%| F| |TAMS 0x0000000780600000, 0x0000000780600000| Untracked -| 7|0x0000000780700000, 0x0000000780700000, 0x0000000780800000| 0%| F| |TAMS 0x0000000780700000, 0x0000000780700000| Untracked -| 8|0x0000000780800000, 0x0000000780800000, 0x0000000780900000| 0%| F| |TAMS 0x0000000780800000, 0x0000000780800000| Untracked -| 9|0x0000000780900000, 0x0000000780900000, 0x0000000780a00000| 0%| F| |TAMS 0x0000000780900000, 0x0000000780900000| Untracked -| 10|0x0000000780a00000, 0x0000000780a00000, 0x0000000780b00000| 0%| F| |TAMS 0x0000000780a00000, 0x0000000780a00000| Untracked -| 11|0x0000000780b00000, 0x0000000780b00000, 0x0000000780c00000| 0%| F| |TAMS 0x0000000780b00000, 0x0000000780b00000| Untracked -| 12|0x0000000780c00000, 0x0000000780c00000, 0x0000000780d00000| 0%| F| |TAMS 0x0000000780c00000, 0x0000000780c00000| Untracked -| 13|0x0000000780d00000, 0x0000000780d00000, 0x0000000780e00000| 0%| F| |TAMS 0x0000000780d00000, 0x0000000780d00000| Untracked -| 14|0x0000000780e00000, 0x0000000780e00000, 0x0000000780f00000| 0%| F| |TAMS 0x0000000780e00000, 0x0000000780e00000| Untracked -| 15|0x0000000780f00000, 0x0000000780f00000, 0x0000000781000000| 0%| F| |TAMS 0x0000000780f00000, 0x0000000780f00000| Untracked -| 16|0x0000000781000000, 0x0000000781000000, 0x0000000781100000| 0%| F| |TAMS 0x0000000781000000, 0x0000000781000000| Untracked -| 17|0x0000000781100000, 0x0000000781100000, 0x0000000781200000| 0%| F| |TAMS 0x0000000781100000, 0x0000000781100000| Untracked -| 18|0x0000000781200000, 0x0000000781200000, 0x0000000781300000| 0%| F| |TAMS 0x0000000781200000, 0x0000000781200000| Untracked -| 19|0x0000000781300000, 0x0000000781300000, 0x0000000781400000| 0%| F| |TAMS 0x0000000781300000, 0x0000000781300000| Untracked -| 20|0x0000000781400000, 0x0000000781400000, 0x0000000781500000| 0%| F| |TAMS 0x0000000781400000, 0x0000000781400000| Untracked -| 21|0x0000000781500000, 0x0000000781500000, 0x0000000781600000| 0%| F| |TAMS 0x0000000781500000, 0x0000000781500000| Untracked -| 22|0x0000000781600000, 0x0000000781600000, 0x0000000781700000| 0%| F| |TAMS 0x0000000781600000, 0x0000000781600000| Untracked -| 23|0x0000000781700000, 0x0000000781700000, 0x0000000781800000| 0%| F| |TAMS 0x0000000781700000, 0x0000000781700000| Untracked -| 24|0x0000000781800000, 0x0000000781800000, 0x0000000781900000| 0%| F| |TAMS 0x0000000781800000, 0x0000000781800000| Untracked -| 25|0x0000000781900000, 0x0000000781900000, 0x0000000781a00000| 0%| F| |TAMS 0x0000000781900000, 0x0000000781900000| Untracked -| 26|0x0000000781a00000, 0x0000000781a00000, 0x0000000781b00000| 0%| F| |TAMS 0x0000000781a00000, 0x0000000781a00000| Untracked -| 27|0x0000000781b00000, 0x0000000781b00000, 0x0000000781c00000| 0%| F| |TAMS 0x0000000781b00000, 0x0000000781b00000| Untracked -| 28|0x0000000781c00000, 0x0000000781c00000, 0x0000000781d00000| 0%| F| |TAMS 0x0000000781c00000, 0x0000000781c00000| Untracked -| 29|0x0000000781d00000, 0x0000000781d00000, 0x0000000781e00000| 0%| F| |TAMS 0x0000000781d00000, 0x0000000781d00000| Untracked -| 30|0x0000000781e00000, 0x0000000781e00000, 0x0000000781f00000| 0%| F| |TAMS 0x0000000781e00000, 0x0000000781e00000| Untracked -| 31|0x0000000781f00000, 0x0000000781f00000, 0x0000000782000000| 0%| F| |TAMS 0x0000000781f00000, 0x0000000781f00000| Untracked -| 32|0x0000000782000000, 0x0000000782000000, 0x0000000782100000| 0%| F| |TAMS 0x0000000782000000, 0x0000000782000000| Untracked -| 33|0x0000000782100000, 0x0000000782100000, 0x0000000782200000| 0%| F| |TAMS 0x0000000782100000, 0x0000000782100000| Untracked -| 34|0x0000000782200000, 0x0000000782200000, 0x0000000782300000| 0%| F| |TAMS 0x0000000782200000, 0x0000000782200000| Untracked -| 35|0x0000000782300000, 0x0000000782300000, 0x0000000782400000| 0%| F| |TAMS 0x0000000782300000, 0x0000000782300000| Untracked -| 36|0x0000000782400000, 0x0000000782400000, 0x0000000782500000| 0%| F| |TAMS 0x0000000782400000, 0x0000000782400000| Untracked -| 37|0x0000000782500000, 0x0000000782500000, 0x0000000782600000| 0%| F| |TAMS 0x0000000782500000, 0x0000000782500000| Untracked -| 38|0x0000000782600000, 0x0000000782600000, 0x0000000782700000| 0%| F| |TAMS 0x0000000782600000, 0x0000000782600000| Untracked -| 39|0x0000000782700000, 0x0000000782700000, 0x0000000782800000| 0%| F| |TAMS 0x0000000782700000, 0x0000000782700000| Untracked -| 40|0x0000000782800000, 0x0000000782800000, 0x0000000782900000| 0%| F| |TAMS 0x0000000782800000, 0x0000000782800000| Untracked -| 41|0x0000000782900000, 0x0000000782900000, 0x0000000782a00000| 0%| F| |TAMS 0x0000000782900000, 0x0000000782900000| Untracked -| 42|0x0000000782a00000, 0x0000000782a00000, 0x0000000782b00000| 0%| F| |TAMS 0x0000000782a00000, 0x0000000782a00000| Untracked -| 43|0x0000000782b00000, 0x0000000782b00000, 0x0000000782c00000| 0%| F| |TAMS 0x0000000782b00000, 0x0000000782b00000| Untracked -| 44|0x0000000782c00000, 0x0000000782c00000, 0x0000000782d00000| 0%| F| |TAMS 0x0000000782c00000, 0x0000000782c00000| Untracked -| 45|0x0000000782d00000, 0x0000000782d00000, 0x0000000782e00000| 0%| F| |TAMS 0x0000000782d00000, 0x0000000782d00000| Untracked -| 46|0x0000000782e00000, 0x0000000782e00000, 0x0000000782f00000| 0%| F| |TAMS 0x0000000782e00000, 0x0000000782e00000| Untracked -| 47|0x0000000782f00000, 0x0000000782f00000, 0x0000000783000000| 0%| F| |TAMS 0x0000000782f00000, 0x0000000782f00000| Untracked -| 48|0x0000000783000000, 0x0000000783000000, 0x0000000783100000| 0%| F| |TAMS 0x0000000783000000, 0x0000000783000000| Untracked -| 49|0x0000000783100000, 0x0000000783100000, 0x0000000783200000| 0%| F| |TAMS 0x0000000783100000, 0x0000000783100000| Untracked -| 50|0x0000000783200000, 0x0000000783200000, 0x0000000783300000| 0%| F| |TAMS 0x0000000783200000, 0x0000000783200000| Untracked -| 51|0x0000000783300000, 0x0000000783300000, 0x0000000783400000| 0%| F| |TAMS 0x0000000783300000, 0x0000000783300000| Untracked -| 52|0x0000000783400000, 0x0000000783400000, 0x0000000783500000| 0%| F| |TAMS 0x0000000783400000, 0x0000000783400000| Untracked -| 53|0x0000000783500000, 0x0000000783500000, 0x0000000783600000| 0%| F| |TAMS 0x0000000783500000, 0x0000000783500000| Untracked -| 54|0x0000000783600000, 0x0000000783600000, 0x0000000783700000| 0%| F| |TAMS 0x0000000783600000, 0x0000000783600000| Untracked -| 55|0x0000000783700000, 0x0000000783700000, 0x0000000783800000| 0%| F| |TAMS 0x0000000783700000, 0x0000000783700000| Untracked -| 56|0x0000000783800000, 0x0000000783800000, 0x0000000783900000| 0%| F| |TAMS 0x0000000783800000, 0x0000000783800000| Untracked -| 57|0x0000000783900000, 0x0000000783900000, 0x0000000783a00000| 0%| F| |TAMS 0x0000000783900000, 0x0000000783900000| Untracked -| 58|0x0000000783a00000, 0x0000000783a00000, 0x0000000783b00000| 0%| F| |TAMS 0x0000000783a00000, 0x0000000783a00000| Untracked -| 59|0x0000000783b00000, 0x0000000783b00000, 0x0000000783c00000| 0%| F| |TAMS 0x0000000783b00000, 0x0000000783b00000| Untracked -| 60|0x0000000783c00000, 0x0000000783c00000, 0x0000000783d00000| 0%| F| |TAMS 0x0000000783c00000, 0x0000000783c00000| Untracked -| 61|0x0000000783d00000, 0x0000000783d00000, 0x0000000783e00000| 0%| F| |TAMS 0x0000000783d00000, 0x0000000783d00000| Untracked -| 62|0x0000000783e00000, 0x0000000783e00000, 0x0000000783f00000| 0%| F| |TAMS 0x0000000783e00000, 0x0000000783e00000| Untracked -| 63|0x0000000783f00000, 0x0000000783f00000, 0x0000000784000000| 0%| F| |TAMS 0x0000000783f00000, 0x0000000783f00000| Untracked -| 64|0x0000000784000000, 0x0000000784000000, 0x0000000784100000| 0%| F| |TAMS 0x0000000784000000, 0x0000000784000000| Untracked -| 65|0x0000000784100000, 0x0000000784100000, 0x0000000784200000| 0%| F| |TAMS 0x0000000784100000, 0x0000000784100000| Untracked -| 66|0x0000000784200000, 0x0000000784200000, 0x0000000784300000| 0%| F| |TAMS 0x0000000784200000, 0x0000000784200000| Untracked -| 67|0x0000000784300000, 0x0000000784300000, 0x0000000784400000| 0%| F| |TAMS 0x0000000784300000, 0x0000000784300000| Untracked -| 68|0x0000000784400000, 0x0000000784400000, 0x0000000784500000| 0%| F| |TAMS 0x0000000784400000, 0x0000000784400000| Untracked -| 69|0x0000000784500000, 0x0000000784500000, 0x0000000784600000| 0%| F| |TAMS 0x0000000784500000, 0x0000000784500000| Untracked -| 70|0x0000000784600000, 0x0000000784600000, 0x0000000784700000| 0%| F| |TAMS 0x0000000784600000, 0x0000000784600000| Untracked -| 71|0x0000000784700000, 0x0000000784700000, 0x0000000784800000| 0%| F| |TAMS 0x0000000784700000, 0x0000000784700000| Untracked -| 72|0x0000000784800000, 0x0000000784800000, 0x0000000784900000| 0%| F| |TAMS 0x0000000784800000, 0x0000000784800000| Untracked -| 73|0x0000000784900000, 0x0000000784900000, 0x0000000784a00000| 0%| F| |TAMS 0x0000000784900000, 0x0000000784900000| Untracked -| 74|0x0000000784a00000, 0x0000000784a00000, 0x0000000784b00000| 0%| F| |TAMS 0x0000000784a00000, 0x0000000784a00000| Untracked -| 75|0x0000000784b00000, 0x0000000784b00000, 0x0000000784c00000| 0%| F| |TAMS 0x0000000784b00000, 0x0000000784b00000| Untracked -| 76|0x0000000784c00000, 0x0000000784c00000, 0x0000000784d00000| 0%| F| |TAMS 0x0000000784c00000, 0x0000000784c00000| Untracked -| 77|0x0000000784d00000, 0x0000000784d00000, 0x0000000784e00000| 0%| F| |TAMS 0x0000000784d00000, 0x0000000784d00000| Untracked -| 78|0x0000000784e00000, 0x0000000784e00000, 0x0000000784f00000| 0%| F| |TAMS 0x0000000784e00000, 0x0000000784e00000| Untracked -| 79|0x0000000784f00000, 0x0000000784f00000, 0x0000000785000000| 0%| F| |TAMS 0x0000000784f00000, 0x0000000784f00000| Untracked -| 80|0x0000000785000000, 0x0000000785000000, 0x0000000785100000| 0%| F| |TAMS 0x0000000785000000, 0x0000000785000000| Untracked -| 81|0x0000000785100000, 0x0000000785100000, 0x0000000785200000| 0%| F| |TAMS 0x0000000785100000, 0x0000000785100000| Untracked -| 82|0x0000000785200000, 0x0000000785200000, 0x0000000785300000| 0%| F| |TAMS 0x0000000785200000, 0x0000000785200000| Untracked -| 83|0x0000000785300000, 0x0000000785300000, 0x0000000785400000| 0%| F| |TAMS 0x0000000785300000, 0x0000000785300000| Untracked -| 84|0x0000000785400000, 0x0000000785400000, 0x0000000785500000| 0%| F| |TAMS 0x0000000785400000, 0x0000000785400000| Untracked -| 85|0x0000000785500000, 0x0000000785500000, 0x0000000785600000| 0%| F| |TAMS 0x0000000785500000, 0x0000000785500000| Untracked -| 86|0x0000000785600000, 0x0000000785600000, 0x0000000785700000| 0%| F| |TAMS 0x0000000785600000, 0x0000000785600000| Untracked -| 87|0x0000000785700000, 0x0000000785700000, 0x0000000785800000| 0%| F| |TAMS 0x0000000785700000, 0x0000000785700000| Untracked -| 88|0x0000000785800000, 0x0000000785800000, 0x0000000785900000| 0%| F| |TAMS 0x0000000785800000, 0x0000000785800000| Untracked -| 89|0x0000000785900000, 0x0000000785900000, 0x0000000785a00000| 0%| F| |TAMS 0x0000000785900000, 0x0000000785900000| Untracked -| 90|0x0000000785a00000, 0x0000000785a00000, 0x0000000785b00000| 0%| F| |TAMS 0x0000000785a00000, 0x0000000785a00000| Untracked -| 91|0x0000000785b00000, 0x0000000785b00000, 0x0000000785c00000| 0%| F| |TAMS 0x0000000785b00000, 0x0000000785b00000| Untracked -| 92|0x0000000785c00000, 0x0000000785c00000, 0x0000000785d00000| 0%| F| |TAMS 0x0000000785c00000, 0x0000000785c00000| Untracked -| 93|0x0000000785d00000, 0x0000000785d00000, 0x0000000785e00000| 0%| F| |TAMS 0x0000000785d00000, 0x0000000785d00000| Untracked -| 94|0x0000000785e00000, 0x0000000785e00000, 0x0000000785f00000| 0%| F| |TAMS 0x0000000785e00000, 0x0000000785e00000| Untracked -| 95|0x0000000785f00000, 0x0000000785f00000, 0x0000000786000000| 0%| F| |TAMS 0x0000000785f00000, 0x0000000785f00000| Untracked -| 96|0x0000000786000000, 0x0000000786000000, 0x0000000786100000| 0%| F| |TAMS 0x0000000786000000, 0x0000000786000000| Untracked -| 97|0x0000000786100000, 0x0000000786100000, 0x0000000786200000| 0%| F| |TAMS 0x0000000786100000, 0x0000000786100000| Untracked -| 98|0x0000000786200000, 0x0000000786200000, 0x0000000786300000| 0%| F| |TAMS 0x0000000786200000, 0x0000000786200000| Untracked -| 99|0x0000000786300000, 0x0000000786300000, 0x0000000786400000| 0%| F| |TAMS 0x0000000786300000, 0x0000000786300000| Untracked -| 100|0x0000000786400000, 0x0000000786400000, 0x0000000786500000| 0%| F| |TAMS 0x0000000786400000, 0x0000000786400000| Untracked -| 101|0x0000000786500000, 0x0000000786500000, 0x0000000786600000| 0%| F| |TAMS 0x0000000786500000, 0x0000000786500000| Untracked -| 102|0x0000000786600000, 0x0000000786700000, 0x0000000786700000|100%| S|CS|TAMS 0x0000000786600000, 0x0000000786600000| Complete -| 103|0x0000000786700000, 0x0000000786800000, 0x0000000786800000|100%| S|CS|TAMS 0x0000000786700000, 0x0000000786700000| Complete -| 104|0x0000000786800000, 0x0000000786900000, 0x0000000786900000|100%| S|CS|TAMS 0x0000000786800000, 0x0000000786800000| Complete -| 105|0x0000000786900000, 0x0000000786900000, 0x0000000786a00000| 0%| F| |TAMS 0x0000000786900000, 0x0000000786900000| Untracked -| 106|0x0000000786a00000, 0x0000000786a00000, 0x0000000786b00000| 0%| F| |TAMS 0x0000000786a00000, 0x0000000786a00000| Untracked -| 107|0x0000000786b00000, 0x0000000786b00000, 0x0000000786c00000| 0%| F| |TAMS 0x0000000786b00000, 0x0000000786b00000| Untracked -| 108|0x0000000786c00000, 0x0000000786c00000, 0x0000000786d00000| 0%| F| |TAMS 0x0000000786c00000, 0x0000000786c00000| Untracked -| 109|0x0000000786d00000, 0x0000000786d00000, 0x0000000786e00000| 0%| F| |TAMS 0x0000000786d00000, 0x0000000786d00000| Untracked -| 110|0x0000000786e00000, 0x0000000786e00000, 0x0000000786f00000| 0%| F| |TAMS 0x0000000786e00000, 0x0000000786e00000| Untracked -| 111|0x0000000786f00000, 0x0000000786f00000, 0x0000000787000000| 0%| F| |TAMS 0x0000000786f00000, 0x0000000786f00000| Untracked -| 112|0x0000000787000000, 0x0000000787000000, 0x0000000787100000| 0%| F| |TAMS 0x0000000787000000, 0x0000000787000000| Untracked -| 113|0x0000000787100000, 0x0000000787100000, 0x0000000787200000| 0%| F| |TAMS 0x0000000787100000, 0x0000000787100000| Untracked -| 114|0x0000000787200000, 0x0000000787200000, 0x0000000787300000| 0%| F| |TAMS 0x0000000787200000, 0x0000000787200000| Untracked -| 115|0x0000000787300000, 0x0000000787300000, 0x0000000787400000| 0%| F| |TAMS 0x0000000787300000, 0x0000000787300000| Untracked -| 116|0x0000000787400000, 0x0000000787400000, 0x0000000787500000| 0%| F| |TAMS 0x0000000787400000, 0x0000000787400000| Untracked -| 117|0x0000000787500000, 0x0000000787500000, 0x0000000787600000| 0%| F| |TAMS 0x0000000787500000, 0x0000000787500000| Untracked -| 118|0x0000000787600000, 0x0000000787600000, 0x0000000787700000| 0%| F| |TAMS 0x0000000787600000, 0x0000000787600000| Untracked -| 119|0x0000000787700000, 0x0000000787700000, 0x0000000787800000| 0%| F| |TAMS 0x0000000787700000, 0x0000000787700000| Untracked -| 120|0x0000000787800000, 0x0000000787800000, 0x0000000787900000| 0%| F| |TAMS 0x0000000787800000, 0x0000000787800000| Untracked -| 121|0x0000000787900000, 0x0000000787900000, 0x0000000787a00000| 0%| F| |TAMS 0x0000000787900000, 0x0000000787900000| Untracked -| 122|0x0000000787a00000, 0x0000000787ac8340, 0x0000000787b00000| 78%| E| |TAMS 0x0000000787a00000, 0x0000000787a00000| Complete -| 123|0x0000000787b00000, 0x0000000787c00000, 0x0000000787c00000|100%| E|CS|TAMS 0x0000000787b00000, 0x0000000787b00000| Complete -| 124|0x0000000787c00000, 0x0000000787d00000, 0x0000000787d00000|100%| E|CS|TAMS 0x0000000787c00000, 0x0000000787c00000| Complete -| 125|0x0000000787d00000, 0x0000000787e00000, 0x0000000787e00000|100%| E|CS|TAMS 0x0000000787d00000, 0x0000000787d00000| Complete -| 126|0x0000000787e00000, 0x0000000787f00000, 0x0000000787f00000|100%| E|CS|TAMS 0x0000000787e00000, 0x0000000787e00000| Complete -| 127|0x0000000787f00000, 0x0000000788000000, 0x0000000788000000|100%| E|CS|TAMS 0x0000000787f00000, 0x0000000787f00000| Complete -|2046|0x00000007ffe00000, 0x00000007ffe78000, 0x00000007fff00000| 46%|OA| |TAMS 0x00000007ffe00000, 0x00000007ffe00000| Untracked -|2047|0x00000007fff00000, 0x00000007fff80000, 0x0000000800000000| 50%|CA| |TAMS 0x00000007fff00000, 0x00000007fff00000| Untracked - -Card table byte_map: [0x000000010ec00000,0x000000010f000000] _byte_map_base: 0x000000010b000000 - -Marking Bits (Prev, Next): (CMBitMap*) 0x000000010d032210, (CMBitMap*) 0x000000010d032250 - Prev Bits: [0x0000000158000000, 0x000000015a000000) - Next Bits: [0x000000015a000000, 0x000000015c000000) - -Polling page: 0x0000000102514000 - -Metaspace: - -Usage: - Non-class: 5.57 MB used. - Class: 809.43 KB used. - Both: 6.36 MB used. - -Virtual space: - Non-class space: 64.00 MB reserved, 5.69 MB ( 9%) committed, 1 nodes. - Class space: 1.00 GB reserved, 896.00 KB ( <1%) committed, 1 nodes. - Both: 1.06 GB reserved, 6.56 MB ( <1%) committed. - -Chunk freelists: - Non-Class: 10.30 MB - Class: 15.10 MB - Both: 25.39 MB - -MaxMetaspaceSize: unlimited -CompressedClassSpaceSize: 1.00 GB -Initial GC threshold: 21.00 MB -Current GC threshold: 21.00 MB -CDS: on -MetaspaceReclaimPolicy: balanced - - commit_granule_bytes: 65536. - - commit_granule_words: 8192. - - virtual_space_node_default_size: 8388608. - - enlarge_chunks_in_place: 1. - - new_chunks_are_fully_committed: 0. - - uncommit_free_chunks: 1. - - use_allocation_guard: 0. - - handle_deallocations: 1. - - -Internal statistics: - -num_allocs_failed_limit: 0. -num_arena_births: 136. -num_arena_deaths: 0. -num_vsnodes_births: 2. -num_vsnodes_deaths: 0. -num_space_committed: 105. -num_space_uncommitted: 0. -num_chunks_returned_to_freelist: 0. -num_chunks_taken_from_freelist: 195. -num_chunk_merges: 0. -num_chunk_splits: 103. -num_chunks_enlarged: 26. -num_inconsistent_stats: 0. - -CodeCache: size=49152Kb used=3474Kb max_used=3474Kb free=45677Kb - bounds [0x0000000124800000, 0x0000000124b70000, 0x0000000127800000] - total_blobs=1771 nmethods=1313 adapters=389 - compilation: enabled - stopped_count=0, restarted_count=0 - full_count=0 - -Compilation events (20 events): -Event: 4.211 Thread 0x0000000123908c00 nmethod 1305 0x0000000124b58710 code [0x0000000124b58880, 0x0000000124b58918] -Event: 4.211 Thread 0x0000000123908c00 1272 1 java.lang.invoke.MemberName::isCallerSensitive (8 bytes) -Event: 4.211 Thread 0x0000000123908c00 nmethod 1272 0x0000000124b58a10 code [0x0000000124b58b80, 0x0000000124b58c58] -Event: 4.211 Thread 0x0000000123908c00 1291 1 java.lang.invoke.MethodType::basicType (8 bytes) -Event: 4.211 Thread 0x0000000123908c00 nmethod 1291 0x0000000124b58d10 code [0x0000000124b58e80, 0x0000000124b58f58] -Event: 4.211 Thread 0x0000000123908c00 1303 1 jdk.jfr.internal.PlatformEventType::isLargeSize (5 bytes) -Event: 4.212 Thread 0x0000000123908c00 nmethod 1303 0x0000000124b59090 code [0x0000000124b59200, 0x0000000124b59298] -Event: 4.212 Thread 0x0000000123908c00 1304 1 jdk.jfr.internal.PlatformEventType::getStackTraceEnabled (5 bytes) -Event: 4.212 Thread 0x0000000123908c00 nmethod 1304 0x0000000124b59390 code [0x0000000124b59500, 0x0000000124b59598] -Event: 4.212 Thread 0x0000000123908c00 1273 1 java.lang.reflect.Modifier::isAbstract (14 bytes) -Event: 4.212 Thread 0x0000000123908c00 nmethod 1273 0x0000000124b59690 code [0x0000000124b59800, 0x0000000124b59898] -Event: 4.212 Thread 0x0000000123908c00 1275 1 jdk.internal.org.objectweb.asm.ClassWriter::visitField (53 bytes) -Event: 4.212 Thread 0x0000000123908c00 nmethod 1275 0x0000000124b59990 code [0x0000000124b59b40, 0x0000000124b59df8] -Event: 4.212 Thread 0x0000000123908c00 1276 1 jdk.internal.org.objectweb.asm.FieldWriter:: (69 bytes) -Event: 4.213 Thread 0x0000000123908c00 nmethod 1276 0x0000000124b5a010 code [0x0000000124b5a1c0, 0x0000000124b5a438] -Event: 4.213 Thread 0x0000000123908c00 1313 1 java.util.WeakHashMap::matchesKey (33 bytes) -Event: 4.214 Thread 0x0000000123908c00 nmethod 1313 0x0000000124b5a710 code [0x0000000124b5a8c0, 0x0000000124b5aa98] -Event: 4.214 Thread 0x0000000123908c00 1314 ! 1 jdk.internal.loader.URLClassPath$JarLoader::ensureOpen (36 bytes) -Event: 4.216 Thread 0x0000000123908c00 nmethod 1314 0x0000000124b5ac90 code [0x0000000124b5ae80, 0x0000000124b5b378] -Event: 4.216 Thread 0x0000000123908c00 1315 s! 1 jdk.internal.loader.URLClassPath::getLoader (194 bytes) - -GC Heap History (2 events): -Event: 4.100 GC heap before -{Heap before GC invocations=0 (full 0): - garbage-first heap total 133120K, used 25568K [0x0000000780000000, 0x0000000800000000) - region size 1024K, 23 young (23552K), 0 survivors (0K) - Metaspace used 5388K, committed 5632K, reserved 1114112K - class space used 667K, committed 768K, reserved 1048576K -} -Event: 4.113 GC heap after -{Heap after GC invocations=1 (full 0): - garbage-first heap total 133120K, used 9824K [0x0000000780000000, 0x0000000800000000) - region size 1024K, 3 young (3072K), 3 survivors (3072K) - Metaspace used 5388K, committed 5632K, reserved 1114112K - class space used 667K, committed 768K, reserved 1048576K -} - -Dll operation events (10 events): -Event: 2.839 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjava.dylib -Event: 3.356 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libzip.dylib -Event: 3.389 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libinstrument.dylib -Event: 3.412 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libnio.dylib -Event: 3.427 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libzip.dylib -Event: 3.543 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjimage.dylib -Event: 3.609 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libnet.dylib -Event: 3.631 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libextnet.dylib -Event: 3.803 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libmanagement.dylib -Event: 3.837 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libmanagement_ext.dylib - -Deoptimization events (6 events): -Event: 3.883 Thread 0x000000010e042e00 DEOPT PACKING pc=0x0000000124a52598 sp=0x000000016db8c970 -Event: 3.883 Thread 0x000000010e042e00 DEOPT UNPACKING pc=0x000000012484777c sp=0x000000016db8c660 mode 3 -Event: 3.906 Thread 0x000000010e042e00 DEOPT PACKING pc=0x0000000124a0cf0c sp=0x000000016db8da10 -Event: 3.906 Thread 0x000000010e042e00 DEOPT UNPACKING pc=0x000000012484777c sp=0x000000016db8d780 mode 3 -Event: 4.036 Thread 0x000000010e042e00 DEOPT PACKING pc=0x0000000124ae9d74 sp=0x000000016db8c3b0 -Event: 4.036 Thread 0x000000010e042e00 DEOPT UNPACKING pc=0x000000012484777c sp=0x000000016db8c070 mode 3 - -Classes unloaded (0 events): -No events - -Classes redefined (20 events): -Event: 4.092 Thread 0x0000000121f6b3b0 redefined class name=sun.nio.ch.SocketChannelImpl, count=1 -Event: 4.092 Thread 0x0000000121f6b3b0 redefined class name=java.lang.Throwable, count=1 -Event: 4.092 Thread 0x0000000121f6b3b0 redefined class name=java.lang.Error, count=2 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.internal.event.ProcessStartEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerIOUsageEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerMemoryUsageEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerCPUThrottlingEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerCPUUsageEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerConfigurationEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.InitialSecurityPropertyEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.DirectBufferStatisticsEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ActiveRecordingEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ActiveSettingEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ErrorThrownEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ExceptionStatisticsEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.SocketWriteEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.SocketReadEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.FileWriteEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.FileReadEvent, count=1 -Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.FileForceEvent, count=1 - -Internal exceptions (20 events): -Event: 3.902 Thread 0x000000010e042e00 Exception (0x0000000787181a78) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.905 Thread 0x000000010e042e00 Exception (0x0000000787193f50) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.908 Thread 0x000000010e042e00 Exception (0x00000007871a3f48) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.909 Thread 0x000000010e042e00 Exception (0x00000007871b0e68) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.912 Thread 0x000000010e042e00 Exception (0x00000007871be7a8) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.917 Thread 0x000000010e099000 Exception (0x00000007871431f0) -thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 759] -Event: 3.918 Thread 0x000000010e042e00 Exception (0x00000007871e63f8) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.921 Thread 0x000000010e042e00 Exception (0x0000000787001198) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.925 Thread 0x000000010e042e00 Exception (0x0000000787013318) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.930 Thread 0x000000010e042e00 Exception (0x0000000787023520) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.932 Thread 0x000000010e042e00 Exception (0x000000078702ee80) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.937 Thread 0x000000010e042e00 Exception (0x0000000787045768) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.940 Thread 0x000000010e042e00 Exception (0x0000000787055278) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.942 Thread 0x000000010e042e00 Exception (0x0000000787062be0) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.945 Thread 0x000000010e042e00 Exception (0x0000000787070c60) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 3.946 Thread 0x000000010e042e00 Exception (0x00000007870f37d8) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] -Event: 4.097 Thread 0x000000010e042e00 Exception (0x00000007869dc758) -thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 759] -Event: 4.098 Thread 0x000000010e042e00 Exception (0x00000007869e26b0) -thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 759] -Event: 4.128 Thread 0x000000010e042e00 Exception (0x0000000787f6de50) -thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 759] -Event: 4.169 Thread 0x000000010e099000 Exception (0x0000000787da3bd8) -thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256] - -VM Operations (20 events): -Event: 3.856 Executing VM operation: ICBufferFull -Event: 3.856 Executing VM operation: ICBufferFull done -Event: 4.044 Executing VM operation: ICBufferFull -Event: 4.044 Executing VM operation: ICBufferFull done -Event: 4.090 Executing VM operation: RedefineClasses -Event: 4.096 Executing VM operation: RedefineClasses done -Event: 4.100 Executing VM operation: G1CollectForAllocation -Event: 4.114 Executing VM operation: G1CollectForAllocation done -Event: 4.125 Executing VM operation: HandshakeAllThreads -Event: 4.125 Executing VM operation: HandshakeAllThreads done -Event: 4.163 Executing VM operation: JFRCheckpoint -Event: 4.163 Executing VM operation: JFRCheckpoint done -Event: 4.167 Executing VM operation: JFROldObject -Event: 4.167 Executing VM operation: JFROldObject done -Event: 4.180 Executing VM operation: RedefineClasses -Event: 4.185 Executing VM operation: RedefineClasses done -Event: 4.196 Executing VM operation: ClassLoaderStatsOperation -Event: 4.197 Executing VM operation: ClassLoaderStatsOperation done -Event: 4.207 Executing VM operation: HandshakeAllThreads -Event: 4.208 Executing VM operation: HandshakeAllThreads done - -Events (20 events): -Event: 4.195 loading class sun/rmi/server/MarshalOutputStream done -Event: 4.195 loading class sun/rmi/transport/ConnectionOutputStream done -Event: 4.197 loading class jdk/internal/agent/ConnectorAddressLink -Event: 4.198 loading class jdk/internal/agent/ConnectorAddressLink done -Event: 4.198 loading class sun/management/counter/Units -Event: 4.198 loading class sun/management/counter/Units done -Event: 4.205 Thread 0x000000010d0ac800 Thread added: 0x000000010d0ac800 -Event: 4.205 Protecting memory [0x0000000170a44000,0x0000000170a50000] with protection modes 0 -Event: 4.205 Thread 0x000000012219c400 Thread added: 0x000000012219c400 -Event: 4.205 Protecting memory [0x0000000170c50000,0x0000000170c5c000] with protection modes 0 -Event: 4.205 loading class jdk/internal/vm/PostVMInitHook -Event: 4.205 loading class jdk/internal/vm/PostVMInitHook done -Event: 4.207 loading class jdk/internal/loader/URLClassPath$FileLoader$1 -Event: 4.207 loading class jdk/internal/loader/URLClassPath$FileLoader$1 done -Event: 4.209 loading class sun/security/util/ManifestEntryVerifier -Event: 4.209 loading class sun/security/util/ManifestEntryVerifier done -Event: 4.215 loading class java/lang/UnsupportedOperationException -Event: 4.215 loading class java/lang/UnsupportedOperationException done -Event: 4.216 loading class java/lang/AssertionError -Event: 4.217 loading class java/lang/AssertionError done - - -Dynamic libraries: -0x0000000102980000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjli.dylib -0x00000001b7ac9000 /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa -0x00000001a10aa000 /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit -0x00000001a4118000 /System/Library/Frameworks/CoreData.framework/Versions/A/CoreData -0x000000019e964000 /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation -0x00000001aa41e000 /usr/lib/libSystem.B.dylib -0x00000001a23e7000 /System/Library/PrivateFrameworks/UIFoundation.framework/Versions/A/UIFoundation -0x0000000238046000 /System/Library/PrivateFrameworks/CollectionViewCore.framework/Versions/A/CollectionViewCore -0x00000001b1680000 /System/Library/PrivateFrameworks/RemoteViewServices.framework/Versions/A/RemoteViewServices -0x00000001a82d0000 /System/Library/PrivateFrameworks/XCTTargetBootstrap.framework/Versions/A/XCTTargetBootstrap -0x00000001aca58000 /System/Library/PrivateFrameworks/InternationalSupport.framework/Versions/A/InternationalSupport -0x00000001acaac000 /System/Library/PrivateFrameworks/UserActivity.framework/Versions/A/UserActivity -0x000000025b9a2000 /System/Library/PrivateFrameworks/WindowManagement.framework/Versions/A/WindowManagement -0x000000019e5e4000 /System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration -0x00000001abec7000 /usr/lib/libspindump.dylib -0x00000001a259c000 /System/Library/Frameworks/UniformTypeIdentifiers.framework/Versions/A/UniformTypeIdentifiers -0x00000001a614a000 /usr/lib/libapp_launch_measurement.dylib -0x00000001a5572000 /System/Library/PrivateFrameworks/CoreAnalytics.framework/Versions/A/CoreAnalytics -0x00000001a6151000 /System/Library/PrivateFrameworks/CoreAutoLayout.framework/Versions/A/CoreAutoLayout -0x00000001a7af1000 /System/Library/Frameworks/Metal.framework/Versions/A/Metal -0x00000001a8a77000 /usr/lib/liblangid.dylib -0x00000001a82d6000 /System/Library/PrivateFrameworks/CoreSVG.framework/Versions/A/CoreSVG -0x00000001a2f65000 /System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight -0x00000001a3405000 /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics -0x00000001b1d53000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate -0x00000001abd22000 /System/Library/PrivateFrameworks/IconServices.framework/Versions/A/IconServices -0x00000001a7acf000 /System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface -0x00000001a55a1000 /usr/lib/libDiagnosticMessagesClient.dylib -0x00000001aa361000 /usr/lib/libz.1.dylib -0x00000001b54ef000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices -0x00000001a82b8000 /System/Library/PrivateFrameworks/DFRFoundation.framework/Versions/A/DFRFoundation -0x00000001a0904000 /usr/lib/libicucore.A.dylib -0x00000001adab5000 /System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox -0x00000001aca67000 /System/Library/PrivateFrameworks/DataDetectorsCore.framework/Versions/A/DataDetectorsCore -0x00000001c6442000 /System/Library/PrivateFrameworks/TextInput.framework/Versions/A/TextInput -0x00000001a2eb6000 /usr/lib/libMobileGestalt.dylib -0x00000001a7ff4000 /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox -0x00000001a5a78000 /System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore -0x00000001a0531000 /System/Library/Frameworks/Security.framework/Versions/A/Security -0x00000001b16c0000 /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/SpeechRecognition.framework/Versions/A/SpeechRecognition -0x00000001a5e78000 /System/Library/PrivateFrameworks/CoreUI.framework/Versions/A/CoreUI -0x000000019fe30000 /System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio -0x00000001a5685000 /System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration -0x00000001ac322000 /System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/A/MultitouchSupport -0x00000001a2eb4000 /usr/lib/libenergytrace.dylib -0x00000001bbbcb000 /System/Library/PrivateFrameworks/RenderBox.framework/Versions/A/RenderBox -0x00000001a0f5e000 /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit -0x00000001b1a94000 /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices -0x00000001a60d6000 /System/Library/PrivateFrameworks/PerformanceAnalysis.framework/Versions/A/PerformanceAnalysis -0x00000001f3dad000 /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL -0x00000001a619b000 /usr/lib/libxml2.2.dylib -0x00000001a97a6000 /System/Library/PrivateFrameworks/MobileKeyBag.framework/Versions/A/MobileKeyBag -0x000000019d3d0000 /usr/lib/libobjc.A.dylib -0x000000019d6c4000 /usr/lib/libc++.1.dylib -0x00000001b1a11000 /System/Library/Frameworks/Accessibility.framework/Versions/A/Accessibility -0x00000001a3ae4000 /System/Library/Frameworks/ColorSync.framework/Versions/A/ColorSync -0x000000019d810000 /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation -0x00000001a8632000 /System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage -0x000000019fc3b000 /System/Library/Frameworks/CoreText.framework/Versions/A/CoreText -0x00000001f8607000 /System/Library/Frameworks/CoreTransferable.framework/Versions/A/CoreTransferable -0x00000001f8acc000 /System/Library/Frameworks/DeveloperToolsSupport.framework/Versions/A/DeveloperToolsSupport -0x00000001a8311000 /System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO -0x00000001fce33000 /System/Library/Frameworks/Symbols.framework/Versions/A/Symbols -0x00000001aa424000 /System/Library/PrivateFrameworks/SoftLinking.framework/Versions/A/SoftLinking -0x00000001ad467000 /usr/lib/swift/libswiftCore.dylib -0x00000001c30eb000 /usr/lib/swift/libswiftCoreFoundation.dylib -0x00000001c0bf2000 /usr/lib/swift/libswiftCoreGraphics.dylib -0x00000001c3135000 /usr/lib/swift/libswiftCoreImage.dylib -0x00000001c0bf9000 /usr/lib/swift/libswiftDarwin.dylib -0x00000001b30f9000 /usr/lib/swift/libswiftDispatch.dylib -0x00000001c3136000 /usr/lib/swift/libswiftIOKit.dylib -0x00000001ceb3b000 /usr/lib/swift/libswiftMetal.dylib -0x00000001dc1af000 /usr/lib/swift/libswiftOSLog.dylib -0x00000001b5968000 /usr/lib/swift/libswiftObjectiveC.dylib -0x00000001d325c000 /usr/lib/swift/libswiftQuartzCore.dylib -0x00000001d7343000 /usr/lib/swift/libswiftUniformTypeIdentifiers.dylib -0x00000001c30fd000 /usr/lib/swift/libswiftXPC.dylib -0x0000000263e4d000 /usr/lib/swift/libswift_Concurrency.dylib -0x00000001b596c000 /usr/lib/swift/libswiftos.dylib -0x00000001c63a7000 /usr/lib/swift/libswiftsimd.dylib -0x00000001aa5d3000 /usr/lib/libcompression.dylib -0x00000001ac9b2000 /System/Library/PrivateFrameworks/TextureIO.framework/Versions/A/TextureIO -0x00000001ab9ce000 /usr/lib/libate.dylib -0x00000001aa418000 /usr/lib/system/libcache.dylib -0x00000001aa3d3000 /usr/lib/system/libcommonCrypto.dylib -0x00000001aa3ff000 /usr/lib/system/libcompiler_rt.dylib -0x00000001aa3f5000 /usr/lib/system/libcopyfile.dylib -0x000000019d514000 /usr/lib/system/libcorecrypto.dylib -0x000000019d5fa000 /usr/lib/system/libdispatch.dylib -0x000000019d7b5000 /usr/lib/system/libdyld.dylib -0x00000001aa40e000 /usr/lib/system/libkeymgr.dylib -0x00000001aa3ab000 /usr/lib/system/libmacho.dylib -0x00000001a988c000 /usr/lib/system/libquarantine.dylib -0x00000001aa40b000 /usr/lib/system/libremovefile.dylib -0x00000001a2f2c000 /usr/lib/system/libsystem_asl.dylib -0x000000019d4a9000 /usr/lib/system/libsystem_blocks.dylib -0x000000019d645000 /usr/lib/system/libsystem_c.dylib -0x00000001aa403000 /usr/lib/system/libsystem_collections.dylib -0x00000001a8a66000 /usr/lib/system/libsystem_configuration.dylib -0x00000001a7aa4000 /usr/lib/system/libsystem_containermanager.dylib -0x00000001aa042000 /usr/lib/system/libsystem_coreservices.dylib -0x00000001a0bcb000 /usr/lib/system/libsystem_darwin.dylib -0x000000026419a000 /usr/lib/system/libsystem_darwindirectory.dylib -0x00000001aa40f000 /usr/lib/system/libsystem_dnssd.dylib -0x000000026419e000 /usr/lib/system/libsystem_eligibility.dylib -0x000000019d642000 /usr/lib/system/libsystem_featureflags.dylib -0x000000019d7e3000 /usr/lib/system/libsystem_info.dylib -0x00000001aa370000 /usr/lib/system/libsystem_m.dylib -0x000000019d5bd000 /usr/lib/system/libsystem_malloc.dylib -0x00000001a2e9a000 /usr/lib/system/libsystem_networkextension.dylib -0x00000001a1041000 /usr/lib/system/libsystem_notify.dylib -0x00000001a8a6b000 /usr/lib/system/libsystem_sandbox.dylib -0x00000002641a2000 /usr/lib/system/libsystem_sanitizers.dylib -0x00000001aa408000 /usr/lib/system/libsystem_secinit.dylib -0x000000019d76d000 /usr/lib/system/libsystem_kernel.dylib -0x000000019d7db000 /usr/lib/system/libsystem_platform.dylib -0x000000019d7a8000 /usr/lib/system/libsystem_pthread.dylib -0x00000001a491a000 /usr/lib/system/libsystem_symptoms.dylib -0x000000019d4f9000 /usr/lib/system/libsystem_trace.dylib -0x00000001aa3e1000 /usr/lib/system/libunwind.dylib -0x000000019d4ae000 /usr/lib/system/libxpc.dylib -0x000000019d751000 /usr/lib/libc++abi.dylib -0x00000001aa3ed000 /usr/lib/liboah.dylib -0x00000001ab87a000 /usr/lib/liblzma.5.dylib -0x00000001aa420000 /usr/lib/libfakelink.dylib -0x00000001a2ac5000 /System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork -0x00000001aa474000 /usr/lib/libarchive.2.dylib -0x00000001af996000 /System/Library/Frameworks/Combine.framework/Versions/A/Combine -0x000000023805a000 /System/Library/PrivateFrameworks/CollectionsInternal.framework/Versions/A/CollectionsInternal -0x000000024e0eb000 /System/Library/PrivateFrameworks/ReflectionInternal.framework/Versions/A/ReflectionInternal -0x000000024e671000 /System/Library/PrivateFrameworks/RuntimeInternal.framework/Versions/A/RuntimeInternal -0x0000000263fa1000 /usr/lib/swift/libswift_StringProcessing.dylib -0x00000001a0edc000 /System/Library/PrivateFrameworks/CoreServicesInternal.framework/Versions/A/CoreServicesInternal -0x00000001a98b3000 /usr/lib/libbsm.0.dylib -0x00000001aa3b3000 /usr/lib/system/libkxld.dylib -0x00000001a6112000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/FSEvents -0x00000001a0bd6000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore -0x00000001a55ea000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata -0x00000001aa048000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Versions/A/OSServices -0x00000001aa4fd000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SearchKit.framework/Versions/A/SearchKit -0x00000001a489b000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/AE -0x000000019dce9000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/LaunchServices -0x00000001ab823000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/DictionaryServices.framework/Versions/A/DictionaryServices -0x00000001a611f000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SharedFileList.framework/Versions/A/SharedFileList -0x00000001aa59d000 /usr/lib/libapple_nghttp2.dylib -0x00000001a450f000 /usr/lib/libsqlite3.dylib -0x00000001a4923000 /System/Library/Frameworks/Network.framework/Versions/A/Network -0x000000026285a000 /usr/lib/libCoreEntitlements.dylib -0x000000024901d000 /System/Library/PrivateFrameworks/MessageSecurity.framework/Versions/A/MessageSecurity -0x00000001a44f5000 /System/Library/PrivateFrameworks/ProtocolBuffer.framework/Versions/A/ProtocolBuffer -0x00000001a9f71000 /System/Library/PrivateFrameworks/AppleFSCompression.framework/Versions/A/AppleFSCompression -0x00000001a989b000 /usr/lib/libcoretls.dylib -0x00000001ab899000 /usr/lib/libcoretls_cfhelpers.dylib -0x00000001aa5cd000 /usr/lib/libpam.2.dylib -0x00000001ab90b000 /usr/lib/libxar.1.dylib -0x00000001abcf9000 /usr/lib/libheimdal-asn1.dylib -0x00000001a2ac4000 /usr/lib/libnetwork.dylib -0x00000001aa425000 /usr/lib/libpcap.A.dylib -0x00000001a490f000 /usr/lib/libdns_services.dylib -0x00000001a8a73000 /System/Library/PrivateFrameworks/AppleSystemInfo.framework/Versions/A/AppleSystemInfo -0x00000001a959b000 /System/Library/PrivateFrameworks/IOMobileFramebuffer.framework/Versions/A/IOMobileFramebuffer -0x0000000263ef8000 /usr/lib/swift/libswift_RegexParser.dylib -0x00000001aa035000 /usr/lib/libbz2.1.0.dylib -0x00000001a988f000 /usr/lib/libCheckFix.dylib -0x00000001a2f44000 /System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC -0x00000001a8a79000 /System/Library/PrivateFrameworks/CoreNLP.framework/Versions/A/CoreNLP -0x00000001a55a3000 /System/Library/PrivateFrameworks/MetadataUtilities.framework/Versions/A/MetadataUtilities -0x00000001a98c5000 /usr/lib/libmecab.dylib -0x000000019e678000 /usr/lib/libCRFSuite.dylib -0x00000001a9921000 /usr/lib/libgermantok.dylib -0x00000001aa574000 /usr/lib/libThaiTokenizer.dylib -0x00000001a568e000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vImage.framework/Versions/A/vImage -0x00000001b1a6b000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/vecLib -0x00000001ab952000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvMisc.dylib -0x00000001a9476000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvDSP.dylib -0x000000019e0ef000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib -0x00000001aa6a8000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib -0x00000001a9924000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib -0x00000001aa5b8000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib -0x00000001aa6a3000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib -0x00000001a8ba2000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBNNS.dylib -0x000000019e57d000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparse.dylib -0x000000024776c000 /System/Library/PrivateFrameworks/MIL.framework/Versions/A/MIL -0x00000001aa45b000 /usr/lib/libiconv.2.dylib -0x00000001aa3a7000 /usr/lib/libcharset.1.dylib -0x00000001a60f2000 /System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework/Versions/A/CFOpenDirectory -0x00000001a60e2000 /System/Library/Frameworks/OpenDirectory.framework/Versions/A/OpenDirectory -0x00000001ab89b000 /System/Library/PrivateFrameworks/APFS.framework/Versions/A/APFS -0x00000001a97cc000 /System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation -0x00000001ab91a000 /usr/lib/libutil.dylib -0x00000002458f1000 /System/Library/PrivateFrameworks/InstalledContentLibrary.framework/Versions/A/InstalledContentLibrary -0x00000001a0f1d000 /System/Library/PrivateFrameworks/CoreServicesStore.framework/Versions/A/CoreServicesStore -0x000000023581f000 /System/Library/PrivateFrameworks/AppleMobileFileIntegrity.framework/Versions/A/AppleMobileFileIntegrity -0x00000001c30b9000 /usr/lib/libmis.dylib -0x00000001d3742000 /System/Library/PrivateFrameworks/MobileSystemServices.framework/Versions/A/MobileSystemServices -0x00000001f11bb000 /System/Library/PrivateFrameworks/ConfigProfileHelper.framework/Versions/A/ConfigProfileHelper -0x00000001aa576000 /System/Library/PrivateFrameworks/AppleSauce.framework/Versions/A/AppleSauce -0x000000019f5c2000 /System/Library/PrivateFrameworks/LanguageModeling.framework/Versions/A/LanguageModeling -0x00000001ab91e000 /usr/lib/libxslt.1.dylib -0x00000001aa462000 /usr/lib/libcmph.dylib -0x00000001a9567000 /System/Library/PrivateFrameworks/CoreEmoji.framework/Versions/A/CoreEmoji -0x00000001a8b9c000 /System/Library/PrivateFrameworks/LinguisticData.framework/Versions/A/LinguisticData -0x000000019e48b000 /System/Library/PrivateFrameworks/Lexicon.framework/Versions/A/Lexicon -0x00000001a985a000 /System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement -0x0000000262a48000 /usr/lib/libTLE.dylib -0x00000001ac1e8000 /System/Library/PrivateFrameworks/AppleJPEG.framework/Versions/A/AppleJPEG -0x00000001abcde000 /usr/lib/libexpat.1.dylib -0x00000001ac810000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib -0x00000001ac83b000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib -0x00000001ac926000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libGIF.dylib -0x00000001ac22e000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJP2.dylib -0x00000001ac8cb000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib -0x00000001ac8c2000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libRadiance.dylib -0x00000001a7e8f000 /System/Library/PrivateFrameworks/FontServices.framework/libFontParser.dylib -0x00000001a4834000 /System/Library/PrivateFrameworks/RunningBoardServices.framework/Versions/A/RunningBoardServices -0x00000001b839d000 /System/Library/PrivateFrameworks/IOSurfaceAccelerator.framework/Versions/A/IOSurfaceAccelerator -0x00000001ac31e000 /System/Library/PrivateFrameworks/WatchdogClient.framework/Versions/A/WatchdogClient -0x000000019f7a8000 /System/Library/Frameworks/CoreDisplay.framework/Versions/A/CoreDisplay -0x00000001a7d47000 /System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia -0x00000001a7ae7000 /System/Library/PrivateFrameworks/IOAccelerator.framework/Versions/A/IOAccelerator -0x00000001a6285000 /System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo -0x00000001aa5cb000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders -0x00000001ac361000 /System/Library/Frameworks/VideoToolbox.framework/Versions/A/VideoToolbox -0x00000001a6321000 /System/Library/PrivateFrameworks/UserManagement.framework/Versions/A/UserManagement -0x00000001a475b000 /System/Library/PrivateFrameworks/BaseBoard.framework/Versions/A/BaseBoard -0x00000001a8a71000 /System/Library/PrivateFrameworks/AggregateDictionary.framework/Versions/A/AggregateDictionary -0x0000000235659000 /System/Library/PrivateFrameworks/AppleKeyStore.framework/Versions/A/AppleKeyStore -0x00000001ac8bd000 /System/Library/PrivateFrameworks/GPUWrangler.framework/Versions/A/GPUWrangler -0x00000001ac89d000 /System/Library/PrivateFrameworks/IOPresentment.framework/Versions/A/IOPresentment -0x00000001ac8c5000 /System/Library/PrivateFrameworks/DSExternalDisplay.framework/Versions/A/DSExternalDisplay -0x00000002419dd000 /System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/libllvm-flatbuffers.dylib -0x00000001f3da0000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreFSCache.dylib -0x000000023ebf9000 /System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/libGPUCompilerUtils.dylib -0x00000001ac92c000 /System/Library/PrivateFrameworks/CMCaptureCore.framework/Versions/A/CMCaptureCore -0x00000001f8bed000 /System/Library/Frameworks/ExtensionFoundation.framework/Versions/A/ExtensionFoundation -0x00000001b3961000 /System/Library/PrivateFrameworks/CoreTime.framework/Versions/A/CoreTime -0x00000001abeb1000 /System/Library/PrivateFrameworks/AppServerSupport.framework/Versions/A/AppServerSupport -0x00000001ae443000 /System/Library/PrivateFrameworks/perfdata.framework/Versions/A/perfdata -0x000000019f8cc000 /System/Library/PrivateFrameworks/AudioToolboxCore.framework/Versions/A/AudioToolboxCore -0x00000001a7d1d000 /System/Library/PrivateFrameworks/caulk.framework/Versions/A/caulk -0x00000001adcb1000 /usr/lib/libAudioStatistics.dylib -0x00000001c23f6000 /System/Library/PrivateFrameworks/SystemPolicy.framework/Versions/A/SystemPolicy -0x00000001adf8a000 /usr/lib/libSMC.dylib -0x00000001b794b000 /System/Library/Frameworks/CoreMIDI.framework/Versions/A/CoreMIDI -0x00000001ac7d7000 /usr/lib/libAudioToolboxUtility.dylib -0x00000001bd867000 /System/Library/PrivateFrameworks/OSAServicesClient.framework/Versions/A/OSAServicesClient -0x00000001ae451000 /usr/lib/libperfcheck.dylib -0x00000001b3419000 /System/Library/PrivateFrameworks/BoardServices.framework/Versions/A/BoardServices -0x00000001abbc6000 /System/Library/PrivateFrameworks/PlugInKit.framework/Versions/A/PlugInKit -0x00000001a97be000 /System/Library/PrivateFrameworks/AssertionServices.framework/Versions/A/AssertionServices -0x00000001b6a65000 /System/Library/PrivateFrameworks/ASEProcessing.framework/Versions/A/ASEProcessing -0x00000001df625000 /System/Library/PrivateFrameworks/Symbolication.framework/Versions/A/Symbolication -0x000000024cee1000 /System/Library/PrivateFrameworks/PhotosensitivityProcessing.framework/Versions/A/PhotosensitivityProcessing -0x00000001abe62000 /System/Library/PrivateFrameworks/GraphVisualizer.framework/Versions/A/GraphVisualizer -0x00000001f3e02000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib -0x00000001f3dc1000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGFXShared.dylib -0x00000001f3f9a000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib -0x00000001f3dca000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLImage.dylib -0x00000001f3dbe000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCVMSPluginSupport.dylib -0x0000000262a00000 /usr/lib/libRosetta.dylib -0x00000001f3da7000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreVMClient.dylib -0x000000023cf93000 /System/Library/PrivateFrameworks/FontServices.framework/Versions/A/FontServices -0x00000001abe6e000 /System/Library/PrivateFrameworks/OTSVG.framework/Versions/A/OTSVG -0x00000001a5e26000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontRegistry.dylib -0x00000001abebc000 /System/Library/PrivateFrameworks/FontServices.framework/libhvf.dylib -0x000000023cf94000 /System/Library/PrivateFrameworks/FontServices.framework/libXTFontStaticRegistryData.dylib -0x00000001a89b8000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSCore.framework/Versions/A/MPSCore -0x00000001a9edf000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSImage.framework/Versions/A/MPSImage -0x00000001a9939000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNeuralNetwork.framework/Versions/A/MPSNeuralNetwork -0x00000001a9d84000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSMatrix.framework/Versions/A/MPSMatrix -0x00000001a9b8f000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSRayIntersector.framework/Versions/A/MPSRayIntersector -0x00000001a9db6000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNDArray.framework/Versions/A/MPSNDArray -0x00000001fa432000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSFunctions.framework/Versions/A/MPSFunctions -0x00000001fa417000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSBenchmarkLoop.framework/Versions/A/MPSBenchmarkLoop -0x000000019dfa3000 /System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/MetalTools -0x00000001c757b000 /System/Library/PrivateFrameworks/IOAccelMemoryInfo.framework/Versions/A/IOAccelMemoryInfo -0x00000001d363c000 /System/Library/PrivateFrameworks/kperf.framework/Versions/A/kperf -0x00000001c30de000 /System/Library/PrivateFrameworks/GPURawCounter.framework/Versions/A/GPURawCounter -0x00000001b3833000 /System/Library/PrivateFrameworks/CoreSymbolication.framework/Versions/A/CoreSymbolication -0x00000001c308a000 /System/Library/PrivateFrameworks/MallocStackLogging.framework/Versions/A/MallocStackLogging -0x00000001aba68000 /System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport -0x00000001b37ee000 /System/Library/PrivateFrameworks/DebugSymbols.framework/Versions/A/DebugSymbols -0x00000001d1fac000 /System/Library/PrivateFrameworks/OSAnalytics.framework/Versions/A/OSAnalytics -0x0000000259c57000 /System/Library/PrivateFrameworks/VideoToolboxParavirtualizationSupport.framework/Versions/A/VideoToolboxParavirtualizationSupport -0x00000001abc92000 /System/Library/PrivateFrameworks/AppleVA.framework/Versions/A/AppleVA -0x00000001adcf9000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/ATS -0x00000001a3c93000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/HIServices -0x00000001ac93a000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/PrintCore -0x00000001ae0e3000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/QD -0x00000001ae0d7000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ColorSyncLegacy.framework/Versions/A/ColorSyncLegacy -0x00000001adcc9000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesis -0x00000001ac8f6000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATSUI.framework/Versions/A/ATSUI -0x00000001ae06a000 /usr/lib/libcups.2.dylib -0x00000001ae45f000 /System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos -0x00000001ae470000 /System/Library/Frameworks/GSS.framework/Versions/A/GSS -0x00000001add78000 /usr/lib/libresolv.9.dylib -0x00000001abecd000 /System/Library/PrivateFrameworks/Heimdal.framework/Versions/A/Heimdal -0x00000001b58d6000 /System/Library/Frameworks/Kerberos.framework/Versions/A/Libraries/libHeimdalProxy.dylib -0x00000001ae4ca000 /System/Library/PrivateFrameworks/CommonAuth.framework/Versions/A/CommonAuth -0x00000001f79da000 /System/Library/Frameworks/AVFAudio.framework/Versions/A/AVFAudio -0x00000001bd8b6000 /System/Library/PrivateFrameworks/AXCoreUtilities.framework/Versions/A/AXCoreUtilities -0x0000000246e64000 /System/Library/PrivateFrameworks/IsolatedCoreAudioClient.framework/Versions/A/IsolatedCoreAudioClient -0x00000001adc35000 /System/Library/PrivateFrameworks/AudioSession.framework/Versions/A/AudioSession -0x00000001af733000 /System/Library/Frameworks/IOBluetooth.framework/Versions/A/IOBluetooth -0x00000001abd9d000 /System/Library/PrivateFrameworks/MediaExperience.framework/Versions/A/MediaExperience -0x00000001ada74000 /System/Library/PrivateFrameworks/AudioSession.framework/libSessionUtility.dylib -0x00000001ae0ef000 /System/Library/PrivateFrameworks/AudioResourceArbitration.framework/Versions/A/AudioResourceArbitration -0x00000001b27a9000 /System/Library/PrivateFrameworks/PowerLog.framework/Versions/A/PowerLog -0x00000001b26c8000 /System/Library/Frameworks/CoreBluetooth.framework/Versions/A/CoreBluetooth -0x00000001b58d7000 /System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit -0x00000001a9628000 /System/Library/PrivateFrameworks/CoreUtils.framework/Versions/A/CoreUtils -0x000000023b2db000 /System/Library/PrivateFrameworks/CoreUtilsExtras.framework/Versions/A/CoreUtilsExtras -0x000000024577f000 /System/Library/PrivateFrameworks/IO80211.framework/Versions/A/IO80211 -0x00000001b335d000 /System/Library/PrivateFrameworks/FrontBoardServices.framework/Versions/A/FrontBoardServices -0x00000001b4ea1000 /System/Library/PrivateFrameworks/BackBoardServices.framework/Versions/A/BackBoardServices -0x00000001abd04000 /System/Library/PrivateFrameworks/IconFoundation.framework/Versions/A/IconFoundation -0x00000001b16ac000 /System/Library/PrivateFrameworks/SpeechRecognitionCore.framework/Versions/A/SpeechRecognitionCore -0x00000001bd8d5000 /usr/lib/libAccessibility.dylib -0x00000001b1d9f000 /System/Library/Frameworks/MediaAccessibility.framework/Versions/A/MediaAccessibility -0x00000001e2cb6000 /System/Library/Frameworks/OSLog.framework/Versions/A/OSLog -0x00000001c3018000 /System/Library/PrivateFrameworks/LoggingSupport.framework/Versions/A/LoggingSupport -0x0000000103a34000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/server/libjvm.dylib -0x0000000102528000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjimage.dylib -0x0000000102558000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libinstrument.dylib -0x00000001025a8000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjava.dylib -0x00000001026e4000 /private/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/libasyncProfiler.so -0x00000001026a4000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libzip.dylib -0x000000010276c000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libnio.dylib -0x000000010278c000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libnet.dylib -0x0000000102588000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libextnet.dylib -0x00000001026cc000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libmanagement.dylib -0x00000001027b0000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libmanagement_ext.dylib -0x00000001ad409000 /usr/lib/libusrtcp.dylib -0x00000001a29fb000 /usr/lib/libboringssl.dylib - - -VM Arguments: -jvm_args: -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57802:/Applications/IntelliJ IDEA.app/Contents/bin -agentpath:/private/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/libasyncProfiler.so=start,jfr,event=cpu,interval=10ms,jfrsync=profile,cstack=no,file=/Users/sungmin/IdeaSnapshots/ComNCheckApplication_2025_01_26_233554.jfr,log=/private/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/ComNCheckApplication_2025_01_26_233554.jfr.log.txt,logLevel=DEBUG -Dfile.encoding=UTF-8 -java_command: com.ComNCheck.ComNCheck.ComNCheckApplication -java_class_path (initial): /Users/sungmin/Desktop/ComNCheck/Spring/ComNCheck-backend/build/classes/java/main:/Users/sungmin/Desktop/ComNCheck/Spring/ComNCheck-backend/build/resources/main:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.36/5a30490a6e14977d97d9c73c924c1f1b5311ea95/lombok-1.18.36.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-oauth2-client/3.4.1/9d39fbd91d9231bf0c9d3259e5152b9bda733f1a/spring-boot-starter-oauth2-client-3.4.1.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-security/3.4.1/6a82a9f484d265c73a203d551b614cd8bdde5825/spring-boot-starter-security-3.4.1.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/io.jsonwebtoken/jjwt-impl/0.12.3/e850d2b3f53bd82355cd9ee1c471054aa602b320/jjwt-impl-0.12.3.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/io.jsonwebtoken/jjwt-jackson/0.12.3/5e6d0e45441547d892d3273a4ce5dd042e91d162/jjwt-jackson-0.12.3.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/io.jsonwebtoken/jjwt-api/0.12.3/30b7de9176d17fa347eef14b85480825dab76b58/jjwt-api-0.12.3.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/io.github.cdimascio/java-dotenv/5.2.2/f77d54ff193ed4b07415ab8d7b3d0550716aa8c/java-dotenv-5.2.2.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-data-jpa/3.4.1/f06be4354c339f3f880a5c66a6913cd2366eb225/spring-boot-starter-data-jpa-3.4.1.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-web/3.4.1/ff7227fc62338e0f6eba3f9f94c12eb952d4da95/spring-boot-starter-web-3.4.1.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springdoc/springdoc-openapi-starter-webmvc-ui/2.7.0/4426174e7fa7428a1c5f2edbd352c89e3e6b9794/springdoc-openapi-starter-webmvc-ui-2.7.0.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter/3.4.1/2c97b6fdc451ea69cd04dcfa -Launcher Type: SUN_STANDARD - -[Global flags] - intx CICompilerCount = 4 {product} {ergonomic} - uint ConcGCThreads = 2 {product} {ergonomic} - bool FlightRecorder = true {product} {management} - uint G1ConcRefinementThreads = 8 {product} {ergonomic} - size_t G1HeapRegionSize = 1048576 {product} {ergonomic} - uintx GCDrainStackTargetSize = 64 {product} {ergonomic} - size_t InitialHeapSize = 134217728 {product} {ergonomic} - bool ManagementServer = true {product} {command line} - size_t MarkStackSize = 4194304 {product} {ergonomic} - size_t MaxHeapSize = 2147483648 {product} {ergonomic} - size_t MaxNewSize = 1287651328 {product} {ergonomic} - size_t MinHeapDeltaBytes = 1048576 {product} {ergonomic} - size_t MinHeapSize = 8388608 {product} {ergonomic} - uintx NonProfiledCodeHeapSize = 0 {pd product} {ergonomic} - bool ProfileInterpreter = false {pd product} {command line} - uintx ProfiledCodeHeapSize = 0 {pd product} {ergonomic} - size_t SoftMaxHeapSize = 2147483648 {manageable} {ergonomic} - intx TieredStopAtLevel = 1 {product} {command line} - bool UseCompressedClassPointers = true {product lp64_product} {ergonomic} - bool UseCompressedOops = true {product lp64_product} {ergonomic} - bool UseG1GC = true {product} {ergonomic} - bool UseNUMA = false {product} {ergonomic} - bool UseNUMAInterleaving = false {product} {ergonomic} - -Logging: -Log output configuration: - #0: stdout all=warning,jni+resolve=error uptime,level,tags (reconfigured) - #1: stderr all=off uptime,level,tags - -Environment Variables: -PATH=/Users/sungmin/opt/anaconda3/bin:/Library/Frameworks/Python.framework/Versions/3.9/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin -SHELL=/bin/zsh -LC_CTYPE=ko_KR.UTF-8 -TMPDIR=/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/ - -Active Locale: -LC_ALL=C/ko_KR.UTF-8/C/C/C/C -LC_COLLATE=C -LC_CTYPE=ko_KR.UTF-8 -LC_MESSAGES=C -LC_MONETARY=C -LC_NUMERIC=C -LC_TIME=C - -Signal Handlers: - SIGSEGV: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked - SIGBUS: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked - SIGFPE: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked - SIGPIPE: javaSignalHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked - SIGXFSZ: javaSignalHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked - SIGILL: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked - SIGUSR2: SR_handler in libjvm.dylib, mask=00100000000000000000000000000000, flags=SA_RESTART|SA_SIGINFO, blocked - SIGHUP: UserHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked - SIGINT: UserHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked - SIGTERM: UserHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked - SIGQUIT: UserHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked - SIGTRAP: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked - - ---------------- S Y S T E M --------------- - -OS: -uname: Darwin 23.4.0 Darwin Kernel Version 23.4.0: Fri Mar 15 00:12:41 PDT 2024; root:xnu-10063.101.17~1/RELEASE_ARM64_T8103 arm64 -OS uptime: 3 days 23:18 hours -rlimit (soft/hard): STACK 8176k/65520k , CORE 0k/infinity , NPROC 1333/2000 , NOFILE 10240/infinity , AS infinity/infinity , CPU infinity/infinity , DATA infinity/infinity , FSIZE infinity/infinity , MEMLOCK infinity/infinity , RSS infinity/infinity -load average: 4.29 3.02 3.73 - -CPU: total 8 (initial active 8) 0x61:0x0:0x1b588bb3:0, fp, simd, crc, lse -machdep.cpu.brand_string:Apple M1 -hw.cachelinesize:128 -hw.l1icachesize:131072 -hw.l1dcachesize:65536 -hw.l2cachesize:4194304 - -Memory: 16k page, physical 8388608k(149104k free), swap 9437184k(1607680k free) - -vm_info: OpenJDK 64-Bit Server VM (17.0.8.1+8-LTS) for bsd-aarch64 JRE (17.0.8.1+8-LTS), built on Aug 18 2023 22:52:47 by "ec2user" with clang Apple LLVM 13.0.0 (clang-1300.0.29.30) - -END. diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java new file mode 100644 index 0000000..e71449a --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java @@ -0,0 +1,26 @@ +package com.ComNCheck.ComNCheck.domain.employmentNotice.config.scheduler; + + +import com.ComNCheck.ComNCheck.domain.employmentNotice.service.EmploymentNoticeService; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +@Configuration +@EnableScheduling +@RequiredArgsConstructor +public class EmploymentNoticeScheduler { + private EmploymentNoticeService employmentNoticeService; + + @Scheduled(cron = "0 0 * * * *") + public void syncEmploymentNoticePeriodically() { + employmentNoticeService.syncEmploymentNotices(); + } + + @PostConstruct + public void initLoad() { + employmentNoticeService.syncEmploymentNotices(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java new file mode 100644 index 0000000..d0384b0 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java @@ -0,0 +1,37 @@ +package com.ComNCheck.ComNCheck.domain.employmentNotice.controller; + +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.PageEmploymentNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.employmentNotice.service.EmploymentNoticeService; +import jakarta.xml.bind.annotation.XmlType.DEFAULT; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RequestMapping("/api/v1/employment/notices") +@RestController +public class EmploymentController { + + private final EmploymentNoticeService employmentNoticeService; + + @GetMapping + public ResponseEntity> getAllEmploymentNotice() { + List lists = employmentNoticeService.getAllEmploymentNotices(); + return ResponseEntity.ok(lists); + } + + @GetMapping("/pages") + public ResponseEntity getEmploymentNoticePage( + @RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "10") int size + ) { + PageEmploymentNoticeResponseDTO pageResponse = employmentNoticeService.getEmploymentNoticesPage(page, size); + return ResponseEntity.ok(pageResponse); + + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java new file mode 100644 index 0000000..e240f77 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java @@ -0,0 +1,27 @@ +package com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response; + +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; +import java.time.LocalDate; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class EmploymentNoticeResponseDTO { + private int employmentNoticeId; + private String title; + @JsonFormat(shape = Shape.STRING, pattern = "yyyy.mm.dd") + private LocalDate date; + private String link; + + public static EmploymentNoticeResponseDTO of(EmploymentNotice employmentNotice) { + return EmploymentNoticeResponseDTO.builder() + .employmentNoticeId(employmentNotice.getEmploymentNoticeId()) + .title(employmentNotice.getTitle()) + .date(employmentNotice.getDate()) + .link(employmentNotice.getLink()) + .build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/FastAPIEmploymentNoticeResponseListDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/FastAPIEmploymentNoticeResponseListDTO.java new file mode 100644 index 0000000..ed475f9 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/FastAPIEmploymentNoticeResponseListDTO.java @@ -0,0 +1,12 @@ +package com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response; + +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class FastAPIEmploymentNoticeResponseListDTO { + private List notices; +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/PageEmploymentNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/PageEmploymentNoticeResponseDTO.java new file mode 100644 index 0000000..ba94486 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/PageEmploymentNoticeResponseDTO.java @@ -0,0 +1,16 @@ +package com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response; + +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class PageEmploymentNoticeResponseDTO { + private int currentPage; + private int totalPages; + private long totalElements; + private int size; + private List content; +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java new file mode 100644 index 0000000..e395768 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java @@ -0,0 +1,51 @@ +package com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity; + +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.time.LocalDate; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + + +@Getter +@Table(name = "employment_notices") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class EmploymentNotice { + @Id + @Column(name = "employment_notice_id") + private int employmentNoticeId; + + @Column + private String title; + + @Column + private LocalDate date; + + @Column + private String link; + + public EmploymentNotice(EmploymentNoticeResponseDTO dto) { + this.employmentNoticeId = dto.getEmploymentNoticeId(); + this.title = dto.getTitle(); + this.date = dto.getDate(); + this.link = dto.getLink(); + } + + public boolean equalsDTO(EmploymentNoticeResponseDTO dto) { + return this.employmentNoticeId == dto.getEmploymentNoticeId() && + this.title.equals(dto.getTitle()) && + this.date.isEqual(dto.getDate()) && + this.link.equals(dto.getLink()); + } + public void updateFromDto(EmploymentNoticeResponseDTO dto) { + this.title = dto.getTitle(); + this.date = dto.getDate(); + this.link = dto.getLink(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java new file mode 100644 index 0000000..5890839 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java @@ -0,0 +1,10 @@ +package com.ComNCheck.ComNCheck.domain.employmentNotice.repository; + +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface EmploymentNoticeRepository extends JpaRepository { + + Optional findEmploymentNoticeId(int employmentNoticeId); +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java new file mode 100644 index 0000000..318b528 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java @@ -0,0 +1,101 @@ +package com.ComNCheck.ComNCheck.domain.employmentNotice.service; + +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.FastAPIEmploymentNoticeResponseListDTO; +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.PageEmploymentNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice; +import com.ComNCheck.ComNCheck.domain.employmentNotice.repository.EmploymentNoticeRepository; +import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.PageMajorNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class EmploymentNoticeService { + + private EmploymentNoticeRepository employmentNoticeRepository; + private FastApiClient fastApiClient; + + @Transactional + public void syncEmploymentNotices() { + FastAPIEmploymentNoticeResponseListDTO response = fastApiClient.fetchEmploymentNotices(); + + List changeEmploymentNotices = new ArrayList<>(); + + if(response != null && response.getNotices() != null) { + for(EmploymentNoticeResponseDTO dto : response.getNotices()) { + Optional findEmployment = employmentNoticeRepository + .findEmploymentNoticeId(dto.getEmploymentNoticeId()); + if(findEmployment.isEmpty()) { + EmploymentNotice newEmploymentNotice = new EmploymentNotice(dto); + employmentNoticeRepository.save(newEmploymentNotice); + changeEmploymentNotices.add(newEmploymentNotice); + } else { + EmploymentNotice existEmploymentNotice = findEmployment.get(); + if(!existEmploymentNotice.equalsDTO(dto)) { + existEmploymentNotice.updateFromDto(dto); + employmentNoticeRepository.save(existEmploymentNotice); + changeEmploymentNotices.add(existEmploymentNotice); + } + } + } + + } + if (!changeEmploymentNotices.isEmpty()) { + // fcm 기능 구현 + } + + } + + public List getAllEmploymentNotices() { + return employmentNoticeRepository.findAll() + .stream() + .map(EmploymentNoticeResponseDTO::of) + .toList(); + } + + public PageEmploymentNoticeResponseDTO getEmploymentNoticesPage(int page, int size) { + List allEmploymentNotices = employmentNoticeRepository.findAll(); + allEmploymentNotices.sort(Comparator.comparing(EmploymentNotice::getDate).reversed()); + + long totalElements = allEmploymentNotices.size(); + int totalPages = (int) Math.ceil((double) totalElements / size); + + if (page < 1) { + page = 1; + } else if (page > totalPages && totalPages > 0) { + page = totalPages; + } + + int zeroBasedPage = page - 1; + int startIndex = zeroBasedPage * size; + int endIndex = Math.min(startIndex + size, (int) totalElements); + + List pageList = (startIndex < endIndex) + ? allEmploymentNotices.subList(startIndex, endIndex) + : Collections.emptyList(); + + List content = pageList.stream() + .map(EmploymentNoticeResponseDTO::of) + .collect(Collectors.toList()); + + return PageEmploymentNoticeResponseDTO.builder() + .currentPage(page) + .totalPages(totalPages) + .totalElements(totalElements) + .size(size) + .content(content) + .build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java index cf3d163..58887fd 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java @@ -1,11 +1,14 @@ package com.ComNCheck.ComNCheck.domain.global.infrastructure; +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.FastAPIEmploymentNoticeResponseListDTO; import com.ComNCheck.ComNCheck.domain.global.exception.FastApiException; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.FastAPIMajorNoticesResponseListDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO; import java.io.IOException; import lombok.RequiredArgsConstructor; import org.springframework.core.io.ByteArrayResource; import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -21,6 +24,8 @@ public class FastApiClient { private final RestTemplate restTemplate; private static final String FAST_API_URL_OCR= "http://localhost:8000/api/vi/compare-and-ocr"; + private static final String FAST_API_URL_SCRAPE_NOTICE = "http://localhost:8000/api/vi/scrape/notice"; + private static final String Fast_API_URL_EMPLOYMENT = "http://localhost:8000/api/vi/scrape/employment"; public FastApiStudentCardDTO sendImage(MultipartFile imageFile) { MultiValueMap body = new LinkedMultiValueMap<>(); @@ -54,4 +59,54 @@ public String getFilename() { throw new FastApiException("이미지 처리 중 오류 발생: " + e.getMessage(), e); } } + + public FastAPIMajorNoticesResponseListDTO fetchMajorNotices() { + try { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity requestEntity = new HttpEntity<>(headers); + + ResponseEntity response = restTemplate.exchange( + FAST_API_URL_SCRAPE_NOTICE, + HttpMethod.GET, + requestEntity, + FastAPIMajorNoticesResponseListDTO.class + ); + + if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) { + throw new FastApiException("FastAPI 호출 실패: " + response.getStatusCode()); + } + + return response.getBody(); + + } catch (Exception e) { + throw new FastApiException("공지사항 가져오기 중 오류 발생: " + e.getMessage(), e); + } + } + + public FastAPIEmploymentNoticeResponseListDTO fetchEmploymentNotices() { + try { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity requestEntity = new HttpEntity<>(headers); + + ResponseEntity response = restTemplate.exchange( + Fast_API_URL_EMPLOYMENT, + HttpMethod.GET, + requestEntity, + FastAPIEmploymentNoticeResponseListDTO.class + ); + + if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) { + throw new FastApiException("FastAPI 호출 실패: " + response.getStatusCode()); + } + + return response.getBody(); + + } catch (Exception e) { + throw new FastApiException("공지사항 가져오기 중 오류 발생: " + e.getMessage(), e); + } + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java index f1cecca..5c31fca 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java @@ -18,7 +18,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/api/v1/major-event") @@ -49,14 +48,14 @@ public ResponseEntity> getAllMajorEventsNotPassed() { return ResponseEntity.ok(allMajorEventsNotPassed); } - @GetMapping("/pages") - public ResponseEntity getAllMajorEventPage( - @RequestParam(defaultValue = "1") int page, - @RequestParam(defaultValue = "10") int size - ) { - PagedEventListResponseDTO responseDTO = majorEventService.getAllMajorEventPage(page, size); - return ResponseEntity.ok(responseDTO); - } +// @GetMapping("/pages") +// public ResponseEntity getAllMajorEventPage( +// @RequestParam(defaultValue = "1") int page, +// @RequestParam(defaultValue = "10") int size +// ) { +// PagedEventListResponseDTO responseDTO = majorEventService.getAllMajorEventPage(page, size); +// return ResponseEntity.ok(responseDTO); +// } @PutMapping("/{majorEventId}") public ResponseEntity updateMajorEvent( diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/repository/MajorEventRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/repository/MajorEventRepository.java index fa7abd0..ee14a28 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/repository/MajorEventRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/repository/MajorEventRepository.java @@ -9,15 +9,15 @@ import org.springframework.data.repository.query.Param; public interface MajorEventRepository extends JpaRepository { - @Query(""" - SELECT e - FROM MajorEvent e - WHERE (e.date > :today) - OR (e.date = :today AND e.time >= :currentTime) - ORDER BY e.date ASC, e.time ASC - """) - List findUpcomingEvents( - @Param("today") LocalDate today, - @Param("currentTime") LocalTime currentTime - ); +// @Query(""" +// SELECT e +// FROM MajorEvent e +// WHERE (e.date > :today) +// OR (e.date = :today AND e.time >= :currentTime) +// ORDER BY e.date ASC, e.time ASC +// """) +// List findUpcomingEvents( +// @Param("today") LocalDate today, +// @Param("currentTime") LocalTime currentTime +// ); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java index 3e9b6f4..684e221 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java @@ -75,48 +75,48 @@ public List getAllMajorEventsNotPassed() { .collect(Collectors.toList()); } - public PagedEventListResponseDTO getAllMajorEventPage(int page, int size) { - List all = majorEventRepository.findAll(); - - LocalDate today = LocalDate.now(); - LocalTime currentTime = LocalTime.now(); - - List filtered = all.stream() - .filter(e -> isNotPassed(e, today, currentTime)) - .collect(Collectors.toList()); - - filtered.sort(Comparator.comparing(MajorEvent::getDate) - .thenComparing(MajorEvent::getTime)); - - long totalElements = filtered.size(); - int totalPages = (int) Math.ceil((double) totalElements / size); - - if (page < 1) { - page = 1; - } else if (page >= totalPages && totalPages > 0) { - page = totalPages -1; - } - int zeroBasedPage = page - 1; - int startIndex = zeroBasedPage * size; - int endIndex = Math.min(startIndex + size, (int) totalElements); - - List pageList = (startIndex < endIndex) - ? filtered.subList(startIndex, endIndex) - : Collections.emptyList(); - - List content = pageList.stream() - .map(EventListResponseDTO::of) - .toList(); - - return PagedEventListResponseDTO.builder() - .currentPage(page) - .totalPages(totalPages) - .totalElements(totalElements) - .size(size) - .content(content) - .build(); - - } +// public PagedEventListResponseDTO getAllMajorEventPage(int page, int size) { +// List all = majorEventRepository.findAll(); +// +// LocalDate today = LocalDate.now(); +// LocalTime currentTime = LocalTime.now(); +// +// List filtered = all.stream() +// .filter(e -> isNotPassed(e, today, currentTime)) +// .collect(Collectors.toList()); +// +// filtered.sort(Comparator.comparing(MajorEvent::getDate) +// .thenComparing(MajorEvent::getTime)); +// +// long totalElements = filtered.size(); +// int totalPages = (int) Math.ceil((double) totalElements / size); +// +// if (page < 1) { +// page = 1; +// } else if (page >= totalPages && totalPages > 0) { +// page = totalPages -1; +// } +// int zeroBasedPage = page - 1; +// int startIndex = zeroBasedPage * size; +// int endIndex = Math.min(startIndex + size, (int) totalElements); +// +// List pageList = (startIndex < endIndex) +// ? filtered.subList(startIndex, endIndex) +// : Collections.emptyList(); +// +// List content = pageList.stream() +// .map(EventListResponseDTO::of) +// .toList(); +// +// return PagedEventListResponseDTO.builder() +// .currentPage(page) +// .totalPages(totalPages) +// .totalElements(totalElements) +// .size(size) +// .content(content) +// .build(); +// +// } @Transactional public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDTO requestDTO) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/config/scheduler/MajorScheduler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/config/scheduler/MajorScheduler.java new file mode 100644 index 0000000..fd28d87 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/config/scheduler/MajorScheduler.java @@ -0,0 +1,25 @@ +package com.ComNCheck.ComNCheck.domain.majorNotice.config.scheduler; + +import com.ComNCheck.ComNCheck.domain.majorNotice.service.MajorNoticeService; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +@Configuration +@EnableScheduling +@RequiredArgsConstructor +public class MajorScheduler { + private final MajorNoticeService majorNoticeService; + + @Scheduled(cron = "0 0 * * * *") + public void syncNoticesPeriodically() { + majorNoticeService.syncMajorNotices(); + } + + @PostConstruct + public void initLoad() { + majorNoticeService.syncMajorNotices(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java new file mode 100644 index 0000000..f0ad86c --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java @@ -0,0 +1,35 @@ +package com.ComNCheck.ComNCheck.domain.majorNotice.controller; + +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.PageMajorNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.majorNotice.service.MajorNoticeService; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RequestMapping("/api/v1/major/notices") +@RestController +public class MajorNoticeController { + + private final MajorNoticeService majorNoticeService; + + @GetMapping + public ResponseEntity> getAllMajorNotices() { + List lists = majorNoticeService.getAllMajorNotices(); + return ResponseEntity.ok(lists); + } + + @GetMapping("/pages") + public ResponseEntity getMajorNoticesPage( + @RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "10") int size + ) { + PageMajorNoticeResponseDTO pageResponse = majorNoticeService.getMajorNoticesPage(page, size); + return ResponseEntity.ok(pageResponse); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/FastAPIMajorNoticesResponseListDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/FastAPIMajorNoticesResponseListDTO.java new file mode 100644 index 0000000..6440c46 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/FastAPIMajorNoticesResponseListDTO.java @@ -0,0 +1,11 @@ +package com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response; + +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class FastAPIMajorNoticesResponseListDTO { + private List notices; +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java new file mode 100644 index 0000000..ccd9d47 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java @@ -0,0 +1,27 @@ +package com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response; + + +import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.time.LocalDate; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class MajorNoticeResponseDTO { + private int noticeId; + private String title; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd") + private LocalDate date; + private String link; + + public static MajorNoticeResponseDTO of(MajorNotice majorNotice) { + return MajorNoticeResponseDTO.builder() + .noticeId(majorNotice.getNoticeId()) + .title(majorNotice.getTitle()) + .date(majorNotice.getDate()) + .link(majorNotice.getLink()) + .build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/PageMajorNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/PageMajorNoticeResponseDTO.java new file mode 100644 index 0000000..0635760 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/PageMajorNoticeResponseDTO.java @@ -0,0 +1,16 @@ +package com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response; + + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class PageMajorNoticeResponseDTO { + private int currentPage; + private int totalPages; + private long totalElements; + private int size; + private List content; +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java new file mode 100644 index 0000000..c1c91d2 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java @@ -0,0 +1,52 @@ +package com.ComNCheck.ComNCheck.domain.majorNotice.model.entity; + +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.time.LocalDate; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + + +@Getter +@Table(name = "notices") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class MajorNotice { + + @Id + @Column(name = "major_notice_id") + private int noticeId; +\ + @Column + private String title; + + @Column + private LocalDate date; + + @Column + private String link; + + public MajorNotice(MajorNoticeResponseDTO dto) { + this.noticeId = dto.getNoticeId(); + this.title = dto.getTitle(); + this.date = dto.getDate(); + this.link = dto.getLink(); + } + + public boolean equalsDTO(MajorNoticeResponseDTO dto) { + return this.noticeId== dto.getNoticeId() && + this.title.equals(dto.getTitle()) && + this.date.isEqual(dto.getDate()) && + this.link.equals(dto.getLink()); + } + public void updateFromDto(MajorNoticeResponseDTO dto) { + this.title = dto.getTitle(); + this.date = dto.getDate(); + this.link = dto.getLink(); + } + +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java new file mode 100644 index 0000000..7be0912 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java @@ -0,0 +1,10 @@ +package com.ComNCheck.ComNCheck.domain.majorNotice.repository; + +import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MajorNoticeRepository extends JpaRepository { + Optional findByNoticeId(int noticeId); + +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java new file mode 100644 index 0000000..4b12f2d --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java @@ -0,0 +1,94 @@ +package com.ComNCheck.ComNCheck.domain.majorNotice.service; + +import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.FastAPIMajorNoticesResponseListDTO; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.PageMajorNoticeResponseDTO; +import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice; +import com.ComNCheck.ComNCheck.domain.majorNotice.repository.MajorNoticeRepository; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MajorNoticeService { + private final FastApiClient fastApiClient; + private final MajorNoticeRepository majorNoticeRepository; + + @Transactional + public void syncMajorNotices() { + FastAPIMajorNoticesResponseListDTO response = fastApiClient.fetchMajorNotices(); + + List changeMajorNotices = new ArrayList<>(); + + if(response != null && response.getNotices() != null) { + for(MajorNoticeResponseDTO dto : response.getNotices()) { + Optional findNotice = majorNoticeRepository.findByNoticeId(dto.getNoticeId()); + if(findNotice.isEmpty()) { + MajorNotice newMajorNotice = new MajorNotice(dto); + majorNoticeRepository.save(newMajorNotice); + changeMajorNotices.add(newMajorNotice); + } else { + MajorNotice existingMajorNotice = findNotice.get(); + if(!existingMajorNotice.equalsDTO(dto)) { + existingMajorNotice.updateFromDto(dto); + majorNoticeRepository.save(existingMajorNotice); + changeMajorNotices.add(existingMajorNotice); + } + } + } + } + if(!changeMajorNotices.isEmpty()) { + // fcm 기능 구현 + } + } + + public List getAllMajorNotices() { + return majorNoticeRepository.findAll() + .stream() + .map(MajorNoticeResponseDTO::of) + .toList(); + } + + public PageMajorNoticeResponseDTO getMajorNoticesPage(int page, int size) { + List allNotices = majorNoticeRepository.findAll(); + allNotices.sort(Comparator.comparing(MajorNotice::getDate).reversed()); + + long totalElements = allNotices.size(); + int totalPages = (int) Math.ceil((double) totalElements / size); + + if (page < 1) { + page = 1; + } else if (page > totalPages && totalPages > 0) { + page = totalPages; + } + + int zeroBasedPage = page - 1; + int startIndex = zeroBasedPage * size; + int endIndex = Math.min(startIndex + size, (int) totalElements); + + List pageList = (startIndex < endIndex) + ? allNotices.subList(startIndex, endIndex) + : Collections.emptyList(); + + List content = pageList.stream() + .map(MajorNoticeResponseDTO::of) + .collect(Collectors.toList()); + + return PageMajorNoticeResponseDTO.builder() + .currentPage(page) + .totalPages(totalPages) + .totalElements(totalElements) + .size(size) + .content(content) + .build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java index 6a89151..0344ebb 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java @@ -1,6 +1,7 @@ package com.ComNCheck.ComNCheck.domain.member.controller; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberDTO; +import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberInformationResponseDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO; import com.ComNCheck.ComNCheck.domain.member.service.MemberService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; @@ -22,10 +23,10 @@ public class MemberController { private final MemberService memberService; @PostMapping("/{memberId}/student/number") - public ResponseEntity registerStudentNumber( + public ResponseEntity registerStudentNumber( @PathVariable Long memberId, @RequestParam("studentCardImage") MultipartFile studentCardImage) { - MemberDTO responseDTO = memberService.registerStudentNumber(memberId, studentCardImage); + MemberInformationResponseDTO responseDTO = memberService.registerStudentNumber(memberId, studentCardImage); return ResponseEntity.ok(responseDTO); } @@ -36,10 +37,10 @@ public ResponseEntity getPresidentCouncilList() { } @GetMapping - public ResponseEntity getMemberInformation(Authentication authentication) { + public ResponseEntity getMemberInformation(Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); - MemberDTO responseDTO = memberService.getMemberInformation(memberId); + MemberInformationResponseDTO responseDTO = memberService.getMemberInformation(memberId); return ResponseEntity.ok(responseDTO); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java index 6a1d602..828a432 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java @@ -9,7 +9,6 @@ @Getter @Setter -@Builder @AllArgsConstructor public class MemberDTO { private Long memberId; @@ -22,14 +21,4 @@ public class MemberDTO { public MemberDTO() { } - public static MemberDTO of(Member member) { - return MemberDTO.builder() - .memberId(member.getMemberId()) - .email(member.getEmail()) - .name(member.getName()) - .major(member.getMajor()) - .studentNumber(member.getStudentNumber()) - .role(member.getRole()) - .build(); - } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java new file mode 100644 index 0000000..52fc597 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java @@ -0,0 +1,27 @@ +package com.ComNCheck.ComNCheck.domain.member.model.dto.response; + +import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; + +import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; +import lombok.Builder; + +@Builder +public class MemberInformationResponseDTO { + + private Long memberId; + private String name; + private String major; + private int studentNumber; + private Role role; + private boolean checkStudentCard; + public static MemberInformationResponseDTO of(Member member) { + return MemberInformationResponseDTO.builder() + .memberId(member.getMemberId()) + .name(member.getName()) + .major(member.getMajor()) + .studentNumber(member.getStudentNumber()) + .role(member.getRole()) + .checkStudentCard(member.isCheckStudentCard()) + .build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java index 2184e3b..9fb1d5b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java @@ -27,7 +27,7 @@ public class Member { @Column(name = "major", nullable = false) private String major; - @Column(name = "studnet_number", nullable = false) + @Column(name = "student_number") private int studentNumber; @Column(name = "member_role", nullable = false) @@ -37,6 +37,9 @@ public class Member { @Column(name = "position") private String position; + @Column(name = "is_check_student_card", nullable = false) + private boolean checkStudentCard; + @Builder public Member(Long memberId, String email, String name, String major, int studentNumber, Role role) { this.memberId = memberId; @@ -46,6 +49,7 @@ public Member(Long memberId, String email, String name, String major, int studen this.studentNumber = studentNumber; this.position = null; this.role = role; + this.checkStudentCard = false; } /* @@ -61,5 +65,8 @@ public void updatePosition(String requestPosition) { public void updateRole(Role newRole) { this.role = newRole; } + public void changeIsCheckStudentCard() { + checkStudentCard = true; + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index 9bac162..b23c953 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -49,7 +49,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic .name(name) .major(major) .role(Role.ROLE_STUDENT) - .studentNumber(12345678)// 난수 변수 값 만드는 메서드 만들어야함 + .studentNumber(null) .build(); memberRepository.save(newMember); return newMember; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java index da8b9b9..c4f3736 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java @@ -6,6 +6,7 @@ import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO.ExtractedText; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberDTO; +import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberInformationResponseDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentDTO; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; @@ -26,7 +27,7 @@ public class MemberService { private final FastApiClient fastApiClient; @Transactional - public MemberDTO registerStudentNumber(Long id, MultipartFile studentCardImage) { + public MemberInformationResponseDTO registerStudentNumber(Long id, MultipartFile studentCardImage) { Member member = memberRepository.findByMemberId(id) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); FastApiStudentCardDTO fastApiResponse = fastApiClient.sendImage(studentCardImage); @@ -41,9 +42,10 @@ public MemberDTO registerStudentNumber(Long id, MultipartFile studentCardImage) throw new ValidationException("이름 또는 전공이 일치하지 않습니다."); } member.setStudentNumber(studentNumber); + member.changeIsCheckStudentCard(); Member savedMember = memberRepository.save(member); - return MemberDTO.of(savedMember); + return MemberInformationResponseDTO.of(savedMember); } public PresidentCouncilResponseDTO getPresidentAndCouncils() { @@ -77,10 +79,10 @@ private void validateFastApiResponse(ExtractedText extractedText) { } } - public MemberDTO getMemberInformation(Long memberId) { + public MemberInformationResponseDTO getMemberInformation(Long memberId) { Member member = memberRepository.findByMemberId(memberId) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); - return MemberDTO.of(member); + return MemberInformationResponseDTO.of(member); } } From 065e93fa660ff9bf8810faedcc01fee71a7bb0ed Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 2 Feb 2025 01:41:27 +0900 Subject: [PATCH 02/67] =?UTF-8?q?Feat:=20=EB=93=B1=EA=B8=89=EB=B3=84=20API?= =?UTF-8?q?=20=EC=A0=91=EA=B7=BC=20=EA=B6=8C=ED=95=9C=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/config/MethodSecurityConfig.java | 10 ++++++++ .../global/config/RoleHierarchyConfig.java | 25 +++++++++++++++++++ .../controller/MajorEventController.java | 7 +++++- .../controller/AnswerController.java | 5 +++- .../controller/QuestionController.java | 1 + .../domain/member/model/entity/Role.java | 1 + .../controller/RoleChangeController.java | 8 +++++- 7 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/config/MethodSecurityConfig.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/config/RoleHierarchyConfig.java diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/MethodSecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/MethodSecurityConfig.java new file mode 100644 index 0000000..b9b52ef --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/MethodSecurityConfig.java @@ -0,0 +1,10 @@ +package com.ComNCheck.ComNCheck.domain.global.config; + + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; + +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class MethodSecurityConfig { +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/RoleHierarchyConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/RoleHierarchyConfig.java new file mode 100644 index 0000000..e732a29 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/RoleHierarchyConfig.java @@ -0,0 +1,25 @@ +package com.ComNCheck.ComNCheck.domain.global.config; + + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; + +@Configuration +public class RoleHierarchyConfig { + + + @Bean + public RoleHierarchy roleHierarchy() { + RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); + String hierarchy = "ROLE_ADMIN > ROLE_MAJOR_PRESIDENT \n" + + "ROLE_MAJOR_PRESIDENT > ROLE_STUDENT_COUNCIL \n" + + "ROLE_STUDENT_COUNCIL > ROLE_STUDENT \n" + + "ROLE_STUDENT > ROLE_GRADUATE_STUDENT"; + roleHierarchy.setHierarchy(hierarchy); + return roleHierarchy; + } + + +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java index 5c31fca..787dea0 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java @@ -10,6 +10,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -26,7 +27,7 @@ public class MajorEventController { private final MajorEventService majorEventService; - + @PreAuthorize("hasRole('STUDENT_COUNCIL')") @PostMapping public ResponseEntity createMajorEvent(@ModelAttribute EventCreateRequestDTO requestDTO, Authentication authentication) { @@ -36,12 +37,14 @@ public ResponseEntity createMajorEvent(@ModelAttribute EventCr return ResponseEntity.ok(responseDTO); } + @GetMapping("/{majorEventId}") public ResponseEntity getMajorEvent(@PathVariable Long majorEventId) { EventResponseDTO responseDTO = majorEventService.getMajorEvent(majorEventId); return ResponseEntity.ok(responseDTO); } + @GetMapping public ResponseEntity> getAllMajorEventsNotPassed() { List allMajorEventsNotPassed = majorEventService.getAllMajorEventsNotPassed(); @@ -57,6 +60,7 @@ public ResponseEntity> getAllMajorEventsNotPassed() { // return ResponseEntity.ok(responseDTO); // } + @PreAuthorize("hasRole('STUDENT_COUNCIL')") @PutMapping("/{majorEventId}") public ResponseEntity updateMajorEvent( @PathVariable Long majorEventId, @@ -66,6 +70,7 @@ public ResponseEntity updateMajorEvent( return ResponseEntity.ok(updateDTO); } + @PreAuthorize("hasRole('STUDENT_COUNCIL')") @DeleteMapping("/{majorEventId}") public ResponseEntity deleteMajorEvent(@PathVariable Long majorEventId) { majorEventService.deleteMajorEvent(majorEventId); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java index 3314515..c1c9f7a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java @@ -6,6 +6,7 @@ import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.*; @@ -15,6 +16,7 @@ public class AnswerController { private final AnswerService answerService; + @PreAuthorize("hasRole('STUDENT_COUNCIL')") @PostMapping public ResponseEntity createOrUpdateAnswer( @RequestBody AnswerRequestDTO requestDTO, @@ -27,6 +29,7 @@ public ResponseEntity createOrUpdateAnswer( AnswerResponseDTO responseDTO = answerService.createOrUpdateAnswer(requestDTO); return ResponseEntity.ok(responseDTO); } + @PreAuthorize("hasRole('STUDENT_COUNCIL')") @PutMapping("/{answerId}") public ResponseEntity updateAnswer( @PathVariable Long answerId, @@ -36,7 +39,7 @@ public ResponseEntity updateAnswer( AnswerResponseDTO responseDTO = answerService.updateAnswer(answerId, content); return ResponseEntity.ok(responseDTO); } - + @PreAuthorize("hasRole('STUDENT_COUNCIL')") @DeleteMapping("/{answerId}") public ResponseEntity deleteAnswer( @PathVariable Long answerId, diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java index 3d7c761..0291ffa 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java @@ -27,6 +27,7 @@ public class QuestionController { private final QuestionService questionService; + @PostMapping public ResponseEntity createQuestion(@RequestBody QuestionRequestDTO requestDTO) { QuestionResponseDTO responseDTO = questionService.createQuestion(requestDTO); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Role.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Role.java index 938f7d6..b75fc9f 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Role.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Role.java @@ -12,6 +12,7 @@ public enum Role { ROLE_STUDENT_COUNCIL("ROLE_STUDENT_COUNCIL"), ROLE_STUDENT("ROLE_STUDENT"), ROLE_GRADUATE_STUDENT("ROLE_GRADUATE_STUDENT"); + private final String value; Role(String value) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java index 3ced13f..c63cb56 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java @@ -8,6 +8,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -34,30 +35,34 @@ public ResponseEntity createRoleChangeRequest( return ResponseEntity.created(location).body(createDTO); } + @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @GetMapping public ResponseEntity> getAllRequest() { List response = roleChangeRequestService.getAllRequests(); return ResponseEntity.ok(response); } + @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @GetMapping("/{requestId}") public ResponseEntity getRequestDetail(@PathVariable Long requestId) { RoleChangeResponseDTO responseDTO = roleChangeRequestService.getRequestDetail(requestId); return ResponseEntity.ok(responseDTO); } + @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @PostMapping("{requestId}/approve") public ResponseEntity approveRequest(@PathVariable Long requestId) { roleChangeRequestService.approveRequest(requestId); return ResponseEntity.ok("승인완료"); } - + @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @GetMapping("/approved") public ResponseEntity> getApprovedRequests() { List approvedList = roleChangeRequestService.getApproveRequests(); return ResponseEntity.ok(approvedList); } + @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @PutMapping("/{requestId}/change-role") public ResponseEntity changeMemberRole( @PathVariable Long requestId, @RequestBody RoleChangeRequestDTO requestDTO @@ -66,6 +71,7 @@ public ResponseEntity changeMemberRole( return ResponseEntity.ok("등급 재변경 완료"); } + @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @DeleteMapping("/{requestId}") public ResponseEntity deleteRequest(@PathVariable Long requestId) { roleChangeRequestService.deleteRequest(requestId); From caf67316f55d1cdd1411cfc1c3011c14bad7c6f6 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 2 Feb 2025 02:08:48 +0900 Subject: [PATCH 03/67] =?UTF-8?q?Fix:=20=EB=B9=88=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=95=88=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/scheduler/EmploymentNoticeScheduler.java | 3 ++- .../model/dto/response/EmploymentNoticeResponseDTO.java | 2 +- .../repository/EmploymentNoticeRepository.java | 3 +-- .../employmentNotice/service/EmploymentNoticeService.java | 6 +++--- .../domain/majorNotice/model/entity/MajorNotice.java | 2 +- .../domain/majorNotice/service/MajorNoticeService.java | 1 + .../domain/member/service/CustomOAuthMemberService.java | 2 +- .../domain/security/handler/CustomSuccessHandler.java | 4 ++-- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java index e71449a..afd7b41 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java @@ -12,7 +12,8 @@ @EnableScheduling @RequiredArgsConstructor public class EmploymentNoticeScheduler { - private EmploymentNoticeService employmentNoticeService; + + private final EmploymentNoticeService employmentNoticeService; @Scheduled(cron = "0 0 * * * *") public void syncEmploymentNoticePeriodically() { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java index e240f77..8849bd7 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java @@ -12,7 +12,7 @@ public class EmploymentNoticeResponseDTO { private int employmentNoticeId; private String title; - @JsonFormat(shape = Shape.STRING, pattern = "yyyy.mm.dd") + @JsonFormat(shape = Shape.STRING, pattern = "yyyy.MM.dd") private LocalDate date; private String link; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java index 5890839..2fd87b2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java @@ -5,6 +5,5 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface EmploymentNoticeRepository extends JpaRepository { - - Optional findEmploymentNoticeId(int employmentNoticeId); + Optional findByEmploymentNoticeId(int employmentNoticeId); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java index 318b528..269d116 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java @@ -24,8 +24,8 @@ @Service public class EmploymentNoticeService { - private EmploymentNoticeRepository employmentNoticeRepository; - private FastApiClient fastApiClient; + private final EmploymentNoticeRepository employmentNoticeRepository; + private final FastApiClient fastApiClient; @Transactional public void syncEmploymentNotices() { @@ -36,7 +36,7 @@ public void syncEmploymentNotices() { if(response != null && response.getNotices() != null) { for(EmploymentNoticeResponseDTO dto : response.getNotices()) { Optional findEmployment = employmentNoticeRepository - .findEmploymentNoticeId(dto.getEmploymentNoticeId()); + .findByEmploymentNoticeId(dto.getEmploymentNoticeId()); if(findEmployment.isEmpty()) { EmploymentNotice newEmploymentNotice = new EmploymentNotice(dto); employmentNoticeRepository.save(newEmploymentNotice); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java index c1c91d2..651502e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java @@ -20,7 +20,7 @@ public class MajorNotice { @Id @Column(name = "major_notice_id") private int noticeId; -\ + @Column private String title; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java index 4b12f2d..44258d8 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java @@ -20,6 +20,7 @@ @Transactional(readOnly = true) @Service public class MajorNoticeService { + private final FastApiClient fastApiClient; private final MajorNoticeRepository majorNoticeRepository; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index b23c953..1062db5 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -49,7 +49,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic .name(name) .major(major) .role(Role.ROLE_STUDENT) - .studentNumber(null) + .studentNumber(123456789) .build(); memberRepository.save(newMember); return newMember; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index c000911..4ba8987 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -43,9 +43,9 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo private Cookie createCookie(String key, String value) { Cookie cookie = new Cookie(key, value); cookie.setMaxAge(60*60*60); - //cookie.setSecure(true); + cookie.setSecure(true); cookie.setPath("/"); - //cookie.setHttpOnly(true); + cookie.setHttpOnly(true); return cookie; } From ec72c25ecaf91bc885a82b8322dcba5b6d0cfa02 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 2 Feb 2025 03:42:34 +0900 Subject: [PATCH 04/67] =?UTF-8?q?Feat:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EC=BF=A0?= =?UTF-8?q?=ED=82=A4=20=EB=A7=8C=EB=A3=8C=20=EA=B0=92=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=EC=9D=84=20=ED=86=B5=ED=95=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/EmploymentNoticeService.java | 3 --- .../domain/member/controller/MemberController.java | 11 +++++++++++ .../domain/member/service/MemberService.java | 11 +++++++++++ .../domain/security/handler/CustomSuccessHandler.java | 2 +- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java index 269d116..1ba206a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java @@ -6,9 +6,6 @@ import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice; import com.ComNCheck.ComNCheck.domain.employmentNotice.repository.EmploymentNoticeRepository; import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient; -import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; -import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.PageMajorNoticeResponseDTO; -import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java index 0344ebb..6fb43b2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java @@ -5,9 +5,11 @@ import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO; import com.ComNCheck.ComNCheck.domain.member.service.MemberService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; +import org.springframework.security.core.parameters.P; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -44,4 +46,13 @@ public ResponseEntity getMemberInformation(Authent return ResponseEntity.ok(responseDTO); } + @PostMapping("/logout") + public ResponseEntity logout(HttpServletResponse response) { + memberService.logout(response); + return ResponseEntity.ok("로그아웃 성공"); + } + + + + } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java index c4f3736..43e921c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java @@ -12,6 +12,8 @@ import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletResponse; import java.util.List; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @@ -85,4 +87,13 @@ public MemberInformationResponseDTO getMemberInformation(Long memberId) { return MemberInformationResponseDTO.of(member); } + + public void logout(HttpServletResponse response) { + Cookie cookie = new Cookie("Authorization", null); + cookie.setPath("/"); + cookie.setHttpOnly(true); + cookie.setSecure(true); + cookie.setMaxAge(0); + response.addCookie(cookie); + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index 4ba8987..54bef14 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -35,7 +35,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo String token = jwtUtil.createJwt(userId, username, role, 60*60*60L); - response.addCookie(createCookie("Authorization", token)); + response.addCookie(createCookie("Autho rization", token)); response.sendRedirect("http://localhost:3000/signup?id=" + userId); } From 30850d4b0e2f92764099e86bc049177088e010a4 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 2 Feb 2025 17:31:51 +0900 Subject: [PATCH 05/67] =?UTF-8?q?Fix:=20fastAPI=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EA=B0=92=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=95=88=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=EA=B1=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/entity/EmploymentNotice.java | 26 ++++++++++++------- .../service/EmploymentNoticeService.java | 6 ++--- .../dto/response/MajorNoticeResponseDTO.java | 2 ++ .../majorNotice/model/entity/MajorNotice.java | 23 ++++++++++++---- .../service/MajorNoticeService.java | 4 +-- .../member/controller/MemberController.java | 2 -- .../MemberInformationResponseDTO.java | 2 ++ .../domain/member/model/entity/Member.java | 3 ++- .../service/CustomOAuthMemberService.java | 16 ++++++------ .../domain/member/service/MemberService.java | 4 +-- .../security/config/SecurityConfig.java | 3 +-- .../domain/security/filter/JWTFilter.java | 2 +- .../handler/CustomSuccessHandler.java | 10 +++---- .../domain/security/util/JWTUtil.java | 2 +- 14 files changed, 62 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java index e395768..6a71558 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java @@ -37,15 +37,21 @@ public EmploymentNotice(EmploymentNoticeResponseDTO dto) { this.link = dto.getLink(); } - public boolean equalsDTO(EmploymentNoticeResponseDTO dto) { - return this.employmentNoticeId == dto.getEmploymentNoticeId() && - this.title.equals(dto.getTitle()) && - this.date.isEqual(dto.getDate()) && - this.link.equals(dto.getLink()); - } - public void updateFromDto(EmploymentNoticeResponseDTO dto) { - this.title = dto.getTitle(); - this.date = dto.getDate(); - this.link = dto.getLink(); + public boolean updateFromDto(EmploymentNoticeResponseDTO dto) { + boolean changed = false; + + if (!this.title.equals(dto.getTitle())) { + this.title = dto.getTitle(); + changed = true; + } + if (!this.date.isEqual(dto.getDate())) { + this.date = dto.getDate(); + changed = true; + } + if (!this.link.equals(dto.getLink())) { + this.link = dto.getLink(); + changed = true; + } + return changed; } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java index 1ba206a..5f44b80 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java @@ -40,19 +40,17 @@ public void syncEmploymentNotices() { changeEmploymentNotices.add(newEmploymentNotice); } else { EmploymentNotice existEmploymentNotice = findEmployment.get(); - if(!existEmploymentNotice.equalsDTO(dto)) { - existEmploymentNotice.updateFromDto(dto); + if (existEmploymentNotice.updateFromDto(dto)) { employmentNoticeRepository.save(existEmploymentNotice); changeEmploymentNotices.add(existEmploymentNotice); } } } - } if (!changeEmploymentNotices.isEmpty()) { // fcm 기능 구현 + System.out.println("알림 전송"); } - } public List getAllEmploymentNotices() { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java index ccd9d47..deecca7 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java @@ -3,6 +3,7 @@ import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; import java.time.LocalDate; import lombok.Builder; import lombok.Getter; @@ -10,6 +11,7 @@ @Getter @Builder public class MajorNoticeResponseDTO { + @JsonProperty("notice_id") private int noticeId; private String title; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd") diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java index 651502e..ca6a18a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java @@ -1,5 +1,6 @@ package com.ComNCheck.ComNCheck.domain.majorNotice.model.entity; +import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -12,7 +13,7 @@ @Getter -@Table(name = "notices") +@Table(name = "major_notices") @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity public class MajorNotice { @@ -43,10 +44,22 @@ public boolean equalsDTO(MajorNoticeResponseDTO dto) { this.date.isEqual(dto.getDate()) && this.link.equals(dto.getLink()); } - public void updateFromDto(MajorNoticeResponseDTO dto) { - this.title = dto.getTitle(); - this.date = dto.getDate(); - this.link = dto.getLink(); + public boolean updateFromDto(MajorNoticeResponseDTO dto) { + boolean changed = false; + + if (!this.title.equals(dto.getTitle())) { + this.title = dto.getTitle(); + changed = true; + } + if (!this.date.isEqual(dto.getDate())) { + this.date = dto.getDate(); + changed = true; + } + if (!this.link.equals(dto.getLink())) { + this.link = dto.getLink(); + changed = true; + } + return changed; } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java index 44258d8..b2c561b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java @@ -39,8 +39,7 @@ public void syncMajorNotices() { changeMajorNotices.add(newMajorNotice); } else { MajorNotice existingMajorNotice = findNotice.get(); - if(!existingMajorNotice.equalsDTO(dto)) { - existingMajorNotice.updateFromDto(dto); + if (existingMajorNotice.updateFromDto(dto)) { majorNoticeRepository.save(existingMajorNotice); changeMajorNotices.add(existingMajorNotice); } @@ -49,6 +48,7 @@ public void syncMajorNotices() { } if(!changeMajorNotices.isEmpty()) { // fcm 기능 구현 + System.out.println("알림 전송"); } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java index 6fb43b2..486185f 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java @@ -1,6 +1,5 @@ package com.ComNCheck.ComNCheck.domain.member.controller; -import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberInformationResponseDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO; import com.ComNCheck.ComNCheck.domain.member.service.MemberService; @@ -9,7 +8,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; -import org.springframework.security.core.parameters.P; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java index 52fc597..230efae 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java @@ -4,8 +4,10 @@ import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import lombok.Builder; +import lombok.Getter; @Builder +@Getter public class MemberInformationResponseDTO { private Long memberId; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java index 9fb1d5b..3622fc0 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java @@ -24,7 +24,8 @@ public class Member { @Column(name = "name", nullable = false) private String name; - @Column(name = "major", nullable = false) + // 실제 배포에서는 nullable 설정 false 해야함 + @Column(name = "major", nullable = true) private String major; @Column(name = "student_number") diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index 1062db5..6cfbbba 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -33,14 +33,14 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic //String sub = oAuth2User.getAttribute("sub"); 이메일 변경 여부 따지고 변경될경우 findByEmail 대신 findBySub 사용 String hd = oAuth2User.getAttribute("hd"); - if (!"hufs.ac.kr".equals(hd)) { - OAuth2Error oauth2Error = new OAuth2Error( - "invalid_hosted_domain", - "허용되지 않은 호스팅 도메인입니다.", - null - ); - throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); - } +// if (!"hufs.ac.kr".equals(hd)) { // 테스트떄는 주석처리 -> 이후 실제 서비스에서는 주석 헤제 +// OAuth2Error oauth2Error = new OAuth2Error( +// "invalid_hosted_domain", +// "허용되지 않은 호스팅 도메인입니다.", +// null +// ); +// throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); +// } // 이메일 변경 가능시 sub 변 Member member = memberRepository.findByEmail(email).orElseGet(() -> { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java index 43e921c..4aff515 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java @@ -89,10 +89,10 @@ public MemberInformationResponseDTO getMemberInformation(Long memberId) { } public void logout(HttpServletResponse response) { - Cookie cookie = new Cookie("Authorization", null); + Cookie cookie = new Cookie("JWT", null); cookie.setPath("/"); cookie.setHttpOnly(true); - cookie.setSecure(true); + //cookie.setSecure(true); cookie.setMaxAge(0); response.addCookie(cookie); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index d8ceb76..66a313e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -37,7 +37,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setMaxAge(3600L); - configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "Authorization")); + configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "JWT")); return configuration; } })) @@ -72,7 +72,6 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .userService(customOAuth2MemberService)) .successHandler(customSuccessHandler) ); - System.out.println("시큐리티config"); // H2 Console 관련 헤더 설정 -> 디비 변경 시 제거 http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin())); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java index 10286a6..a6b1d7e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java @@ -61,7 +61,7 @@ protected void doFilterInternal(HttpServletRequest request, Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { - if ("Authorization".equals(cookie.getName())) { // 쿠키 이름 확인 + if ("JWT".equals(cookie.getName())) { // 쿠키 이름 확인 token = cookie.getValue(); logger.debug("Found Authorization cookie: " + token); break; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index 54bef14..fe015b7 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -26,24 +26,24 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo Authentication authentication) throws IOException, ServletException { CustomOAuth2Member customMemberDetails = (CustomOAuth2Member) authentication.getPrincipal(); - Long userId = customMemberDetails.getMemberDTO().getMemberId(); + Long memberId = customMemberDetails.getMemberDTO().getMemberId(); String username = customMemberDetails.getName(); Collection authorities = authentication.getAuthorities(); Iterator iterator = authorities.iterator(); GrantedAuthority auth = iterator.next(); String role = auth.getAuthority().toString(); - String token = jwtUtil.createJwt(userId, username, role, 60*60*60L); + String token = jwtUtil.createJwt(memberId, username, role, 60 * 60 * 1000L); - response.addCookie(createCookie("Autho rization", token)); - response.sendRedirect("http://localhost:3000/signup?id=" + userId); + response.addCookie(createCookie("JWT", token)); + response.sendRedirect("http://localhost:3000/signup?id=" + memberId); } private Cookie createCookie(String key, String value) { Cookie cookie = new Cookie(key, value); cookie.setMaxAge(60*60*60); - cookie.setSecure(true); + //cookie.setSecure(true); // https에서만 작동 cookie.setPath("/"); cookie.setHttpOnly(true); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/util/JWTUtil.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/util/JWTUtil.java index 37ab0d4..d877de0 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/util/JWTUtil.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/util/JWTUtil.java @@ -46,7 +46,7 @@ public String getUsername(String token) { .build() .parseSignedClaims(token) .getPayload() - .get("username", String.class); + .get("name", String.class); } public Role getRole(String token) { From 760168f5d1c5a4bb72883bf248ba8f29b0e4114c Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 2 Feb 2025 19:47:06 +0900 Subject: [PATCH 06/67] =?UTF-8?q?Refactor=20=ED=95=99=EC=83=9D=ED=9A=8C=20?= =?UTF-8?q?=EB=93=B1=EA=B8=89=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=95=99?= =?UTF-8?q?=EC=83=9D=EC=A6=9D=20=EC=9D=B8=EC=A6=9D=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DeveloperQuestionController.java | 12 ++++++++---- .../dto/request/DeveloperQuestionRequestDTO.java | 1 - .../service/DeveloperQuestionService.java | 4 ++-- .../dto/response/EmploymentNoticeResponseDTO.java | 2 ++ .../controller/QuestionController.java | 14 +++++++------- .../domain/member/controller/MemberController.java | 8 +++++--- .../controller/RoleChangeController.java | 9 +++++++-- .../model/dto/request/RoleChangeRequestDTO.java | 1 - .../service/RoleChangeRequestService.java | 4 ++-- src/main/resources/application.yaml | 2 +- 10 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java index ebbba67..785ae57 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java @@ -19,7 +19,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -@RequestMapping("api/v1/developer/question") +@RequestMapping("api/v1/developer/questions") @RequiredArgsConstructor @RestController public class DeveloperQuestionController { @@ -28,10 +28,14 @@ public class DeveloperQuestionController { @PostMapping public ResponseEntity createDeveloperQuestion( - @RequestBody DeveloperQuestionRequestDTO requestDTO + @RequestBody DeveloperQuestionRequestDTO requestDTO, + Authentication authentication ) { - DeveloperQuestionResponseDTO createdDTO = developerQuestionService.createDeveloperQuestion(requestDTO); - URI location = URI.create("api/v1/developer/question/" + createdDTO.getId()); + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + DeveloperQuestionResponseDTO createdDTO = developerQuestionService + .createDeveloperQuestion(memberId, requestDTO); + URI location = URI.create("api/v1/developer/questions/" + createdDTO.getId()); return ResponseEntity.created(location).body(createdDTO); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/dto/request/DeveloperQuestionRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/dto/request/DeveloperQuestionRequestDTO.java index 980b2f3..1aea267 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/dto/request/DeveloperQuestionRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/dto/request/DeveloperQuestionRequestDTO.java @@ -8,5 +8,4 @@ @Setter public class DeveloperQuestionRequestDTO { private String content; - private Long writerId; } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java index 81341d2..a0c4a48 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java @@ -23,8 +23,8 @@ public class DeveloperQuestionService { private final DeveloperQuestionRepository developerQuestionRepository; @Transactional - public DeveloperQuestionResponseDTO createDeveloperQuestion(DeveloperQuestionRequestDTO requestDTO) { - Member writer = memberRepository.findById(requestDTO.getWriterId()) + public DeveloperQuestionResponseDTO createDeveloperQuestion(Long memberId, DeveloperQuestionRequestDTO requestDTO) { + Member writer = memberRepository.findById(memberId) .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다.")); DeveloperQuestion developerQuestion = DeveloperQuestion.builder() diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java index 8849bd7..60d6da8 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java @@ -3,6 +3,7 @@ import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat.Shape; +import com.fasterxml.jackson.annotation.JsonProperty; import java.time.LocalDate; import lombok.Builder; import lombok.Getter; @@ -10,6 +11,7 @@ @Getter @Builder public class EmploymentNoticeResponseDTO { + @JsonProperty("notice_id") private int employmentNoticeId; private String title; @JsonFormat(shape = Shape.STRING, pattern = "yyyy.MM.dd") diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java index 0291ffa..1decfbc 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java @@ -33,15 +33,15 @@ public ResponseEntity createQuestion(@RequestBody QuestionR QuestionResponseDTO responseDTO = questionService.createQuestion(requestDTO); URI location = ServletUriComponentsBuilder.fromCurrentRequest() - .path("/{id}") + .path("/{majorQuestionId}") .buildAndExpand(responseDTO.getId()) .toUri(); return ResponseEntity.created(location).body(responseDTO); } - @GetMapping("/{id}") - public ResponseEntity getQuestion(@PathVariable Long id) { - QuestionResponseDTO responseDTO = questionService.getQuestion(id); + @GetMapping("/{majorQuestionId}") + public ResponseEntity getQuestion(@PathVariable Long majorQuestionId) { + QuestionResponseDTO responseDTO = questionService.getQuestion(majorQuestionId); return ResponseEntity.ok(responseDTO); } @@ -59,13 +59,13 @@ public ResponseEntity> getMyQuestions(Authentication a return ResponseEntity.ok(myQuestions); } - @PutMapping("/{id}") - public ResponseEntity updateQuestion(@PathVariable Long id, + @PutMapping("/{majorQuestionId}") + public ResponseEntity updateQuestion(@PathVariable Long majorQuestionId, @RequestBody QuestionRequestDTO requestDTO, Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); - QuestionResponseDTO updateDTO = questionService.updateQuestion(id, requestDTO, memberId); + QuestionResponseDTO updateDTO = questionService.updateQuestion(majorQuestionId, requestDTO, memberId); return ResponseEntity.ok(updateDTO); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java index 486185f..683cde9 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java @@ -22,10 +22,12 @@ public class MemberController { private final MemberService memberService; - @PostMapping("/{memberId}/student/number") + @PostMapping("/student/number") public ResponseEntity registerStudentNumber( - @PathVariable Long memberId, - @RequestParam("studentCardImage") MultipartFile studentCardImage) { + @RequestParam("studentCardImage") MultipartFile studentCardImage, + Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); MemberInformationResponseDTO responseDTO = memberService.registerStudentNumber(memberId, studentCardImage); return ResponseEntity.ok(responseDTO); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java index c63cb56..edbc501 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java @@ -5,10 +5,12 @@ import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeListDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeResponseDTO; import com.ComNCheck.ComNCheck.domain.roleChange.service.RoleChangeRequestService; +import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -29,8 +31,11 @@ public class RoleChangeController { @PostMapping public ResponseEntity createRoleChangeRequest( - @RequestBody RoleChangeRequestDTO requestDTO) { - RoleChangeResponseDTO createDTO = roleChangeRequestService.createRoleChangeRequest(requestDTO); + @RequestBody RoleChangeRequestDTO requestDTO, + Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + RoleChangeResponseDTO createDTO = roleChangeRequestService.createRoleChangeRequest(memberId, requestDTO); URI location = URI.create("api/role-change-requests/" + createDTO.getRequestId()); return ResponseEntity.created(location).body(createDTO); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeRequestDTO.java index 64cc240..be91ed4 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeRequestDTO.java @@ -7,7 +7,6 @@ @Getter @Setter public class RoleChangeRequestDTO { - private Long memberId; private String name; private int studentNumber; private String major; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java index f9da172..904e97e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java @@ -24,8 +24,8 @@ public class RoleChangeRequestService { private final MemberRepository memberRepository; @Transactional - public RoleChangeResponseDTO createRoleChangeRequest(RoleChangeRequestDTO requestDTO) { - Member member = memberRepository.findByMemberId(requestDTO.getMemberId()) + public RoleChangeResponseDTO createRoleChangeRequest(Long memberId, RoleChangeRequestDTO requestDTO) { + Member member = memberRepository.findByMemberId(memberId) .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); RoleChange roleChange = RoleChange.builder() diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index bf9002c..12affb3 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -4,7 +4,7 @@ server: spring: jpa: hibernate: - ddl-auto: create-drop + ddl-auto: update show-sql: true application: name: ComNCheck From 3892ea0a0e551d95425a1e94a1f905d989904a37 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 2 Feb 2025 23:59:50 +0900 Subject: [PATCH 07/67] =?UTF-8?q?Fix=20:=20roleChange=20=EA=B6=8C=ED=95=9C?= =?UTF-8?q?=20=EC=A0=91=EA=B7=BC=20=EC=95=88=EB=90=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B8=EA=B2=B0=20=EC=8B=9C=ED=81=90=EB=A6=AC?= =?UTF-8?q?=ED=8B=B0=20=EC=BB=A8=ED=85=8D=EC=8A=A4=ED=8A=B8=EC=97=90=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=EC=9D=B4=20=EC=95=88=EB=8F=BC=EC=84=9C=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=EB=B3=80=EA=B2=BD=EB=90=98=EB=8F=84=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=EC=9D=B4=20=EC=95=88=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EB=B0=9C=EC=83=9D,=20=EC=9D=BC=EB=8B=A8?= =?UTF-8?q?=20=EB=94=94=EB=B9=84=EC=9D=98=20=EA=B6=8C=ED=95=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EB=A1=9C=20=ED=95=B4=EA=B2=B0=20=EC=B6=94=ED=9B=84=20?= =?UTF-8?q?=EB=8B=A4=EB=A5=B8=20=EB=8D=94=20=EB=82=98=EC=9D=80=20=EB=B0=A9?= =?UTF-8?q?=ED=96=A5=EC=9C=BC=EB=A1=9C=20=ED=95=A0=20=EC=98=88=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + .../ComNCheck/ComNCheckApplication.java | 1 + .../exception/GlobalExceptionHandler.java | 8 +-- .../controller/RoleChangeController.java | 51 ++++++++++------- .../dto/response/RoleChangeResponseDTO.java | 1 + .../service/RoleChangeRequestService.java | 56 +++++++++++++++---- .../handler/CustomSuccessHandler.java | 2 +- 7 files changed, 85 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index e8baff1..f0ce13b 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ out/ hs_err_pid44980.jfr hs_err_pid44980.log + +build/ diff --git a/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java b/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java index 160ade7..bc4757b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java +++ b/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java @@ -9,6 +9,7 @@ public class ComNCheckApplication { public static void main(String[] args) { + System.out.println("실행"); //Load .env file Dotenv dotenv = Dotenv.load(); System.setProperty("H2_DB_URL", dotenv.get("H2_DB_URL")); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java index d1a57ce..eba91c0 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java @@ -25,10 +25,10 @@ public ResponseEntity handleValidationException(ValidationException ex) return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); } - @ExceptionHandler(Exception.class) - public ResponseEntity handleGeneralException(Exception ex) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("서버 내부 오류가 발생했습니다."); - } +// @ExceptionHandler(Exception.class) +// public ResponseEntity handleGeneralException(Exception ex) { +// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("서버 내부 오류가 발생했습니다."); +// } @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity handleResourceNotFound(ResourceNotFoundException ex) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java index edbc501..50f0d89 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java @@ -1,5 +1,6 @@ package com.ComNCheck.ComNCheck.domain.roleChange.controller; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request.RoleChangeRequestDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.ApprovedRoleListDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeListDTO; @@ -40,48 +41,60 @@ public ResponseEntity createRoleChangeRequest( return ResponseEntity.created(location).body(createDTO); } - @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @GetMapping - public ResponseEntity> getAllRequest() { - List response = roleChangeRequestService.getAllRequests(); + public ResponseEntity> getAllRequest(Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + List response = roleChangeRequestService.getAllRequests(memberId); return ResponseEntity.ok(response); } - @PreAuthorize("hasRole('MAJOR_PRESIDENT')") + @GetMapping("/{requestId}") - public ResponseEntity getRequestDetail(@PathVariable Long requestId) { - RoleChangeResponseDTO responseDTO = roleChangeRequestService.getRequestDetail(requestId); + public ResponseEntity getRequestDetail(@PathVariable Long requestId, + Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + RoleChangeResponseDTO responseDTO = roleChangeRequestService.getRequestDetail(requestId, memberId); return ResponseEntity.ok(responseDTO); } - @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @PostMapping("{requestId}/approve") - public ResponseEntity approveRequest(@PathVariable Long requestId) { - roleChangeRequestService.approveRequest(requestId); + public ResponseEntity approveRequest(@PathVariable Long requestId + , Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + roleChangeRequestService.approveRequest(requestId, memberId); return ResponseEntity.ok("승인완료"); } - @PreAuthorize("hasRole('MAJOR_PRESIDENT')") + + @GetMapping("/approved") - public ResponseEntity> getApprovedRequests() { - List approvedList = roleChangeRequestService.getApproveRequests(); + public ResponseEntity> getApprovedRequests(Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + List approvedList = roleChangeRequestService.getApproveRequests(memberId); return ResponseEntity.ok(approvedList); } - @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @PutMapping("/{requestId}/change-role") public ResponseEntity changeMemberRole( - @PathVariable Long requestId, @RequestBody RoleChangeRequestDTO requestDTO + @PathVariable Long requestId, @RequestBody RoleChangeRequestDTO requestDTO, + Authentication authentication ) { - roleChangeRequestService.changeMemberRole(requestId, requestDTO); + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + roleChangeRequestService.changeMemberRole(requestId, requestDTO, memberId); return ResponseEntity.ok("등급 재변경 완료"); } - @PreAuthorize("hasRole('MAJOR_PRESIDENT')") @DeleteMapping("/{requestId}") - public ResponseEntity deleteRequest(@PathVariable Long requestId) { - roleChangeRequestService.deleteRequest(requestId); + public ResponseEntity deleteRequest(@PathVariable Long requestId, + Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + roleChangeRequestService.deleteRequest(requestId, memberId); return ResponseEntity.noContent().build(); } - } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeResponseDTO.java index c027585..e64e9a7 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeResponseDTO.java @@ -27,6 +27,7 @@ public static RoleChangeResponseDTO of(RoleChange entity) { .major(entity.getMember().getMajor()) .studentNumber(entity.getMember().getStudentNumber()) .position(entity.getRequestPosition()) + .requestedRole(entity.getRequestRole()) .status(entity.getStatus()) .build(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java index 904e97e..ed915ae 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java @@ -1,6 +1,7 @@ package com.ComNCheck.ComNCheck.domain.roleChange.service; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request.RoleChangeRequestDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.ApprovedRoleListDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeListDTO; @@ -38,33 +39,49 @@ public RoleChangeResponseDTO createRoleChangeRequest(Long memberId, RoleChangeRe return RoleChangeResponseDTO.of(saveRoleChange); } - public List getAllRequests() { + public List getAllRequests(Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); + List requests = roleChangeRequestRepository.findAll(); return requests.stream() .map(RoleChangeListDTO::of) .collect(Collectors.toList()); } - public RoleChangeResponseDTO getRequestDetail(Long requestId) { + public RoleChangeResponseDTO getRequestDetail(Long requestId, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); + RoleChange request = roleChangeRequestRepository.findById(requestId) .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다.")); return RoleChangeResponseDTO.of(request); } @Transactional - public void approveRequest(Long requestId) { + public void approveRequest(Long requestId, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); + RoleChange request = roleChangeRequestRepository.findById(requestId) .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다.")); request.approve(); - Member member = request.getMember(); - member.updateRole(request.getRequestRole()); - member.updatePosition(request.getRequestPosition()); + Member updateMember = request.getMember(); + updateMember.updateRole(request.getRequestRole()); + updateMember.updatePosition(request.getRequestPosition()); } - public List getApproveRequests() { + public List getApproveRequests(Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); + List requests = roleChangeRequestRepository.findAll().stream() .filter(req -> req.getStatus() == RequestStatus.APPROVED) .collect(Collectors.toList()); @@ -75,7 +92,7 @@ public List getApproveRequests() { } @Transactional - public void changeMemberRole(Long requestId, RoleChangeRequestDTO requestDTO) { + public void changeMemberRole(Long requestId, RoleChangeRequestDTO requestDTO, Long memberId) { RoleChange request = roleChangeRequestRepository.findById(requestId) .orElseThrow(() -> new IllegalArgumentException("요청이 없습니다.")); @@ -83,15 +100,30 @@ public void changeMemberRole(Long requestId, RoleChangeRequestDTO requestDTO) { throw new IllegalArgumentException("한번 변경된 요청만 수정 가능합니다."); } - Member member = request.getMember(); - member.updateRole(requestDTO.getRequestRole()); - member.updatePosition(requestDTO.getRequestPosition()); + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); + + Member updateMember = request.getMember(); + updateMember.updateRole(requestDTO.getRequestRole()); + updateMember.updatePosition(requestDTO.getRequestPosition()); } @Transactional - public void deleteRequest(Long requestId) { + public void deleteRequest(Long requestId, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); + RoleChange request = roleChangeRequestRepository.findById(requestId) .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다.")); roleChangeRequestRepository.delete(request); } + + public void isCheckRole(Member member) { + Role checkRole = member.getRole(); + if(checkRole != Role.ROLE_MAJOR_PRESIDENT) { + throw new IllegalArgumentException("접근 권한이 없습니다."); + } + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index fe015b7..d4fd367 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -36,7 +36,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo String token = jwtUtil.createJwt(memberId, username, role, 60 * 60 * 1000L); response.addCookie(createCookie("JWT", token)); - response.sendRedirect("http://localhost:3000/signup?id=" + memberId); + response.sendRedirect("http://localhost:3000/login/first"); } From a38482789ac91ff3f9208c0fa97a952512da7509 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Mon, 3 Feb 2025 02:47:30 +0900 Subject: [PATCH 08/67] =?UTF-8?q?Fix:=20API=20=EC=97=B0=EB=8F=99=20?= =?UTF-8?q?=EC=95=88=EB=90=98=EB=8A=94=20=EC=98=A4=EB=A5=98=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/ComNCheckApplication.java | 1 - .../controller/MajorEventController.java | 30 +++---- .../dto/request/EventCreateRequestDTO.java | 14 +++- .../dto/request/EventUpdateRequestDTO.java | 14 +++- .../majorEvent/service/MajorEventService.java | 82 ++++++++----------- .../controller/AnswerController.java | 18 ++-- .../controller/QuestionController.java | 15 ++-- .../model/dto/request/AnswerRequestDTO.java | 1 - .../dto/request/AnswerUpdateRequestDTO.java | 11 +++ .../model/dto/request/QuestionRequestDTO.java | 1 - .../majorQuestion/model/entity/Question.java | 4 +- .../majorQuestion/service/AnswerService.java | 26 ++++-- .../service/QuestionService.java | 6 +- .../service/RoleChangeRequestService.java | 3 +- 14 files changed, 126 insertions(+), 100 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerUpdateRequestDTO.java diff --git a/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java b/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java index bc4757b..160ade7 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java +++ b/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java @@ -9,7 +9,6 @@ public class ComNCheckApplication { public static void main(String[] args) { - System.out.println("실행"); //Load .env file Dotenv dotenv = Dotenv.load(); System.setProperty("H2_DB_URL", dotenv.get("H2_DB_URL")); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java index 787dea0..46f4bb0 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java @@ -7,6 +7,8 @@ import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.PagedEventListResponseDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.service.MajorEventService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -27,10 +29,11 @@ public class MajorEventController { private final MajorEventService majorEventService; - @PreAuthorize("hasRole('STUDENT_COUNCIL')") + @PostMapping public ResponseEntity createMajorEvent(@ModelAttribute EventCreateRequestDTO requestDTO, Authentication authentication) { + // 문제 발생시 쌍따음표 일수도 있음 CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); EventResponseDTO responseDTO = majorEventService.createMajorEvent(requestDTO, memberId); @@ -51,29 +54,26 @@ public ResponseEntity> getAllMajorEventsNotPassed() { return ResponseEntity.ok(allMajorEventsNotPassed); } -// @GetMapping("/pages") -// public ResponseEntity getAllMajorEventPage( -// @RequestParam(defaultValue = "1") int page, -// @RequestParam(defaultValue = "10") int size -// ) { -// PagedEventListResponseDTO responseDTO = majorEventService.getAllMajorEventPage(page, size); -// return ResponseEntity.ok(responseDTO); -// } - @PreAuthorize("hasRole('STUDENT_COUNCIL')") @PutMapping("/{majorEventId}") public ResponseEntity updateMajorEvent( @PathVariable Long majorEventId, - @ModelAttribute EventUpdateRequestDTO requestDTO + @ModelAttribute EventUpdateRequestDTO requestDTO, + Authentication authentication ) { - EventResponseDTO updateDTO = majorEventService.updateMajorEvent(majorEventId, requestDTO); + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + EventResponseDTO updateDTO = majorEventService.updateMajorEvent(majorEventId, requestDTO, memberId); return ResponseEntity.ok(updateDTO); } - @PreAuthorize("hasRole('STUDENT_COUNCIL')") + @DeleteMapping("/{majorEventId}") - public ResponseEntity deleteMajorEvent(@PathVariable Long majorEventId) { - majorEventService.deleteMajorEvent(majorEventId); + public ResponseEntity deleteMajorEvent(@PathVariable Long majorEventId, + Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + majorEventService.deleteMajorEvent(majorEventId, memberId); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventCreateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventCreateRequestDTO.java index 816074a..06e5d4c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventCreateRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventCreateRequestDTO.java @@ -14,14 +14,20 @@ public class EventCreateRequestDTO { private String eventName; - @DateTimeFormat(pattern = "yyyy-MM-dd") - private LocalDate date; - @DateTimeFormat(pattern = "HH:mm") - private LocalTime time; + private String date; + private String time; private String location; private String notice; private String googleFormLink; private List cardNewsImages; + public LocalDate getParsedDate() { + return date != null ? LocalDate.parse(date) : null; + } + + public LocalTime getParsedTime() { + return time != null ? LocalTime.parse(time) : null; + } + } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java index c61d41a..a7979b1 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java @@ -14,13 +14,19 @@ public class EventUpdateRequestDTO { private String eventName; - @DateTimeFormat(pattern = "yyyy-MM-dd") - private LocalDate date; - @DateTimeFormat(pattern = "HH:mm") - private LocalTime time; + private String date; + private String time; private String location; private String notice; private String googleFormLink; private List cardNewsImages; + + public LocalDate getParsedDate() { + return date != null ? LocalDate.parse(date) : null; + } + + public LocalTime getParsedTime() { + return time != null ? LocalTime.parse(time) : null; + } } \ No newline at end of file diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java index 684e221..988e017 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java @@ -8,6 +8,7 @@ import com.ComNCheck.ComNCheck.domain.majorEvent.model.entity.MajorEvent; import com.ComNCheck.ComNCheck.domain.majorEvent.repository.MajorEventRepository; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; import java.time.LocalDate; import java.time.LocalTime; @@ -31,16 +32,21 @@ public class MajorEventService { @Transactional public EventResponseDTO createMajorEvent(EventCreateRequestDTO requestDTO, Long writerId) { + System.out.println("서비스 들어옴"); Member writer = memberRepository.findByMemberId(writerId) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원입니다.")); + isCheckRole(writer); + List imageUrls = uploadImagesToGcs(requestDTO.getCardNewsImages()); + LocalDate eventDate = requestDTO.getParsedDate(); + LocalTime eventTime = requestDTO.getParsedTime(); MajorEvent majorEvent = MajorEvent.builder() .writer(writer) .eventName(requestDTO.getEventName()) - .date(requestDTO.getDate()) - .time(requestDTO.getTime()) + .date(eventDate) + .time(eventTime) .location(requestDTO.getLocation()) .notice(requestDTO.getNotice()) .googleFormLink(requestDTO.getGoogleFormLink()) @@ -58,6 +64,7 @@ public EventResponseDTO getMajorEvent(Long majorEventId) { } public List getAllMajorEventsNotPassed() { + // 코드 상에서 정렬 보다는 디비에서 정렬하고 보내는 것이 더 효율적일꺼같음 추후 리펙토링 필요 List all = majorEventRepository.findAll(); LocalDate today = LocalDate.now(); @@ -75,58 +82,22 @@ public List getAllMajorEventsNotPassed() { .collect(Collectors.toList()); } -// public PagedEventListResponseDTO getAllMajorEventPage(int page, int size) { -// List all = majorEventRepository.findAll(); -// -// LocalDate today = LocalDate.now(); -// LocalTime currentTime = LocalTime.now(); -// -// List filtered = all.stream() -// .filter(e -> isNotPassed(e, today, currentTime)) -// .collect(Collectors.toList()); -// -// filtered.sort(Comparator.comparing(MajorEvent::getDate) -// .thenComparing(MajorEvent::getTime)); -// -// long totalElements = filtered.size(); -// int totalPages = (int) Math.ceil((double) totalElements / size); -// -// if (page < 1) { -// page = 1; -// } else if (page >= totalPages && totalPages > 0) { -// page = totalPages -1; -// } -// int zeroBasedPage = page - 1; -// int startIndex = zeroBasedPage * size; -// int endIndex = Math.min(startIndex + size, (int) totalElements); -// -// List pageList = (startIndex < endIndex) -// ? filtered.subList(startIndex, endIndex) -// : Collections.emptyList(); -// -// List content = pageList.stream() -// .map(EventListResponseDTO::of) -// .toList(); -// -// return PagedEventListResponseDTO.builder() -// .currentPage(page) -// .totalPages(totalPages) -// .totalElements(totalElements) -// .size(size) -// .content(content) -// .build(); -// -// } - @Transactional - public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDTO requestDTO) { + public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDTO requestDTO, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); + MajorEvent majorEvent = majorEventRepository.findById(majorEventId) .orElseThrow(() -> new IllegalArgumentException("해당 학부 행사 정보가 없습니다.")); + LocalDate eventDate = requestDTO.getParsedDate(); + LocalTime eventTime = requestDTO.getParsedTime(); + majorEvent.updateEvent( requestDTO.getEventName(), - requestDTO.getDate(), - requestDTO.getTime(), + eventDate, + eventTime, requestDTO.getLocation(), requestDTO.getNotice(), requestDTO.getGoogleFormLink() @@ -140,7 +111,11 @@ public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDT } @Transactional - public void deleteMajorEvent(Long majorEventId) { + public void deleteMajorEvent(Long majorEventId, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); + MajorEvent majorEvent = majorEventRepository.findById(majorEventId) .orElseThrow(() -> new IllegalArgumentException("해당 학부 행사 정보가 없습니다.")); majorEventRepository.delete(majorEvent); @@ -164,4 +139,13 @@ private boolean isNotPassed(MajorEvent majorEvent, LocalDate today, LocalTime cu return majorEvent.getDate().isAfter(today) || (majorEvent.getDate().isEqual(today) && majorEvent.getTime().isBefore(currentTime)); } + + public void isCheckRole(Member member) { + System.out.println("조건문 들어옴"); + Role checkRole = member.getRole(); + if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) { + System.out.println("접근 권한이 없음"); + throw new IllegalArgumentException("접근 권한이 없습니다."); + } + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java index c1c9f7a..57c85c9 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java @@ -16,7 +16,6 @@ public class AnswerController { private final AnswerService answerService; - @PreAuthorize("hasRole('STUDENT_COUNCIL')") @PostMapping public ResponseEntity createOrUpdateAnswer( @RequestBody AnswerRequestDTO requestDTO, @@ -24,28 +23,31 @@ public ResponseEntity createOrUpdateAnswer( ) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long writerId = principal.getMemberDTO().getMemberId(); - requestDTO.setWriterId(writerId); - AnswerResponseDTO responseDTO = answerService.createOrUpdateAnswer(requestDTO); + AnswerResponseDTO responseDTO = answerService.createOrUpdateAnswer(requestDTO, writerId); return ResponseEntity.ok(responseDTO); } - @PreAuthorize("hasRole('STUDENT_COUNCIL')") + @PutMapping("/{answerId}") public ResponseEntity updateAnswer( @PathVariable Long answerId, - @RequestBody String content, + @RequestBody AnswerRequestDTO answerRequestDTO, Authentication authentication ) { - AnswerResponseDTO responseDTO = answerService.updateAnswer(answerId, content); + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long writerId = principal.getMemberDTO().getMemberId(); + AnswerResponseDTO responseDTO = answerService.updateAnswer(answerId, answerRequestDTO.getContent(), writerId); return ResponseEntity.ok(responseDTO); } - @PreAuthorize("hasRole('STUDENT_COUNCIL')") + @DeleteMapping("/{answerId}") public ResponseEntity deleteAnswer( @PathVariable Long answerId, Authentication authentication ) { - answerService.deleteAnswer(answerId); + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long writerId = principal.getMemberDTO().getMemberId(); + answerService.deleteAnswer(answerId, writerId); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java index 1decfbc..2914e4a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java @@ -6,7 +6,6 @@ import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; import java.net.URI; import java.util.List; -import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; @@ -29,13 +28,17 @@ public class QuestionController { @PostMapping - public ResponseEntity createQuestion(@RequestBody QuestionRequestDTO requestDTO) { - QuestionResponseDTO responseDTO = questionService.createQuestion(requestDTO); + public ResponseEntity createQuestion(@RequestBody QuestionRequestDTO requestDTO, + Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + QuestionResponseDTO responseDTO = questionService.createQuestion(requestDTO, memberId); URI location = ServletUriComponentsBuilder.fromCurrentRequest() .path("/{majorQuestionId}") .buildAndExpand(responseDTO.getId()) .toUri(); + return ResponseEntity.created(location).body(responseDTO); } @@ -69,11 +72,11 @@ public ResponseEntity updateQuestion(@PathVariable Long maj return ResponseEntity.ok(updateDTO); } - @DeleteMapping - public ResponseEntity deleteQuestion(@PathVariable Long id, Authentication authentication) { + @DeleteMapping("/{majorQuestionId}") + public ResponseEntity deleteQuestion(@PathVariable Long majorQuestionId, Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); - questionService.deleteQuestion(id, memberId); + questionService.deleteQuestion(majorQuestionId, memberId); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java index 2fb621b..f474ffe 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java @@ -8,6 +8,5 @@ public class AnswerRequestDTO { private String content; private Long questionId; - private Long writerId; } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerUpdateRequestDTO.java new file mode 100644 index 0000000..e22a5d8 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerUpdateRequestDTO.java @@ -0,0 +1,11 @@ +package com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request; + + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AnswerUpdateRequestDTO { + private String content; +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java index ae1d984..1c25ef1 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java @@ -8,6 +8,5 @@ public class QuestionRequestDTO { private String title; private String content; - private Long writerId; } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java index 483b49f..1810c60 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java @@ -43,7 +43,9 @@ public class Question { @OneToOne(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true) private Answer answer; + @Column private LocalDateTime createdAt; + @Column private LocalDateTime updatedAt; @@ -55,7 +57,7 @@ public void setAnswer(Answer answer) { answer.setQuestion(this); } - public void updateQuestion(String title, String contest) { + public void updateQuestion(String title, String content) { this.title = title; this.content = content; this.updatedAt = LocalDateTime.now(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java index 127500c..e65bc62 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java @@ -1,6 +1,7 @@ package com.ComNCheck.ComNCheck.domain.majorQuestion.service; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.AnswerRequestDTO; import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.AnswerResponseDTO; @@ -23,10 +24,10 @@ public class AnswerService { @Transactional - public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO) { - // Role 체크 로직 - Member writer = memberRepository.findByMemberId(requestDTO.getWriterId()) + public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO, Long memberId) { + Member writer = memberRepository.findByMemberId(memberId) .orElseThrow(() -> new IllegalArgumentException("해당 회원이 존재하지 않습니다.")); + isCheckRole(writer); Question question = questionRepository.findById(requestDTO.getQuestionId()) .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); @@ -49,7 +50,10 @@ public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO) { } } @Transactional - public AnswerResponseDTO updateAnswer(Long answerId, String content) { + public AnswerResponseDTO updateAnswer(Long answerId, String content, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); Answer answer = answerRepository.findById(answerId) .orElseThrow(() -> new IllegalArgumentException("해당 답글이 존재하지 않습니다.")); @@ -58,10 +62,20 @@ public AnswerResponseDTO updateAnswer(Long answerId, String content) { } @Transactional - public void deleteAnswer(Long answerId) { + public void deleteAnswer(Long answerId, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + isCheckRole(member); Answer answer = answerRepository.findById(answerId) .orElseThrow(() -> new IllegalArgumentException("해당 답글이 존재하지 않습니다.")); answerRepository.delete(answer); -} + } + + public void isCheckRole(Member member) { + Role checkRole = member.getRole(); + if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) { + throw new IllegalArgumentException("접근 권한이 없습니다."); + } + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index 044b64e..dab6830 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -22,8 +22,8 @@ public class QuestionService { private final MemberRepository memberRepository; @Transactional - public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO) { - Member writer = memberRepository.findByMemberId(requestDTO.getWriterId()) + public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO, Long memberId) { + Member writer = memberRepository.findByMemberId(memberId) .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다.")); Question question = Question.builder() @@ -67,7 +67,7 @@ public void deleteQuestion(Long questionId, Long writerId) { Question question = questionRepository.findById(questionId) .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); - if(question.getWriter().getMemberId().equals(writerId)) { + if(!question.getWriter().getMemberId().equals(writerId)) { throw new UnauthorizedException("작성자가 아닙니다."); } questionRepository.delete(question); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java index ed915ae..df7b568 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java @@ -122,8 +122,9 @@ public void deleteRequest(Long requestId, Long memberId) { public void isCheckRole(Member member) { Role checkRole = member.getRole(); - if(checkRole != Role.ROLE_MAJOR_PRESIDENT) { + if (checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_ADMIN) { throw new IllegalArgumentException("접근 권한이 없습니다."); } } + } From 8dac5bff3ed7e71ddd7638c1826735d0081ce67a Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 4 Feb 2025 21:28:56 +0900 Subject: [PATCH 09/67] =?UTF-8?q?Feat:=20=EC=8A=A4=EC=9B=A8=EA=B1=B0=20?= =?UTF-8?q?=EC=84=A4=EB=AA=85=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 2 ++ docker-compose.yaml | 11 ----------- .../controller/DeveloperQuestionController.java | 6 ++++++ .../controller/EmploymentController.java | 3 +++ .../global/infrastructure/FastApiClient.java | 9 ++++++--- .../controller/MajorEventController.java | 6 ++++++ .../controller/MajorNoticeController.java | 3 +++ .../controller/AnswerController.java | 4 ++++ .../controller/QuestionController.java | 9 ++++++++- .../majorQuestion/model/entity/Question.java | 3 +++ .../repository/QuestionRepository.java | 1 + .../majorQuestion/service/QuestionService.java | 5 +++-- .../member/controller/MemberController.java | 9 +++++---- .../controller/RoleChangeController.java | 8 ++++++++ .../domain/security/config/SecurityConfig.java | 4 ++-- .../domain/security/filter/JWTFilter.java | 4 ++-- .../domain/testController/MyController.java | 2 ++ src/main/resources/application.yaml | 6 ++++-- 19 files changed, 68 insertions(+), 27 deletions(-) create mode 100644 .DS_Store delete mode 100644 docker-compose.yaml diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 createDeveloperQuestion( @RequestBody DeveloperQuestionRequestDTO requestDTO, Authentication authentication @@ -40,6 +42,7 @@ public ResponseEntity createDeveloperQuestion( } @GetMapping("/{developerQuestionId}") + @Operation(summary = "특정 개발자 질문 게시글 조회", description = "특정 개발자 질문 게시글 조회한다.") public ResponseEntity getDeveloperQuestion( @PathVariable Long developerQuestionId ) { @@ -48,12 +51,14 @@ public ResponseEntity getDeveloperQuestion( } @GetMapping + @Operation(summary = "개발자 질문 게시글 목록 조회", description = "개발자 질문 게시글 목록 조회한다.") public ResponseEntity> getAllDeveloperQuestions() { List questionList = developerQuestionService.getAllQuestion(); return ResponseEntity.ok(questionList); } @PutMapping("/{developerQuestionId}") + @Operation(summary = "개발자 질문 게시글 수정", description = "개발자 질문 게시글을 수정한다.") public ResponseEntity updateDeveloperQuestion( @PathVariable Long developerQuestionId, @RequestBody DeveloperQuestionResponseDTO requestDTO, @@ -68,6 +73,7 @@ public ResponseEntity updateDeveloperQuestion( } @DeleteMapping("/{developerQuestionId}") + @Operation(summary = "개발자 질문 게시글 삭제", description = "개발자 질문 게시글을 삭제한다.") public ResponseEntity deleteDeveloperQuestion( @PathVariable Long developerQuestionId, Authentication authentication diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java index d0384b0..50b0417 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java @@ -3,6 +3,7 @@ import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.PageEmploymentNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.employmentNotice.service.EmploymentNoticeService; +import io.swagger.v3.oas.annotations.Operation; import jakarta.xml.bind.annotation.XmlType.DEFAULT; import java.util.List; import lombok.RequiredArgsConstructor; @@ -20,12 +21,14 @@ public class EmploymentController { private final EmploymentNoticeService employmentNoticeService; @GetMapping + @Operation(summary = "취업정보 게시판 목록 조회", description = "취업정보 게시판 목록을 조회한다.") public ResponseEntity> getAllEmploymentNotice() { List lists = employmentNoticeService.getAllEmploymentNotices(); return ResponseEntity.ok(lists); } @GetMapping("/pages") + @Operation(summary = "취업정보 게시판 목록 조회(페이지네이션)", description = "페이지네이션으로 취업정보 게시판 목록을 조회한다.") public ResponseEntity getEmploymentNoticePage( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java index 58887fd..4bc228a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java @@ -23,9 +23,12 @@ public class FastApiClient { private final RestTemplate restTemplate; - private static final String FAST_API_URL_OCR= "http://localhost:8000/api/vi/compare-and-ocr"; - private static final String FAST_API_URL_SCRAPE_NOTICE = "http://localhost:8000/api/vi/scrape/notice"; - private static final String Fast_API_URL_EMPLOYMENT = "http://localhost:8000/api/vi/scrape/employment"; + private static final String LOCAL = "http://localhost:8000"; + public static final String TEST_DISTRIBUTION = "http://comncheck.iptime.org:8000"; + + private static final String FAST_API_URL_OCR= TEST_DISTRIBUTION + "/api/vi/compare-and-ocr"; + private static final String FAST_API_URL_SCRAPE_NOTICE = TEST_DISTRIBUTION + "/api/vi/scrape/notice"; + private static final String Fast_API_URL_EMPLOYMENT = TEST_DISTRIBUTION + "/api/vi/scrape/employment"; public FastApiStudentCardDTO sendImage(MultipartFile imageFile) { MultiValueMap body = new LinkedMultiValueMap<>(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java index 46f4bb0..406dda8 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java @@ -7,6 +7,7 @@ import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.PagedEventListResponseDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.service.MajorEventService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; +import io.swagger.v3.oas.annotations.Operation; import java.time.LocalDate; import java.time.LocalTime; import java.util.List; @@ -31,6 +32,7 @@ public class MajorEventController { private final MajorEventService majorEventService; @PostMapping + @Operation(summary = "과행사 게시글 작성", description = "과행사 게시글을 작성한다. 학생회, 과회장만 가능하다.") public ResponseEntity createMajorEvent(@ModelAttribute EventCreateRequestDTO requestDTO, Authentication authentication) { // 문제 발생시 쌍따음표 일수도 있음 @@ -42,6 +44,7 @@ public ResponseEntity createMajorEvent(@ModelAttribute EventCr @GetMapping("/{majorEventId}") + @Operation(summary = "특정 과행사 게시글 조회", description = "특정 과행사 게시글을 조회한다.") public ResponseEntity getMajorEvent(@PathVariable Long majorEventId) { EventResponseDTO responseDTO = majorEventService.getMajorEvent(majorEventId); return ResponseEntity.ok(responseDTO); @@ -49,6 +52,7 @@ public ResponseEntity getMajorEvent(@PathVariable Long majorEv @GetMapping + @Operation(summary = "과행사 게시글 목록 조회", description = "과행사 게시글 목록을 조회한다. 이미 지난 행사는 보여주지 않는다.") public ResponseEntity> getAllMajorEventsNotPassed() { List allMajorEventsNotPassed = majorEventService.getAllMajorEventsNotPassed(); return ResponseEntity.ok(allMajorEventsNotPassed); @@ -56,6 +60,7 @@ public ResponseEntity> getAllMajorEventsNotPassed() { @PutMapping("/{majorEventId}") + @Operation(summary = "과행사 게시글 수정", description = "작성된 과행사 게시글을 수정한다. 작성자가 누구든 과회장과, 학생회는 수정할 수 있다.") public ResponseEntity updateMajorEvent( @PathVariable Long majorEventId, @ModelAttribute EventUpdateRequestDTO requestDTO, @@ -69,6 +74,7 @@ public ResponseEntity updateMajorEvent( @DeleteMapping("/{majorEventId}") + @Operation(summary = "과행사 게시글 삭제 ", description = "작성된 과행사 게시글을 삭제한다. 작성자가 누구든 과회장과, 학생회는 삭제할 수 있다.") public ResponseEntity deleteMajorEvent(@PathVariable Long majorEventId, Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java index f0ad86c..4a258ca 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java @@ -3,6 +3,7 @@ import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.PageMajorNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.majorNotice.service.MajorNoticeService; +import io.swagger.v3.oas.annotations.Operation; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -19,12 +20,14 @@ public class MajorNoticeController { private final MajorNoticeService majorNoticeService; @GetMapping + @Operation(summary = "학부 공지사항 목록 조회", description = "학부 공지사항 목록을 조회한다.") public ResponseEntity> getAllMajorNotices() { List lists = majorNoticeService.getAllMajorNotices(); return ResponseEntity.ok(lists); } @GetMapping("/pages") + @Operation(summary = "학부 공지사항 목록 조회(페이지네이션)", description = "페이지네이션으로 학부 공지사항 목록을 조회한다.") public ResponseEntity getMajorNoticesPage( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java index 57c85c9..d67162e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java @@ -4,6 +4,7 @@ import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.AnswerResponseDTO; import com.ComNCheck.ComNCheck.domain.majorQuestion.service.AnswerService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; +import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -17,6 +18,7 @@ public class AnswerController { private final AnswerService answerService; @PostMapping + @Operation(summary = "fAQ 댓글 작성", description = "학생회권한만 댓글을 달 수 있다.") public ResponseEntity createOrUpdateAnswer( @RequestBody AnswerRequestDTO requestDTO, Authentication authentication @@ -29,6 +31,7 @@ public ResponseEntity createOrUpdateAnswer( } @PutMapping("/{answerId}") + @Operation(summary = "fAQ 댓글 수정", description = "학생회권한만 댓글 작성자의 관계없이 댓글 수정이 가능하다.") public ResponseEntity updateAnswer( @PathVariable Long answerId, @RequestBody AnswerRequestDTO answerRequestDTO, @@ -41,6 +44,7 @@ public ResponseEntity updateAnswer( } @DeleteMapping("/{answerId}") + @Operation(summary = "fAQ 댓글 삭제", description = "학생회권한만 작성자의 관계없이 댓글 삭제가 가능하다") public ResponseEntity deleteAnswer( @PathVariable Long answerId, Authentication authentication diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java index 2914e4a..61972ab 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java @@ -4,6 +4,7 @@ import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.QuestionResponseDTO; import com.ComNCheck.ComNCheck.domain.majorQuestion.service.QuestionService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; +import io.swagger.v3.oas.annotations.Operation; import java.net.URI; import java.util.List; import lombok.RequiredArgsConstructor; @@ -28,6 +29,7 @@ public class QuestionController { @PostMapping + @Operation(summary = "FAQ 게시글 작성", description = "학생회에게 질문글을 작성할 수 있다.") public ResponseEntity createQuestion(@RequestBody QuestionRequestDTO requestDTO, Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); @@ -43,18 +45,21 @@ public ResponseEntity createQuestion(@RequestBody QuestionR } @GetMapping("/{majorQuestionId}") + @Operation(summary = "fAQ 특정 게시글 조회", description = "FAQ의 특정 게시글을 클릭했을 때 자세히 볼 수 있다") public ResponseEntity getQuestion(@PathVariable Long majorQuestionId) { QuestionResponseDTO responseDTO = questionService.getQuestion(majorQuestionId); return ResponseEntity.ok(responseDTO); } @GetMapping + @Operation(summary = "fAQ의 답변이 달린 게시글 목록 조회", description = "댓글이 달린 모든 게시글 목록을 조회한다.") public ResponseEntity> getAllQuestion() { - List questions = questionService.getAllQuestions(); + List questions = questionService.getQuestionsWithAnswer(); return ResponseEntity.ok(questions); } @GetMapping("/my") + @Operation(summary = "내가 작성한 FAQ 게시글 목록 조회", description = "내가 작성한 FAQ 게시글 목록을 조회한다") public ResponseEntity> getMyQuestions(Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long writerId = principal.getMemberDTO().getMemberId(); @@ -63,6 +68,7 @@ public ResponseEntity> getMyQuestions(Authentication a } @PutMapping("/{majorQuestionId}") + @Operation(summary = "FAQ 게시글 수정", description = "FAQ 게시글을 수정한다. 단, 본인이 작성한 게시글만 가능") public ResponseEntity updateQuestion(@PathVariable Long majorQuestionId, @RequestBody QuestionRequestDTO requestDTO, Authentication authentication) { @@ -73,6 +79,7 @@ public ResponseEntity updateQuestion(@PathVariable Long maj } @DeleteMapping("/{majorQuestionId}") + @Operation(summary = "FAQ 게시글 삭제 ", description = "FAQ 게시글을 삭제한다. 단, 본인이 작성한 게시글만 가능") public ResponseEntity deleteQuestion(@PathVariable Long majorQuestionId, Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java index 1810c60..607a327 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java @@ -48,6 +48,9 @@ public class Question { @Column private LocalDateTime updatedAt; +// @Column +// private boolean + /* 연관관계 편의 메서드 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java index c4d83c6..3c13ac2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java @@ -6,4 +6,5 @@ public interface QuestionRepository extends JpaRepository { List findAllByWriterMemberId(Long writerId); + List findByAnswerIsNotNull(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index dab6830..fb03507 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -42,8 +42,9 @@ public QuestionResponseDTO getQuestion(Long questionId) { return QuestionResponseDTO.of(question); } - public List getAllQuestions() { - return questionRepository.findAll() + public List getQuestionsWithAnswer() { + + return questionRepository.findByAnswerIsNotNull() .stream() .map(QuestionResponseDTO::of) .toList(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java index 683cde9..21d601f 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java @@ -4,6 +4,7 @@ import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO; import com.ComNCheck.ComNCheck.domain.member.service.MemberService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; +import io.swagger.v3.oas.annotations.Operation; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -23,6 +24,7 @@ public class MemberController { private final MemberService memberService; @PostMapping("/student/number") + @Operation(summary = "학번 등록", description = "모바일 학생증으로 학번을 등록한다.") public ResponseEntity registerStudentNumber( @RequestParam("studentCardImage") MultipartFile studentCardImage, Authentication authentication) { @@ -33,12 +35,14 @@ public ResponseEntity registerStudentNumber( } @GetMapping("/members/president-council") + @Operation(summary = "학생회 목록 조회", description = "학생회 목록을 조회한다.") public ResponseEntity getPresidentCouncilList() { PresidentCouncilResponseDTO responseDTO = memberService.getPresidentAndCouncils(); return ResponseEntity.ok(responseDTO); } @GetMapping + @Operation(summary = "본인 정보 조회", description = "로그인 이후, 학번 변동 이후 본인 정보를 조회한다.") public ResponseEntity getMemberInformation(Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); @@ -47,12 +51,9 @@ public ResponseEntity getMemberInformation(Authent } @PostMapping("/logout") + @Operation(summary = "로그아웃", description = "쿠키의 jwt를 강제로 만료시켜 로그아웃 시킨다.") public ResponseEntity logout(HttpServletResponse response) { memberService.logout(response); return ResponseEntity.ok("로그아웃 성공"); } - - - - } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java index 50f0d89..35bc8fa 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java @@ -7,6 +7,7 @@ import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeResponseDTO; import com.ComNCheck.ComNCheck.domain.roleChange.service.RoleChangeRequestService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; +import io.swagger.v3.oas.annotations.Operation; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -31,6 +32,7 @@ public class RoleChangeController { private final RoleChangeRequestService roleChangeRequestService; @PostMapping + @Operation(summary = "학생회 등급 신청", description = "학생회 인원이 학생회 등급으로 신청한다") public ResponseEntity createRoleChangeRequest( @RequestBody RoleChangeRequestDTO requestDTO, Authentication authentication) { @@ -42,6 +44,7 @@ public ResponseEntity createRoleChangeRequest( } @GetMapping + @Operation(summary = "학새회 등급 신청 목록 조회", description = "학생회 등급 신청 목록을 조회한다.") public ResponseEntity> getAllRequest(Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); @@ -51,6 +54,7 @@ public ResponseEntity> getAllRequest(Authentication auth @GetMapping("/{requestId}") + @Operation(summary = "특정 학생회 등급 신청 조회", description = "특정 학생회 등급 신청을 조회한다.") public ResponseEntity getRequestDetail(@PathVariable Long requestId, Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); @@ -60,6 +64,7 @@ public ResponseEntity getRequestDetail(@PathVariable Long } @PostMapping("{requestId}/approve") + @Operation(summary = "학생회 등급 신청 승인", description = "과회장 or 관리자가 학생회 등급 신청을 승인한다.") public ResponseEntity approveRequest(@PathVariable Long requestId , Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); @@ -70,6 +75,7 @@ public ResponseEntity approveRequest(@PathVariable Long requestId @GetMapping("/approved") + @Operation(summary = "승인된 학생회 등급 신청 목록 조회", description = "승인된 학생회 등급 신청 목록을 조회한다.") public ResponseEntity> getApprovedRequests(Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); @@ -78,6 +84,7 @@ public ResponseEntity> getApprovedRequests(Authenticat } @PutMapping("/{requestId}/change-role") + @Operation(summary = "특정 학생회 등급 조정", description = "승인된 학생회 등급 신청에서 등급을 조정한다.") public ResponseEntity changeMemberRole( @PathVariable Long requestId, @RequestBody RoleChangeRequestDTO requestDTO, Authentication authentication @@ -89,6 +96,7 @@ public ResponseEntity changeMemberRole( } @DeleteMapping("/{requestId}") + @Operation(summary = "특정 학생회 등급 신청 요청 삭제", description = "요청온 학생회 등급 신청 요청을 삭제한다.") public ResponseEntity deleteRequest(@PathVariable Long requestId, Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 66a313e..6680e3c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -55,8 +55,8 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { "/V3/api-docs", "/v3/api-docs/**", "/swagger-resources/**", - "/webjars/**" - //"/api/v1/**" + "/webjars/**", + "/api/v1/**" ).permitAll() .anyRequest().authenticated() ) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java index a6b1d7e..0fac515 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java @@ -34,8 +34,8 @@ public class JWTFilter extends OncePerRequestFilter { "/webjars/**", "/login/**", "/oauth2/**", - "/h2-console/**" - //"api/v1/**" + "/h2-console/**", + "api/v1/**" }; private final AntPathMatcher pathMatcher = new AntPathMatcher(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java index 0eb39ce..7e10d71 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java @@ -1,5 +1,6 @@ package com.ComNCheck.ComNCheck.domain.testController; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @@ -8,6 +9,7 @@ public class MyController { @GetMapping("/my") + @Operation(summary = "CORS 에러 체크", description = "CORS 여부를 따지기 위한 API 였으므로, 신경 안써도됨 삭제 예정") @ResponseBody public String myAPI() { return "my route"; diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 12affb3..85b055c 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -4,19 +4,21 @@ server: spring: jpa: hibernate: - ddl-auto: update + ddl-auto: create show-sql: true application: name: ComNCheck datasource: driver-class-name: org.h2.Driver - url: ${H2_DB_URL} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode) + url: ${H2_DB_URL:jdbc:h2:mem:test} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode) username: ${DB_USERNAME} password: ${DB_PASSWORD} h2: console: enabled: true path: /h2-console + settings: + web-allow-others: true security: oauth2: client: From 962ce959e1ed82592d60bce87e6adbe6a18fc7f1 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Wed, 5 Feb 2025 01:23:31 +0900 Subject: [PATCH 10/67] =?UTF-8?q?Feat:=20=ED=95=99=EA=B3=BC=20=EC=A7=88?= =?UTF-8?q?=EB=AC=B8=20=EA=B3=B5=EA=B0=9C=20=EC=97=AC=EB=B6=80=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 1 + buildDockerWindow.sh | 4 ++++ .../com/ComNCheck/ComNCheck/ComNCheckApplication.java | 11 ----------- .../majorQuestion/controller/QuestionController.java | 3 ++- .../model/dto/request/QuestionRequestDTO.java | 2 +- .../model/dto/response/QuestionResponseDTO.java | 2 ++ .../domain/majorQuestion/model/entity/Question.java | 8 ++++---- .../majorQuestion/repository/QuestionRepository.java | 3 +++ .../domain/majorQuestion/service/QuestionService.java | 3 ++- 9 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 .dockerignore create mode 100755 buildDockerWindow.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/buildDockerWindow.sh b/buildDockerWindow.sh new file mode 100755 index 0000000..1701b13 --- /dev/null +++ b/buildDockerWindow.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.0.5 . + diff --git a/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java b/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java index 160ade7..f71d3c8 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java +++ b/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java @@ -1,6 +1,5 @@ package com.ComNCheck.ComNCheck; -import io.github.cdimascio.dotenv.Dotenv; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -9,16 +8,6 @@ public class ComNCheckApplication { public static void main(String[] args) { - //Load .env file - Dotenv dotenv = Dotenv.load(); - System.setProperty("H2_DB_URL", dotenv.get("H2_DB_URL")); - System.setProperty("DB_USERNAME", dotenv.get("DB_USERNAME")); - System.setProperty("DB_PASSWORD", dotenv.get("DB_PASSWORD")); - System.setProperty("JWT_SECRET", dotenv.get("JWT_SECRET")); - System.setProperty("GOOGLE_CLIENT_ID", dotenv.get("GOOGLE_CLIENT_ID")); - System.setProperty("GOOGLE_CLIENT_SECRET", dotenv.get("GOOGLE_CLIENT_SECRET")); - System.setProperty("JWT_EXPIRATIONMS",dotenv.get("JWT_EXPIRATIONMS")); - System.setProperty("GOOGLE_REDIRECT_URI",dotenv.get("GOOGLE_REDIRECT_URI")); SpringApplication.run(ComNCheckApplication.class, args); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java index 61972ab..c10b242 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java @@ -52,7 +52,8 @@ public ResponseEntity getQuestion(@PathVariable Long majorQ } @GetMapping - @Operation(summary = "fAQ의 답변이 달린 게시글 목록 조회", description = "댓글이 달린 모든 게시글 목록을 조회한다.") + @Operation(summary = "fAQ의 답변이 달린 게시글 목록 조회 공유가 true 인 경우만" + , description = "댓글이 달린 모든 게시글 목록을 조회한다.") public ResponseEntity> getAllQuestion() { List questions = questionService.getQuestionsWithAnswer(); return ResponseEntity.ok(questions); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java index 1c25ef1..b5a79e7 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java @@ -8,5 +8,5 @@ public class QuestionRequestDTO { private String title; private String content; - + private boolean shared; } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java index 89b7b60..db00297 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java @@ -15,12 +15,14 @@ public class QuestionResponseDTO { private LocalDateTime createdAt; private LocalDateTime updatedAt; private AnswerResponseDTO answer; + private boolean shared; public static QuestionResponseDTO of(Question question) { return QuestionResponseDTO.builder() .id(question.getId()) .title(question.getTitle()) .content(question.getContent()) + .shared(question.isShared()) //.writerId(question.getWriter().getId()) .createdAt(question.getCreatedAt()) .updatedAt(question.getUpdatedAt()) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java index 607a327..e09068b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java @@ -37,6 +37,9 @@ public class Question { @Column(nullable = false) private String content; + @Column(nullable = false) + private boolean shared; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "writer_id") private Member writer; @@ -48,13 +51,10 @@ public class Question { @Column private LocalDateTime updatedAt; -// @Column -// private boolean - - /* 연관관계 편의 메서드 */ + public void setAnswer(Answer answer) { this.answer = answer; answer.setQuestion(this); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java index 3c13ac2..0aae3eb 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java @@ -2,9 +2,12 @@ import com.ComNCheck.ComNCheck.domain.majorQuestion.model.entity.Question; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface QuestionRepository extends JpaRepository { List findAllByWriterMemberId(Long writerId); List findByAnswerIsNotNull(); + Optional findByIdAndSharedTrue(Long id); + List findByAnswerIsNotNullAndSharedTrue(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index fb03507..e96f5be 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -29,6 +29,7 @@ public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO, Long me Question question = Question.builder() .title(requestDTO.getTitle()) .content(requestDTO.getContent()) + .shared(requestDTO.isShared()) .writer(writer) .build(); @@ -44,7 +45,7 @@ public QuestionResponseDTO getQuestion(Long questionId) { public List getQuestionsWithAnswer() { - return questionRepository.findByAnswerIsNotNull() + return questionRepository.findByAnswerIsNotNullAndSharedTrue() .stream() .map(QuestionResponseDTO::of) .toList(); From 6c6db197236dd846b328f9ebf909a27e6f9ecc31 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 6 Feb 2025 02:17:38 +0900 Subject: [PATCH 11/67] =?UTF-8?q?Feat:=20=EA=B3=BC=ED=96=89=EC=82=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=97=90=20GOOGLE=20GLOUD=20STORAGE=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + Dockerfile | 3 +- build.gradle | 6 ++- buildDockerWindow.sh | 2 +- data/refresh-token-data/dump.rdb | Bin 0 -> 88 bytes .../majorEvent/service/MajorEventService.java | 36 ++++++++++++++---- src/main/resources/application.yaml | 13 ++++++- 7 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 data/refresh-token-data/dump.rdb diff --git a/.gitignore b/.gitignore index 113baba..8f7b99d 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ hs_err_pid44980.log build/ docker-compose.yaml + +/src/main/resources/ancient-pipe-447417-i4-755ce59fbf03.json diff --git a/Dockerfile b/Dockerfile index cc15b00..9ccc954 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,4 +2,5 @@ FROM openjdk:17 ARG JAR_FILE=build/libs/*.jar COPY ${JAR_FILE} test-app.jar EXPOSE 8080 -CMD ["java", "-Dtest.customName=${CUSTOM_NAME}", "-jar", "test-app.jar"] \ No newline at end of file +CMD ["java", "-Dtest.customName=${CUSTOM_NAME}", "-jar", "test-app.jar"] + diff --git a/build.gradle b/build.gradle index 11d7364..c28bbfd 100644 --- a/build.gradle +++ b/build.gradle @@ -23,13 +23,15 @@ repositories { mavenCentral() } + dependencies { implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'io.jsonwebtoken:jjwt-api:0.12.3' implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' - implementation 'io.github.cdimascio:java-dotenv:5.2.2' // .env 파일 + implementation 'org.springframework.boot:spring-boot-starter-data-redis' + //implementation 'io.github.cdimascio:java-dotenv:5.2.2' // .env 파일 implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.h2database:h2' implementation 'org.springframework.boot:spring-boot-starter-web' @@ -38,6 +40,8 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' + implementation group: 'com.google.cloud', name: 'spring-cloud-gcp-starter', version: '6.0.0' + implementation group: 'com.google.cloud', name: 'spring-cloud-gcp-storage', version: '6.0.0' } tasks.named('test') { diff --git a/buildDockerWindow.sh b/buildDockerWindow.sh index 1701b13..cbcb728 100755 --- a/buildDockerWindow.sh +++ b/buildDockerWindow.sh @@ -1,4 +1,4 @@ #!/bin/bash -docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.0.5 . +docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.0.7 . diff --git a/data/refresh-token-data/dump.rdb b/data/refresh-token-data/dump.rdb new file mode 100644 index 0000000000000000000000000000000000000000..ece464bd7a24cd2d8ccf9b38aa6a1a1da00cf047 GIT binary patch literal 88 zcmWG?b@2=~FfcUw#aWb^l3A=*t005{MBYpq? literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java index 988e017..0052a19 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java @@ -4,20 +4,23 @@ import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventUpdateRequestDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.EventListResponseDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.EventResponseDTO; -import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.PagedEventListResponseDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.entity.MajorEvent; import com.ComNCheck.ComNCheck.domain.majorEvent.repository.MajorEventRepository; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; +import com.google.cloud.storage.Storage; +import com.google.cloud.storage.BlobInfo; +import java.io.IOException; import java.time.LocalDate; import java.time.LocalTime; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -29,10 +32,12 @@ public class MajorEventService { private final MajorEventRepository majorEventRepository; private final MemberRepository memberRepository; + @Value("${spring.cloud.gcp.storage.bucket}") + private String bucketName; + private final Storage storage; @Transactional public EventResponseDTO createMajorEvent(EventCreateRequestDTO requestDTO, Long writerId) { - System.out.println("서비스 들어옴"); Member writer = memberRepository.findByMemberId(writerId) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원입니다.")); @@ -126,11 +131,27 @@ private List uploadImagesToGcs(List images) { if (images == null || images.isEmpty()) { return new ArrayList<>(); } + List uploadUrls = new ArrayList<>(); - for(MultipartFile file : images) { - // gcs 업로드 호출 - String url = "https://gcs.com" + file.getOriginalFilename(); - uploadUrls.add(url); + for (MultipartFile file : images) { + try { + String uuid = UUID.randomUUID().toString(); + String contentType = file.getContentType(); + if (contentType == null) { + contentType = "application/octet-stream"; + } + BlobInfo blobInfo = storage.create( + BlobInfo.newBuilder(bucketName, uuid) + .setContentType(contentType) + .build(), + file.getInputStream() + ); + String url = "https://storage.googleapis.com/" + bucketName + "/" + uuid; + uploadUrls.add(url); + + } catch (IOException e) { + throw new RuntimeException("이미지 업로드 실패", e); + } } return uploadUrls; } @@ -141,7 +162,6 @@ private boolean isNotPassed(MajorEvent majorEvent, LocalDate today, LocalTime cu } public void isCheckRole(Member member) { - System.out.println("조건문 들어옴"); Role checkRole = member.getRole(); if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) { System.out.println("접근 권한이 없음"); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 85b055c..ee1d298 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -32,7 +32,18 @@ spring: scope: - email - profile - + data: + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASSWORD} + cloud: + gcp: + storage: + credentials: + location: classpath:ancient-pipe-447417-i4-755ce59fbf03.json + project-id: ${PROJECT_ID} + bucket: ${BUCKET_ID} jwt: secret: ${JWT_SECRET} expirationMs: ${JWT_EXPIRATIONMS} \ No newline at end of file From 05f389b3ca27954eecceb3b9a12b3957bc451adb Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 6 Feb 2025 21:57:07 +0900 Subject: [PATCH 12/67] =?UTF-8?q?Refactor:=20=EB=B0=B0=ED=8F=AC=EB=A5=BC?= =?UTF-8?q?=20=EC=9C=84=ED=95=9C=20yaml=20=ED=8C=8C=EC=9D=BC=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildDockerWindow.sh | 2 +- src/main/resources/application.yaml | 52 +++++++++---------- src/main/resources/yaml/application-dev.yaml | 11 ++++ .../resources/yaml/application-local.yaml | 18 +++++++ 4 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 src/main/resources/yaml/application-dev.yaml create mode 100644 src/main/resources/yaml/application-local.yaml diff --git a/buildDockerWindow.sh b/buildDockerWindow.sh index cbcb728..2380fe7 100755 --- a/buildDockerWindow.sh +++ b/buildDockerWindow.sh @@ -1,4 +1,4 @@ #!/bin/bash -docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.0.7 . +docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.0.9 . diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index ee1d298..acd15bf 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -2,23 +2,31 @@ server: port: 8080 spring: - jpa: - hibernate: - ddl-auto: create - show-sql: true application: name: ComNCheck - datasource: - driver-class-name: org.h2.Driver - url: ${H2_DB_URL:jdbc:h2:mem:test} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode) - username: ${DB_USERNAME} - password: ${DB_PASSWORD} - h2: - console: - enabled: true - path: /h2-console - settings: - web-allow-others: true + config: + import: + - classpath:/yaml/application-dev.yaml + - classpath:/yaml/application-local.yaml + profiles: + group: + setting: local + active : setting + + data: + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASSWORD} + + cloud: + gcp: + storage: + credentials: + location: classpath:ancient-pipe-447417-i4-755ce59fbf03.json + project-id: ${PROJECT_ID} + bucket: ${BUCKET_ID} + security: oauth2: client: @@ -32,18 +40,6 @@ spring: scope: - email - profile - data: - redis: - host: ${REDIS_HOST:localhost} - port: ${REDIS_PORT:6379} - password: ${REDIS_PASSWORD} - cloud: - gcp: - storage: - credentials: - location: classpath:ancient-pipe-447417-i4-755ce59fbf03.json - project-id: ${PROJECT_ID} - bucket: ${BUCKET_ID} jwt: secret: ${JWT_SECRET} - expirationMs: ${JWT_EXPIRATIONMS} \ No newline at end of file + expirationMs: ${JWT_EXPIRATIONMS} diff --git a/src/main/resources/yaml/application-dev.yaml b/src/main/resources/yaml/application-dev.yaml new file mode 100644 index 0000000..2b55aec --- /dev/null +++ b/src/main/resources/yaml/application-dev.yaml @@ -0,0 +1,11 @@ +#spring: +# config: +# on-profile: dev +# datasource: +# driver-class-name: 이름 +# url: 이름 +# username: 관리자이름 +# password: 비밀번호 +# jpa: +# hibernate: +# ddl-auto: none diff --git a/src/main/resources/yaml/application-local.yaml b/src/main/resources/yaml/application-local.yaml new file mode 100644 index 0000000..7f2cc4d --- /dev/null +++ b/src/main/resources/yaml/application-local.yaml @@ -0,0 +1,18 @@ +spring: + config: + on-profile: dev + jpa: + hibernate: + ddl-auto: create + show-sql: true + datasource: + driver-class-name: org.h2.Driver + url: ${H2_DB_URL:jdbc:h2:mem:test} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode) + username: ${H2_DB_USERNAME} + password: ${H2_DB_PASSWORD} + h2: + console: + enabled: true + path: /h2-console + settings: + web-allow-others: true \ No newline at end of file From 18786e2d811d9e2e785ab005a3c0acacb08174e5 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 6 Feb 2025 23:51:38 +0900 Subject: [PATCH 13/67] =?UTF-8?q?Refactor:=20=ED=95=99=EC=83=9D=EC=A6=9D?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EC=97=AC=EB=B6=80=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=BF=A0=ED=82=A4=20=EB=A6=AC=EB=8B=A4=EC=9D=B4?= =?UTF-8?q?=EB=9E=99=ED=8A=B8=20=EC=A1=B0=EC=A0=95:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/infrastructure/FastApiClient.java | 6 +++--- .../member/model/dto/response/MemberDTO.java | 1 + .../domain/member/model/entity/Member.java | 3 ++- .../service/CustomOAuthMemberService.java | 2 +- .../domain/member/service/MemberService.java | 2 +- .../security/config/SecurityConfig.java | 2 +- .../domain/security/filter/JWTFilter.java | 4 ++-- .../handler/CustomSuccessHandler.java | 12 ++++++++++-- .../security/oauth/CustomOAuth2Member.java | 3 +++ src/main/resources/application.yaml | 2 +- .../resources/yaml/application-local.yaml | 1 - src/main/resources/yaml/application-log.yaml | 19 +++++++++++++++++++ 12 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 src/main/resources/yaml/application-log.yaml diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java index 4bc228a..c89d43f 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java @@ -26,9 +26,9 @@ public class FastApiClient { private static final String LOCAL = "http://localhost:8000"; public static final String TEST_DISTRIBUTION = "http://comncheck.iptime.org:8000"; - private static final String FAST_API_URL_OCR= TEST_DISTRIBUTION + "/api/vi/compare-and-ocr"; - private static final String FAST_API_URL_SCRAPE_NOTICE = TEST_DISTRIBUTION + "/api/vi/scrape/notice"; - private static final String Fast_API_URL_EMPLOYMENT = TEST_DISTRIBUTION + "/api/vi/scrape/employment"; + private static final String FAST_API_URL_OCR= TEST_DISTRIBUTION + "/api/v1/compare-and-ocr"; + private static final String FAST_API_URL_SCRAPE_NOTICE = TEST_DISTRIBUTION + "/api/v1/scrape/notice"; + private static final String Fast_API_URL_EMPLOYMENT = TEST_DISTRIBUTION + "/api/v1/scrape/employment"; public FastApiStudentCardDTO sendImage(MultipartFile imageFile) { MultiValueMap body = new LinkedMultiValueMap<>(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java index 828a432..5791b26 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java @@ -17,6 +17,7 @@ public class MemberDTO { private String major; private int studentNumber; private Role role; + private boolean checkStudentCard; public MemberDTO() { } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java index 3622fc0..ac62396 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java @@ -38,7 +38,7 @@ public class Member { @Column(name = "position") private String position; - @Column(name = "is_check_student_card", nullable = false) + @Column(name = "check_student_card", nullable = false) private boolean checkStudentCard; @Builder @@ -57,6 +57,7 @@ public Member(Long memberId, String email, String name, String major, int studen setter code 어노테이션으로 안하고 필요한 경우만 setter 설정 */ + public void setStudentNumber(int studentNumber) { this.studentNumber = studentNumber; } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index 6cfbbba..86a2c23 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -26,7 +26,6 @@ public class CustomOAuthMemberService extends DefaultOAuth2UserService { public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { OAuth2User oAuth2User = super.loadUser(userRequest); - System.out.println( "oAuthUser 정보"+ oAuth2User); String email = oAuth2User.getAttribute("email"); String name = extractName(oAuth2User.getAttribute("name")); String major = extractMajor(oAuth2User.getAttribute("name")); @@ -62,6 +61,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic memberDTO.setMajor(member.getMajor()); memberDTO.setRole(member.getRole()); memberDTO.setStudentNumber(member.getStudentNumber()); + memberDTO.setCheckStudentCard(true); return new CustomOAuth2Member(memberDTO); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java index 4aff515..829a0eb 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java @@ -89,7 +89,7 @@ public MemberInformationResponseDTO getMemberInformation(Long memberId) { } public void logout(HttpServletResponse response) { - Cookie cookie = new Cookie("JWT", null); + Cookie cookie = new Cookie("AccessToken", null); cookie.setPath("/"); cookie.setHttpOnly(true); //cookie.setSecure(true); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 6680e3c..0257ef3 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -37,7 +37,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setMaxAge(3600L); - configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "JWT")); + configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "AccessToken")); return configuration; } })) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java index 0fac515..1b6d978 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java @@ -61,7 +61,7 @@ protected void doFilterInternal(HttpServletRequest request, Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { - if ("JWT".equals(cookie.getName())) { // 쿠키 이름 확인 + if ("AccessToken".equals(cookie.getName())) { // 쿠키 이름 확인 token = cookie.getValue(); logger.debug("Found Authorization cookie: " + token); break; @@ -95,7 +95,7 @@ protected void doFilterInternal(HttpServletRequest request, SecurityContextHolder.getContext().setAuthentication(authToken); logger.debug("SecurityContext set with user: " + username); } else { - logger.debug("No JWT token found in cookies."); + logger.debug("No AccessToken token found in cookies."); } } catch (Exception e) { logger.error("Authentication error: " + e.getMessage()); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index d4fd367..fe6f9af 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -32,11 +32,19 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo Iterator iterator = authorities.iterator(); GrantedAuthority auth = iterator.next(); String role = auth.getAuthority().toString(); + boolean checkStudentCard = customMemberDetails.isCheckStudentCard(); + System.out.println(checkStudentCard); String token = jwtUtil.createJwt(memberId, username, role, 60 * 60 * 1000L); - response.addCookie(createCookie("JWT", token)); - response.sendRedirect("http://localhost:3000/login/first"); + response.addCookie(createCookie("AccessToken", token)); + if(!checkStudentCard) { + response.sendRedirect("http://localhost:3000/login/first"); + } + else { + response.sendRedirect("http://localhost:3000/notice"); + } + //response.sendRedirect("http://localhost:3000/login/first"); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java index 41e541e..232fc4b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java @@ -38,5 +38,8 @@ public String getName() { return memberDTO.getName(); } + public boolean isCheckStudentCard() { + return memberDTO.isCheckStudentCard(); + } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index acd15bf..34321d9 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -10,7 +10,7 @@ spring: - classpath:/yaml/application-local.yaml profiles: group: - setting: local + setting: local, log active : setting data: diff --git a/src/main/resources/yaml/application-local.yaml b/src/main/resources/yaml/application-local.yaml index 7f2cc4d..00e5bef 100644 --- a/src/main/resources/yaml/application-local.yaml +++ b/src/main/resources/yaml/application-local.yaml @@ -4,7 +4,6 @@ spring: jpa: hibernate: ddl-auto: create - show-sql: true datasource: driver-class-name: org.h2.Driver url: ${H2_DB_URL:jdbc:h2:mem:test} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode) diff --git a/src/main/resources/yaml/application-log.yaml b/src/main/resources/yaml/application-log.yaml new file mode 100644 index 0000000..bee3dd2 --- /dev/null +++ b/src/main/resources/yaml/application-log.yaml @@ -0,0 +1,19 @@ +spring: + config: + activate: + on-profile: log + jpa: + properties: + hibernate: + show_sql: true # System.out 방식 로그 + format_sql: true + highlight_sql: true + use_sql_comments: true +#logging: +# level: +# org: +# hibernate: +# SQL: debug # logger 방식 로그 +# orm: +# jdbc: +# bind: trace \ No newline at end of file From f9d26323f6318ca349d11c3dd74c7f6a9f13f0c5 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Fri, 7 Feb 2025 02:32:07 +0900 Subject: [PATCH 14/67] =?UTF-8?q?Feat:=20Google=20Cloud=20SQL=20=EC=84=B8?= =?UTF-8?q?=ED=8C=85=20-=20=EB=B0=B0=ED=8F=AC=EC=9A=A9=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../security/config/SecurityConfig.java | 3 -- src/main/resources/.DS_Store | Bin 0 -> 6148 bytes src/main/resources/application.yaml | 4 +- src/main/resources/yaml/application-dev.yaml | 11 ------ .../resources/yaml/application-local.yaml | 35 +++++++++--------- src/main/resources/yaml/application-log.yaml | 2 +- src/main/resources/yaml/application-prod.yaml | 13 +++++++ 8 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 src/main/resources/.DS_Store delete mode 100644 src/main/resources/yaml/application-dev.yaml create mode 100644 src/main/resources/yaml/application-prod.yaml diff --git a/build.gradle b/build.gradle index c28bbfd..70acae9 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-redis' //implementation 'io.github.cdimascio:java-dotenv:5.2.2' // .env 파일 implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - runtimeOnly 'com.h2database:h2' + runtimeOnly 'mysql:mysql-connector-java:8.0.33' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 0257ef3..01a5fe2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -49,7 +49,6 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .requestMatchers( "/login/**", "/oauth2/**", - "/h2-console/**", "/swagger-ui.html", "/swagger-ui/**", "/V3/api-docs", @@ -72,8 +71,6 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .userService(customOAuth2MemberService)) .successHandler(customSuccessHandler) ); - // H2 Console 관련 헤더 설정 -> 디비 변경 시 제거 - http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin())); http.addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class); diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 H2 DB 연결 주소 (Embedded Mode) - username: ${H2_DB_USERNAME} - password: ${H2_DB_PASSWORD} - h2: - console: - enabled: true - path: /h2-console - settings: - web-allow-others: true \ No newline at end of file +#spring: +# config: +# activate: +# on-profile: local +# jpa: +# hibernate: +# ddl-auto: create +# datasource: +# driver-class-name: org.h2.Driver +# url: ${H2_DB_URL:jdbc:h2:mem:test} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode) +# username: ${H2_DB_USERNAME} +# password: ${H2_DB_PASSWORD} +# h2: +# console: +# enabled: true +# path: /h2-console +# settings: +# web-allow-others: true \ No newline at end of file diff --git a/src/main/resources/yaml/application-log.yaml b/src/main/resources/yaml/application-log.yaml index bee3dd2..90c6bbf 100644 --- a/src/main/resources/yaml/application-log.yaml +++ b/src/main/resources/yaml/application-log.yaml @@ -5,7 +5,7 @@ spring: jpa: properties: hibernate: - show_sql: true # System.out 방식 로그 + #show_sql: true # System.out 방식 로그 format_sql: true highlight_sql: true use_sql_comments: true diff --git a/src/main/resources/yaml/application-prod.yaml b/src/main/resources/yaml/application-prod.yaml new file mode 100644 index 0000000..2bbf799 --- /dev/null +++ b/src/main/resources/yaml/application-prod.yaml @@ -0,0 +1,13 @@ +spring: + config: + activate: + on-profile: prod + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${MYSQL_URL} + username: ${MYSQL_USERNAME} + password: ${MYSQL_PASSWORD} + jpa: + hibernate: + ddl-auto: none + From 20074d5c79aa8b18afd54b5213695121ba5a0281 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 9 Feb 2025 02:38:24 +0900 Subject: [PATCH 15/67] =?UTF-8?q?Feat:=20FCM=20=EA=B8=B0=EB=8A=A5=EC=9D=84?= =?UTF-8?q?=20=EC=9C=84=ED=95=9C=20=EA=B0=81=20=EA=B3=B5=EC=A7=80=EB=B3=84?= =?UTF-8?q?=20=EC=95=8C=EB=9E=8C=20=EB=81=84=EA=B3=A0=20=EC=BC=9C=EB=8A=94?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20Member=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EB=B6=88=EB=A6=AC=EC=96=B8=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=81=84=EA=B3=A0?= =?UTF-8?q?=20=EC=BC=9C=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20+=20FCM=20=EA=B8=B0=EB=8A=A5=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 ++- build.gradle | 2 +- .../domain/fcm/config/FCMConfig.java | 40 +++++++++++++++++ .../member/controller/MemberController.java | 27 +++++++++++ .../domain/member/model/entity/Member.java | 45 ++++++++++++++----- .../domain/member/service/MemberService.java | 39 +++++++++++++++- src/main/resources/application.yaml | 2 +- 7 files changed, 146 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/fcm/config/FCMConfig.java diff --git a/.gitignore b/.gitignore index 8f7b99d..57fd22c 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,7 @@ build/ docker-compose.yaml -/src/main/resources/ancient-pipe-447417-i4-755ce59fbf03.json +#GCP, FIREBASE KEY +/src/main/resources/gcp +/src/main/resources/firebase + diff --git a/build.gradle b/build.gradle index c28bbfd..c77d1b0 100644 --- a/build.gradle +++ b/build.gradle @@ -31,10 +31,10 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' implementation 'org.springframework.boot:spring-boot-starter-data-redis' - //implementation 'io.github.cdimascio:java-dotenv:5.2.2' // .env 파일 implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.h2database:h2' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'com.google.firebase:firebase-admin:8.1.0' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/config/FCMConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/config/FCMConfig.java new file mode 100644 index 0000000..0759894 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/config/FCMConfig.java @@ -0,0 +1,40 @@ +package com.ComNCheck.ComNCheck.domain.fcm.config; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.FirebaseMessaging; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; + +@Configuration +public class FCMConfig { + @Bean + FirebaseMessaging firebaseMessaging() throws IOException { + ClassPathResource resource = new ClassPathResource("firebase/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json"); + + InputStream refreshToken = resource.getInputStream(); + + FirebaseApp firebaseApp = null; + List firebaseAppList = FirebaseApp.getApps(); + + if(firebaseAppList != null && !firebaseAppList.isEmpty()) { + for(FirebaseApp app : firebaseAppList) { + if (app.getName().equals(FirebaseApp.DEFAULT_APP_NAME)) { + firebaseApp = app; + } + } + } + else { + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(refreshToken)) + .build(); + firebaseApp = FirebaseApp.initializeApp(options); + } + return FirebaseMessaging.getInstance(firebaseApp); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java index 21d601f..a43d5ed 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java @@ -56,4 +56,31 @@ public ResponseEntity logout(HttpServletResponse response) { memberService.logout(response); return ResponseEntity.ok("로그아웃 성공"); } + + @PostMapping("/alarm/major/events") + @Operation(summary = "과행사 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.") + public ResponseEntity changeAlarmMajorEvent(Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + memberService.changeAlarmMajorEvent(memberId); + return ResponseEntity.ok("과행사 알람 변경"); + } + + @PostMapping("/alarm/major/noticest") + @Operation(summary = "과행사 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.") + public ResponseEntity changeAlarmMajorNotice(Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + memberService.changeAlarmMajorNotice(memberId); + return ResponseEntity.ok("과행사 알람 변경"); + } + + @PostMapping("/alarm/employment/notices") + @Operation(summary = "과행사 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.") + public ResponseEntity changeAlarmEmploymentNotice(Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + memberService.changeAlarmEmploymentNotice(memberId); + return ResponseEntity.ok("과행사 알람 변경"); + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java index ac62396..b85be3a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java @@ -6,6 +6,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; @Getter @@ -29,6 +30,7 @@ public class Member { private String major; @Column(name = "student_number") + @Setter private int studentNumber; @Column(name = "member_role", nullable = false) @@ -41,6 +43,15 @@ public class Member { @Column(name = "check_student_card", nullable = false) private boolean checkStudentCard; + @Column(name = "alarm_major_event", nullable = false) + private boolean alarmMajorEvent; + + @Column(name = "alarm_major_notice", nullable = false) + private boolean alarmMajorNotice; + + @Column(name = "alarm_employment_notice") + private boolean alarmEmploymentNotice; + @Builder public Member(Long memberId, String email, String name, String major, int studentNumber, Role role) { this.memberId = memberId; @@ -51,24 +62,38 @@ public Member(Long memberId, String email, String name, String major, int studen this.position = null; this.role = role; this.checkStudentCard = false; + this.alarmMajorNotice = false; + this.alarmMajorEvent = false; + this.alarmEmploymentNotice = false; } - /* - setter code - 어노테이션으로 안하고 필요한 경우만 setter 설정 - */ - - public void setStudentNumber(int studentNumber) { - this.studentNumber = studentNumber; - } public void updatePosition(String requestPosition) { this.position = requestPosition; } public void updateRole(Role newRole) { this.role = newRole; } - public void changeIsCheckStudentCard() { - checkStudentCard = true; + public void changeCheckStudentCard() { + this.checkStudentCard = true; + } + public void onAlarmMajorEvent() { + this.alarmMajorEvent = true; } + public void offAlarmMajorEvent() { + this.alarmMajorEvent = false; + } + public void onAlarmMajorNotice() { + this.alarmMajorNotice = true; + } + public void offAlarmMajorNotice() { + this.alarmMajorNotice = false; + } + public void onAlarmEmploymentNotice() { + this.alarmEmploymentNotice = true; + } + public void offAlarmEmploymentNotice() { + this.alarmEmploymentNotice = false; + } + } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java index 829a0eb..6f455de 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java @@ -44,7 +44,7 @@ public MemberInformationResponseDTO registerStudentNumber(Long id, MultipartFile throw new ValidationException("이름 또는 전공이 일치하지 않습니다."); } member.setStudentNumber(studentNumber); - member.changeIsCheckStudentCard(); + member.changeCheckStudentCard(); Member savedMember = memberRepository.save(member); return MemberInformationResponseDTO.of(savedMember); @@ -96,4 +96,41 @@ public void logout(HttpServletResponse response) { cookie.setMaxAge(0); response.addCookie(cookie); } + + @Transactional + public void changeAlarmMajorEvent(Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); + if(member.isAlarmMajorEvent()) { + member.offAlarmMajorEvent(); + } + else { + member.onAlarmMajorEvent(); + } + memberRepository.save(member); + } + + public void changeAlarmMajorNotice(Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); + if(member.isAlarmMajorNotice()) { + member.offAlarmMajorEvent(); + } + else { + member.onAlarmMajorEvent(); + } + memberRepository.save(member); + } + + public void changeAlarmEmploymentNotice(Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); + if(member.isAlarmEmploymentNotice()) { + member.offAlarmMajorEvent(); + } + else { + member.onAlarmMajorEvent(); + } + memberRepository.save(member); + } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 34321d9..19a45c5 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -23,7 +23,7 @@ spring: gcp: storage: credentials: - location: classpath:ancient-pipe-447417-i4-755ce59fbf03.json + location: classpath:/gcp/ancient-pipe-447417-i4-755ce59fbf03.json project-id: ${PROJECT_ID} bucket: ${BUCKET_ID} From 684dee01b637c28fb52e8ea9b12b98b2d81d9ce5 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 9 Feb 2025 14:20:45 +0900 Subject: [PATCH 16/67] =?UTF-8?q?Refactor:=20=EC=95=8C=EB=9E=8C=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B0=8F=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20?= =?UTF-8?q?Operation=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/controller/MemberController.java | 6 +++--- .../ComNCheck/domain/member/service/MemberService.java | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java index a43d5ed..e7e5f1c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java @@ -66,8 +66,8 @@ public ResponseEntity changeAlarmMajorEvent(Authentication authenticatio return ResponseEntity.ok("과행사 알람 변경"); } - @PostMapping("/alarm/major/noticest") - @Operation(summary = "과행사 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.") + @PostMapping("/alarm/major/notices") + @Operation(summary = "과공지 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.") public ResponseEntity changeAlarmMajorNotice(Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); @@ -76,7 +76,7 @@ public ResponseEntity changeAlarmMajorNotice(Authentication authenticati } @PostMapping("/alarm/employment/notices") - @Operation(summary = "과행사 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.") + @Operation(summary = "과 취업정보 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.") public ResponseEntity changeAlarmEmploymentNotice(Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java index 6f455de..4eb5e3b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java @@ -110,26 +110,28 @@ public void changeAlarmMajorEvent(Long memberId) { memberRepository.save(member); } + @Transactional public void changeAlarmMajorNotice(Long memberId) { Member member = memberRepository.findByMemberId(memberId) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); if(member.isAlarmMajorNotice()) { - member.offAlarmMajorEvent(); + member.offAlarmMajorNotice(); } else { - member.onAlarmMajorEvent(); + member.onAlarmMajorNotice(); } memberRepository.save(member); } + @Transactional public void changeAlarmEmploymentNotice(Long memberId) { Member member = memberRepository.findByMemberId(memberId) .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); if(member.isAlarmEmploymentNotice()) { - member.offAlarmMajorEvent(); + member.offAlarmEmploymentNotice(); } else { - member.onAlarmMajorEvent(); + member.onAlarmEmploymentNotice(); } memberRepository.save(member); } From cb9495729b012c9c54ce493647b8efd16d4713b1 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 9 Feb 2025 19:06:55 +0900 Subject: [PATCH 17/67] =?UTF-8?q?Feat:=20FCM=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EA=B0=9C=EB=B0=9C=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?valid=EB=8A=94=20=EC=95=84=EC=A7=81=20=EC=A0=9C=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EC=95=88=EB=90=98=EC=96=B4=EC=9E=88=EC=9D=8C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=ED=95=99=EC=8A=B5=20=ED=9B=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EC=98=88=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 6 +++ buildDockerWindow.sh | 2 +- data/refresh-token-data/dump.rdb | Bin 88 -> 88 bytes .../domain/fcm/controller/FcmController.java | 31 +++++++++++ .../domain/fcm/model/entity/FcmToken.java | 42 +++++++++++++++ .../domain/fcm/repository/FcmRepository.java | 9 ++++ .../domain/fcm/service/FcmService.java | 48 ++++++++++++++++++ .../service/MajorNoticeService.java | 27 ++++++++++ .../domain/member/model/entity/Member.java | 10 ++++ .../member/repository/MemberRepository.java | 1 + src/main/resources/application.yaml | 9 +++- 11 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/fcm/controller/FcmController.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/entity/FcmToken.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/fcm/repository/FcmRepository.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java diff --git a/Dockerfile b/Dockerfile index 9ccc954..5394b6e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,12 @@ FROM openjdk:17 ARG JAR_FILE=build/libs/*.jar COPY ${JAR_FILE} test-app.jar + +COPY src/main/resources/gcp/ancient-pipe-447417-i4-755ce59fbf03.json /app/ancient-pipe-447417-i4-755ce59fbf03.json +ENV GOOGLE_APPLICATION_CREDENTIALS="app/ancient-pipe-447417-i4-755ce59fbf03.json" + +COPY src/main/resources/firebase/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json /app/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json + EXPOSE 8080 CMD ["java", "-Dtest.customName=${CUSTOM_NAME}", "-jar", "test-app.jar"] diff --git a/buildDockerWindow.sh b/buildDockerWindow.sh index 2380fe7..b241fc6 100755 --- a/buildDockerWindow.sh +++ b/buildDockerWindow.sh @@ -1,4 +1,4 @@ #!/bin/bash -docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.0.9 . +docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.1.1 . diff --git a/data/refresh-token-data/dump.rdb b/data/refresh-token-data/dump.rdb index ece464bd7a24cd2d8ccf9b38aa6a1a1da00cf047..eb7cd6f8af715065a7bbe3adea9c874276ad9bdc 100644 GIT binary patch delta 45 zcma!um|&pM=eZ*N7e{GvYKm@dYVM&GANd%5aU|xa=_Vx>rygMVucKcg)wFbfEC8-6 B67m25 delta 45 zcma!um|&oxS-&{_7e{GvYKm@dYVM(ok9-WjI1=;IbdwT`Qx7ow*KLvcc=^%{0|2FM B6MX;x diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/controller/FcmController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/controller/FcmController.java new file mode 100644 index 0000000..eba7348 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/controller/FcmController.java @@ -0,0 +1,31 @@ +package com.ComNCheck.ComNCheck.domain.fcm.controller; + +import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService; +import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/fcm") +public class FcmController { + + private final FcmService fcmTokenService; + + @PostMapping + public ResponseEntity registerToken(@RequestParam String token, + Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + fcmTokenService.registerFcmToken(memberId, token); + return ResponseEntity.ok("토큰 등록 완료"); + } + + + +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/entity/FcmToken.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/entity/FcmToken.java new file mode 100644 index 0000000..e702fa6 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/entity/FcmToken.java @@ -0,0 +1,42 @@ +package com.ComNCheck.ComNCheck.domain.fcm.model.entity; + +import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class FcmToken { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "fcm_token") + private String token; + + @Column(name = "fcm_valid") + private boolean valid = true; + + @Setter + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name ="member_id") + private Member member; + + public FcmToken(String token) { + this.token = token; + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/repository/FcmRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/repository/FcmRepository.java new file mode 100644 index 0000000..fa5e7f8 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/repository/FcmRepository.java @@ -0,0 +1,9 @@ +package com.ComNCheck.ComNCheck.domain.fcm.repository; + +import com.ComNCheck.ComNCheck.domain.fcm.model.entity.FcmToken; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface FcmRepository extends JpaRepository { + Optional findByToken(String token); +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java new file mode 100644 index 0000000..8d1ea40 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java @@ -0,0 +1,48 @@ +package com.ComNCheck.ComNCheck.domain.fcm.service; + +import com.ComNCheck.ComNCheck.domain.fcm.model.entity.FcmToken; +import com.ComNCheck.ComNCheck.domain.fcm.repository.FcmRepository; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.Notification; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class FcmService { + + private final MemberRepository memberRepository; + private final FcmRepository fcmRepository; + + public void sendMessageToToken(String token, String title, String body) throws FirebaseMessagingException { + Message message = Message.builder() + .setToken(token) + .setNotification( + Notification.builder() + .setTitle(title) + .setBody(body) + .build() + ) + .build(); + String response = FirebaseMessaging.getInstance().send(message); + } + @Transactional + public void registerFcmToken(Long memberId, String token) { + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원입니다.")); + + FcmToken existing = fcmRepository.findByToken(token).orElse(null); + if(existing != null) return; // 학습 후 추가 기능 구현해야함 + + FcmToken newFcmToken = new FcmToken(token); + member.addFcmToken(newFcmToken); + + memberRepository.save(member); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java index b2c561b..122c60e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java @@ -1,11 +1,15 @@ package com.ComNCheck.ComNCheck.domain.majorNotice.service; +import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService; import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient; import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.FastAPIMajorNoticesResponseListDTO; import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.PageMajorNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice; import com.ComNCheck.ComNCheck.domain.majorNotice.repository.MajorNoticeRepository; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; +import com.google.firebase.messaging.FirebaseMessagingException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -23,6 +27,8 @@ public class MajorNoticeService { private final FastApiClient fastApiClient; private final MajorNoticeRepository majorNoticeRepository; + private final MemberRepository memberRepository; + private final FcmService fcmService; @Transactional public void syncMajorNotices() { @@ -49,6 +55,27 @@ public void syncMajorNotices() { if(!changeMajorNotices.isEmpty()) { // fcm 기능 구현 System.out.println("알림 전송"); + List members = memberRepository.findByAlarmMajorNoticeTrue(); + + if(!members.isEmpty()) { + String title = "전공 공지사항"; + String body = "새로운 컴퓨터공학부 공지사항 글이 등록되었습니다."; + + for(Member member : members) { + if(!member.getFcmTokens().isEmpty()) { + member.getFcmTokens().forEach(fcmToken -> { + if(fcmToken.isValid() && fcmToken.getToken() != null + && !fcmToken.getToken().isBlank()) { + try { + fcmService.sendMessageToToken(fcmToken.getToken(), title,body); + } catch(FirebaseMessagingException e) { // 예외처리 이후 확인 + System.out.println("전송 실패"); + } + } + }); + } + } + } } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java index b85be3a..a9d2f4c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java @@ -1,6 +1,9 @@ package com.ComNCheck.ComNCheck.domain.member.model.entity; +import com.ComNCheck.ComNCheck.domain.fcm.model.entity.FcmToken; import jakarta.persistence.*; +import java.util.ArrayList; +import java.util.List; import lombok.AccessLevel; import lombok.Builder; @@ -52,6 +55,9 @@ public class Member { @Column(name = "alarm_employment_notice") private boolean alarmEmploymentNotice; + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) + private List fcmTokens = new ArrayList<>(); + @Builder public Member(Long memberId, String email, String name, String major, int studentNumber, Role role) { this.memberId = memberId; @@ -73,6 +79,10 @@ public void updatePosition(String requestPosition) { public void updateRole(Role newRole) { this.role = newRole; } + public void addFcmToken(FcmToken token) { + this.fcmTokens.add(token); + token.setMember(this); + } public void changeCheckStudentCard() { this.checkStudentCard = true; } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java index 1e9dbd3..0d939c2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java @@ -14,5 +14,6 @@ public interface MemberRepository extends JpaRepository { Optional findByRole(Role role); List findAllByRole(Role role); + List findByAlarmMajorNoticeTrue(); } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 19a45c5..979af66 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -24,8 +24,13 @@ spring: storage: credentials: location: classpath:/gcp/ancient-pipe-447417-i4-755ce59fbf03.json - project-id: ${PROJECT_ID} - bucket: ${BUCKET_ID} + project-id: ${GCP_PROJECT_ID} + bucket: ${GCP_BUCKET_ID} + firestore: + project-id: ${FIREBASE_PROJECT_ID} + credentials: + location: classpath:/firebase/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json + security: oauth2: From f7fadb0c313c2ab951af80d38ab26bd8111b8f2f Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Feb 2025 03:00:55 +0900 Subject: [PATCH 18/67] =?UTF-8?q?Feat:=20fcm=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B3=BC=ED=96=89=EC=82=AC=20=EA=B3=B5=EC=A7=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=B7=A8=EC=97=85=20=EA=B3=B5=EC=A7=80=EC=82=AC=ED=95=AD?= =?UTF-8?q?=EC=97=90=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=20+=20?= =?UTF-8?q?=EB=8B=B5=EA=B8=80=EB=8B=AC=EB=A6=AC=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildDockerWindow.sh | 2 +- .../DeveloperQuestionController.java | 4 +++ .../service/EmploymentNoticeService.java | 27 +++++++++++++++++++ .../MissingAuthenticationException.java | 11 ++++++++ .../global/infrastructure/FastApiClient.java | 24 +++++++++++++---- .../majorEvent/service/MajorEventService.java | 25 +++++++++++++++++ .../controller/QuestionController.java | 15 ++++++++--- .../repository/QuestionRepository.java | 1 + .../service/QuestionService.java | 18 +++++++++++++ .../member/repository/MemberRepository.java | 2 ++ .../handler/CustomSuccessHandler.java | 2 +- src/main/resources/application.yaml | 4 +++ 12 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MissingAuthenticationException.java diff --git a/buildDockerWindow.sh b/buildDockerWindow.sh index b241fc6..c942cad 100755 --- a/buildDockerWindow.sh +++ b/buildDockerWindow.sh @@ -1,4 +1,4 @@ #!/bin/bash -docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.1.1 . +docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.1.5 . diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java index 60dbd80..7de32d7 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java @@ -4,6 +4,7 @@ import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.request.DeveloperQuestionRequestDTO; import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.response.DeveloperQuestionResponseDTO; import com.ComNCheck.ComNCheck.domain.developerQuestion.service.DeveloperQuestionService; +import com.ComNCheck.ComNCheck.domain.global.exception.MissingAuthenticationException; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; import io.swagger.v3.oas.annotations.Operation; import java.net.URI; @@ -33,6 +34,9 @@ public ResponseEntity createDeveloperQuestion( @RequestBody DeveloperQuestionRequestDTO requestDTO, Authentication authentication ) { + if (authentication == null) { + throw new MissingAuthenticationException("인증 정보가 필요합니다."); + } CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); DeveloperQuestionResponseDTO createdDTO = developerQuestionService diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java index 5f44b80..454602e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java @@ -5,7 +5,11 @@ import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.PageEmploymentNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice; import com.ComNCheck.ComNCheck.domain.employmentNotice.repository.EmploymentNoticeRepository; +import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService; import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; +import com.google.firebase.messaging.FirebaseMessagingException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -23,6 +27,8 @@ public class EmploymentNoticeService { private final EmploymentNoticeRepository employmentNoticeRepository; private final FastApiClient fastApiClient; + private final MemberRepository memberRepository; + private final FcmService fcmService; @Transactional public void syncEmploymentNotices() { @@ -50,6 +56,27 @@ public void syncEmploymentNotices() { if (!changeEmploymentNotices.isEmpty()) { // fcm 기능 구현 System.out.println("알림 전송"); + List members = memberRepository.findByAlarmEmploymentNoticeTrue(); + + if(!members.isEmpty()) { + String title = "취업 공지사항"; + String body = "새로운 컴퓨터공학부 취업 글이 등록되었습니다."; + + for(Member member : members) { + if(!member.getFcmTokens().isEmpty()) { + member.getFcmTokens().forEach(fcmToken -> { + if(fcmToken.isValid() && fcmToken.getToken() != null + && !fcmToken.getToken().isBlank()) { + try { + fcmService.sendMessageToToken(fcmToken.getToken(), title,body); + } catch(FirebaseMessagingException e) { // 예외처리 이후 확인 + System.out.println("전송 실패"); + } + } + }); + } + } + } } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MissingAuthenticationException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MissingAuthenticationException.java new file mode 100644 index 0000000..aa3e032 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MissingAuthenticationException.java @@ -0,0 +1,11 @@ +package com.ComNCheck.ComNCheck.domain.global.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.BAD_REQUEST) +public class MissingAuthenticationException extends RuntimeException { + public MissingAuthenticationException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java index c89d43f..d49333d 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java @@ -4,8 +4,10 @@ import com.ComNCheck.ComNCheck.domain.global.exception.FastApiException; import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.FastAPIMajorNoticesResponseListDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO; +import jakarta.annotation.PostConstruct; import java.io.IOException; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ByteArrayResource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; @@ -18,17 +20,29 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import org.springframework.http.HttpHeaders; + @Component @RequiredArgsConstructor public class FastApiClient { private final RestTemplate restTemplate; private static final String LOCAL = "http://localhost:8000"; - public static final String TEST_DISTRIBUTION = "http://comncheck.iptime.org:8000"; - - private static final String FAST_API_URL_OCR= TEST_DISTRIBUTION + "/api/v1/compare-and-ocr"; - private static final String FAST_API_URL_SCRAPE_NOTICE = TEST_DISTRIBUTION + "/api/v1/scrape/notice"; - private static final String Fast_API_URL_EMPLOYMENT = TEST_DISTRIBUTION + "/api/v1/scrape/employment"; + private static final String TEST_DISTRIBUTION = "http://comncheck.iptime.org:8000"; + @Value("${target.server.ip}") + private String PROD_FASTAPI_IP; + + private String PROD_FASTAPI; + private String FAST_API_URL_OCR; + private String FAST_API_URL_SCRAPE_NOTICE; + private String Fast_API_URL_EMPLOYMENT; + + @PostConstruct + public void init() { + PROD_FASTAPI = "http://" + PROD_FASTAPI_IP; + FAST_API_URL_OCR= PROD_FASTAPI + "/api/v1/compare-and-ocr"; + FAST_API_URL_SCRAPE_NOTICE = PROD_FASTAPI + "/api/v1/scrape/notice"; + Fast_API_URL_EMPLOYMENT = PROD_FASTAPI + "/api/v1/scrape/employment"; + } public FastApiStudentCardDTO sendImage(MultipartFile imageFile) { MultiValueMap body = new LinkedMultiValueMap<>(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java index 0052a19..6ff51f4 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java @@ -1,5 +1,6 @@ package com.ComNCheck.ComNCheck.domain.majorEvent.service; +import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventCreateRequestDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventUpdateRequestDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.EventListResponseDTO; @@ -11,6 +12,7 @@ import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; import com.google.cloud.storage.Storage; import com.google.cloud.storage.BlobInfo; +import com.google.firebase.messaging.FirebaseMessagingException; import java.io.IOException; import java.time.LocalDate; import java.time.LocalTime; @@ -32,6 +34,7 @@ public class MajorEventService { private final MajorEventRepository majorEventRepository; private final MemberRepository memberRepository; + private final FcmService fcmService; @Value("${spring.cloud.gcp.storage.bucket}") private String bucketName; private final Storage storage; @@ -59,6 +62,28 @@ public EventResponseDTO createMajorEvent(EventCreateRequestDTO requestDTO, Long .build(); MajorEvent savedMajorEvent = majorEventRepository.save(majorEvent); + + List members = memberRepository.findByAlarmMajorEventTrue(); + + if(!members.isEmpty()) { + String title = "공지사항"; + String body = "새로운 과행사 글이 등록되었습니다."; + + for(Member member : members) { + if(!member.getFcmTokens().isEmpty()) { + member.getFcmTokens().forEach(fcmToken -> { + if(fcmToken.isValid() && fcmToken.getToken() != null + && !fcmToken.getToken().isBlank()) { + try { + fcmService.sendMessageToToken(fcmToken.getToken(), title,body); + } catch(FirebaseMessagingException e) { + System.out.println("전송 실패"); + } + } + }); + } + } + } return EventResponseDTO.of(savedMajorEvent); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java index c10b242..c901901 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java @@ -45,16 +45,16 @@ public ResponseEntity createQuestion(@RequestBody QuestionR } @GetMapping("/{majorQuestionId}") - @Operation(summary = "fAQ 특정 게시글 조회", description = "FAQ의 특정 게시글을 클릭했을 때 자세히 볼 수 있다") + @Operation(summary = "FAQ 특정 게시글 조회", description = "FAQ의 특정 게시글을 클릭했을 때 자세히 볼 수 있다") public ResponseEntity getQuestion(@PathVariable Long majorQuestionId) { QuestionResponseDTO responseDTO = questionService.getQuestion(majorQuestionId); return ResponseEntity.ok(responseDTO); } @GetMapping - @Operation(summary = "fAQ의 답변이 달린 게시글 목록 조회 공유가 true 인 경우만" + @Operation(summary = "FAQ의 답변이 달린 게시글 목록 조회 공유가 true 인 경우만" , description = "댓글이 달린 모든 게시글 목록을 조회한다.") - public ResponseEntity> getAllQuestion() { + public ResponseEntity> getAnsweredAllQuestions() { List questions = questionService.getQuestionsWithAnswer(); return ResponseEntity.ok(questions); } @@ -88,5 +88,14 @@ public ResponseEntity deleteQuestion(@PathVariable Long majorQuestionId, A return ResponseEntity.noContent().build(); } + @GetMapping("/all/unanswerd") + @Operation(summary = "FAQ 답변이 달리지 않는 게시글 목록 조회", description = "답변을 아직 하지 않느니 게시글 목록을 조회한다.") + public ResponseEntity> getUnansweredAllQuestions(Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + List questions = questionService.getUnanswerdAllQuestion(memberId); + return ResponseEntity.ok(questions); + + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java index 0aae3eb..e270d01 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java @@ -10,4 +10,5 @@ public interface QuestionRepository extends JpaRepository { List findByAnswerIsNotNull(); Optional findByIdAndSharedTrue(Long id); List findByAnswerIsNotNullAndSharedTrue(); + List findByAnswerIsNull(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index e96f5be..628a8e2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -2,6 +2,7 @@ import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; import com.ComNCheck.ComNCheck.domain.global.exception.UnauthorizedException; import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.QuestionRequestDTO; @@ -81,4 +82,21 @@ public List getMyQuestions(Long writerId) { .map(QuestionResponseDTO::of) .toList(); } + + public List getUnanswerdAllQuestion(Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다.")); + isCheckRole(member); + return questionRepository.findByAnswerIsNull() + .stream() + .map(QuestionResponseDTO::of) + .toList(); + } + + public void isCheckRole(Member member) { + Role checkRole = member.getRole(); + if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) { + throw new IllegalArgumentException("접근 권한이 없습니다."); + } + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java index 0d939c2..f1f025e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java @@ -15,5 +15,7 @@ public interface MemberRepository extends JpaRepository { List findAllByRole(Role role); List findByAlarmMajorNoticeTrue(); + List findByAlarmEmploymentNoticeTrue(); + List findByAlarmMajorEventTrue(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index fe6f9af..18af0dc 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -35,7 +35,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo boolean checkStudentCard = customMemberDetails.isCheckStudentCard(); System.out.println(checkStudentCard); - String token = jwtUtil.createJwt(memberId, username, role, 60 * 60 * 1000L); + String token = jwtUtil.createJwt(memberId, username, role, 365L * 24 * 60 * 60 * 1000); // 60 * 60 * 1000L response.addCookie(createCookie("AccessToken", token)); if(!checkStudentCard) { diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 979af66..d164b6e 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -48,3 +48,7 @@ spring: jwt: secret: ${JWT_SECRET} expirationMs: ${JWT_EXPIRATIONMS} + +target: + server: + ip: ${PROD_FASTAPI_IP} From c3855c37742e14230945ba40cef349b390e0b899 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Feb 2025 03:35:14 +0900 Subject: [PATCH 19/67] =?UTF-8?q?Refactor=20:=20JWTFilter=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=88=98=EC=A0=95=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=95=88=EB=90=90=EB=8B=A4=EB=8A=94=20200?= =?UTF-8?q?=20=EB=8C=80=EC=8B=A0=20=EA=B0=81=EA=B0=81=EC=9D=98=20=EC=83=81?= =?UTF-8?q?=ED=99=A9=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/QuestionService.java | 1 + .../domain/security/filter/JWTFilter.java | 74 +++++++++++-------- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index 628a8e2..9879583 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -83,6 +83,7 @@ public List getMyQuestions(Long writerId) { .toList(); } + @Transactional public List getUnanswerdAllQuestion(Long memberId) { Member member = memberRepository.findByMemberId(memberId) .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다.")); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java index 1b6d978..f920e9f 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java @@ -2,9 +2,9 @@ import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberDTO; import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; -import com.ComNCheck.ComNCheck.domain.security.exception.TokenExpiredException; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; import com.ComNCheck.ComNCheck.domain.security.util.JWTUtil; +import io.jsonwebtoken.ExpiredJwtException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.Cookie; @@ -12,13 +12,13 @@ import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.AntPathMatcher; import org.springframework.web.filter.OncePerRequestFilter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @RequiredArgsConstructor public class JWTFilter extends OncePerRequestFilter { @@ -61,45 +61,59 @@ protected void doFilterInternal(HttpServletRequest request, Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { - if ("AccessToken".equals(cookie.getName())) { // 쿠키 이름 확인 + if ("AccessToken".equals(cookie.getName())) { token = cookie.getValue(); - logger.debug("Found Authorization cookie: " + token); + logger.debug("AccessToken 쿠키를 찾았습니다: " + token); break; } } } try { - if (token != null) { - if (jwtUtil.isExpired(token)) { - throw new TokenExpiredException("만료된 토큰입니다."); - } + if (token == null || token.trim().isEmpty()) { + logger.error("AccessToken 쿠키가 존재하지 않습니다."); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json;charset=UTF-8"); + response.setCharacterEncoding("UTF-8"); + response.getWriter().write("{\"error\": \"MISSING_TOKEN\", \"message\": \"AccessToken 쿠키가 존재하지 않습니다.\"}"); + response.getWriter().flush(); + return; + } - String username = jwtUtil.getUsername(token); - Long id = jwtUtil.getId(token); - Role role = jwtUtil.getRole(token); + String username = jwtUtil.getUsername(token); + Long id = jwtUtil.getId(token); + Role role = jwtUtil.getRole(token); - MemberDTO memberDTO = new MemberDTO(); - memberDTO.setMemberId(id); - memberDTO.setName(username); - memberDTO.setRole(role); + MemberDTO memberDTO = new MemberDTO(); + memberDTO.setMemberId(id); + memberDTO.setName(username); + memberDTO.setRole(role); - CustomOAuth2Member customOAuth2Member = new CustomOAuth2Member(memberDTO); + CustomOAuth2Member customOAuth2Member = new CustomOAuth2Member(memberDTO); - Authentication authToken = - new UsernamePasswordAuthenticationToken( - customOAuth2Member, - null, - customOAuth2Member.getAuthorities() - ); - SecurityContextHolder.getContext().setAuthentication(authToken); - logger.debug("SecurityContext set with user: " + username); - } else { - logger.debug("No AccessToken token found in cookies."); - } + Authentication authToken = new UsernamePasswordAuthenticationToken( + customOAuth2Member, + null, + customOAuth2Member.getAuthorities() + ); + SecurityContextHolder.getContext().setAuthentication(authToken); + logger.debug("SecurityContext에 사용자 정보를 설정했습니다: " + username); + + } catch (ExpiredJwtException e) { + logger.error("토큰 만료: " + e.getMessage()); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json;charset=UTF-8"); + response.setCharacterEncoding("UTF-8"); + response.getWriter().write("{\"error\": \"TOKEN_EXPIRED\", \"message\": \"" + e.getMessage() + "\"}"); + response.getWriter().flush(); + return; } catch (Exception e) { - logger.error("Authentication error: " + e.getMessage()); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); + logger.error("인증 오류: " + e.getMessage()); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json;charset=UTF-8"); + response.setCharacterEncoding("UTF-8"); + response.getWriter().write("{\"error\": \"AUTHENTICATION_ERROR\", \"message\": \"" + e.getMessage() + "\"}"); + response.getWriter().flush(); return; } From 9de0175fa8598358bd06a37c25049231e5e7db7d Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Feb 2025 22:40:04 +0900 Subject: [PATCH 20/67] =?UTF-8?q?Fix=20:=20=ED=95=99=EC=83=9D=EC=A6=9D=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EC=95=88=ED=95=B4=EB=8F=84=20true=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildDockerWindow.sh | 2 +- .../member/model/dto/response/MemberDTO.java | 13 +++++++++++++ .../response/MemberInformationResponseDTO.java | 6 ++++++ .../service/CustomOAuthMemberService.java | 18 +++++++++--------- .../security/handler/CustomSuccessHandler.java | 2 +- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/buildDockerWindow.sh b/buildDockerWindow.sh index c942cad..4774e5f 100755 --- a/buildDockerWindow.sh +++ b/buildDockerWindow.sh @@ -1,4 +1,4 @@ #!/bin/bash -docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.1.5 . +docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.1.9 . diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java index 5791b26..f794d96 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java @@ -9,6 +9,7 @@ @Getter @Setter +@Builder @AllArgsConstructor public class MemberDTO { private Long memberId; @@ -22,4 +23,16 @@ public class MemberDTO { public MemberDTO() { } + public static MemberDTO of(Member member) { + return MemberDTO.builder() + .memberId(member.getMemberId()) + .email(member.getEmail()) + .name(member.getName()) + .major(member.getMajor()) + .studentNumber(member.getStudentNumber()) + .role(member.getRole()) + .checkStudentCard(member.isCheckStudentCard()) + .build(); + } + } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java index 230efae..2c5727f 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java @@ -16,6 +16,9 @@ public class MemberInformationResponseDTO { private int studentNumber; private Role role; private boolean checkStudentCard; + private boolean alarmMajorEvent; + private boolean alarmMajorNotice; + private boolean alarmEmploymentNotice; public static MemberInformationResponseDTO of(Member member) { return MemberInformationResponseDTO.builder() .memberId(member.getMemberId()) @@ -24,6 +27,9 @@ public static MemberInformationResponseDTO of(Member member) { .studentNumber(member.getStudentNumber()) .role(member.getRole()) .checkStudentCard(member.isCheckStudentCard()) + .alarmMajorEvent(member.isAlarmMajorEvent()) + .alarmMajorNotice(member.isAlarmMajorNotice()) + .alarmEmploymentNotice(member.isAlarmEmploymentNotice()) .build(); } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index 86a2c23..d4966e6 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -54,15 +54,15 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic return newMember; }); - MemberDTO memberDTO = new MemberDTO(); - memberDTO.setMemberId(member.getMemberId()); - memberDTO.setEmail(member.getEmail()); - memberDTO.setName(member.getName()); - memberDTO.setMajor(member.getMajor()); - memberDTO.setRole(member.getRole()); - memberDTO.setStudentNumber(member.getStudentNumber()); - memberDTO.setCheckStudentCard(true); - return new CustomOAuth2Member(memberDTO); +// MemberDTO memberDTO = new MemberDTO(); +// memberDTO.setMemberId(member.getMemberId()); +// memberDTO.setEmail(member.getEmail()); +// memberDTO.setName(member.getName()); +// memberDTO.setMajor(member.getMajor()); +// memberDTO.setRole(member.getRole()); +// memberDTO.setStudentNumber(member.getStudentNumber()); +// memberDTO.setCheckStudentCard(member.isCheckStudentCard()); + return new CustomOAuth2Member(MemberDTO.of(member)); } private String cleanString(String input) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index 18af0dc..6956ac2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -35,7 +35,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo boolean checkStudentCard = customMemberDetails.isCheckStudentCard(); System.out.println(checkStudentCard); - String token = jwtUtil.createJwt(memberId, username, role, 365L * 24 * 60 * 60 * 1000); // 60 * 60 * 1000L + String token = jwtUtil.createJwt(memberId, username, role, 365L * 24 * 60 * 60 * 1000); // 60 * 60 * 1000L response.addCookie(createCookie("AccessToken", token)); if(!checkStudentCard) { From e598ebe32aa670e8d49b8f435e4c10be306a5220 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Feb 2025 23:21:51 +0900 Subject: [PATCH 21/67] =?UTF-8?q?Feat:=20MemberDTO=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=EB=A1=9C=20Setting=20=ED=96=88=EB=8D=98=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/service/CustomOAuthMemberService.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index d4966e6..7fe4f88 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -54,14 +54,6 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic return newMember; }); -// MemberDTO memberDTO = new MemberDTO(); -// memberDTO.setMemberId(member.getMemberId()); -// memberDTO.setEmail(member.getEmail()); -// memberDTO.setName(member.getName()); -// memberDTO.setMajor(member.getMajor()); -// memberDTO.setRole(member.getRole()); -// memberDTO.setStudentNumber(member.getStudentNumber()); -// memberDTO.setCheckStudentCard(member.isCheckStudentCard()); return new CustomOAuth2Member(MemberDTO.of(member)); } From 53c1cd1eafc375f3d064f71ffe9fb96f50837046 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Wed, 12 Feb 2025 00:04:46 +0900 Subject: [PATCH 22/67] =?UTF-8?q?Merge:=20develop=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=B3=91=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ buildDockerWindow.sh | 2 +- src/main/resources/yaml/application-prod.yaml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 57fd22c..ab47ae6 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,5 @@ docker-compose.yaml /src/main/resources/gcp /src/main/resources/firebase +data/ +gradle/ diff --git a/buildDockerWindow.sh b/buildDockerWindow.sh index 4774e5f..4c112e4 100755 --- a/buildDockerWindow.sh +++ b/buildDockerWindow.sh @@ -1,4 +1,4 @@ #!/bin/bash -docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.1.9 . +docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.2.1 . diff --git a/src/main/resources/yaml/application-prod.yaml b/src/main/resources/yaml/application-prod.yaml index 2bbf799..f70ef20 100644 --- a/src/main/resources/yaml/application-prod.yaml +++ b/src/main/resources/yaml/application-prod.yaml @@ -9,5 +9,5 @@ spring: password: ${MYSQL_PASSWORD} jpa: hibernate: - ddl-auto: none + ddl-auto: update From 934a7b14212203103433734cc42858d668043b33 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Wed, 12 Feb 2025 00:27:35 +0900 Subject: [PATCH 23/67] =?UTF-8?q?Refactor=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=B3=80=EA=B2=BD=20=EC=A7=84=ED=96=89=20=EC=A4=91?= =?UTF-8?q?=20=EA=B6=8C=ED=95=9C=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?403?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ data/refresh-token-data/dump.rdb | Bin 88 -> 0 bytes gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 7 ------- .../service/DeveloperQuestionService.java | 7 ++++--- ...edException.java => ForbiddenException.java} | 7 +++---- .../majorEvent/service/MajorEventService.java | 4 ++-- .../majorQuestion/service/AnswerService.java | 3 ++- .../majorQuestion/service/QuestionService.java | 6 +++--- 9 files changed, 16 insertions(+), 20 deletions(-) delete mode 100644 data/refresh-token-data/dump.rdb delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties rename src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/{UnauthorizedException.java => ForbiddenException.java} (66%) diff --git a/.gitignore b/.gitignore index 57fd22c..ab47ae6 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,5 @@ docker-compose.yaml /src/main/resources/gcp /src/main/resources/firebase +data/ +gradle/ diff --git a/data/refresh-token-data/dump.rdb b/data/refresh-token-data/dump.rdb deleted file mode 100644 index eb7cd6f8af715065a7bbe3adea9c874276ad9bdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c8..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java index a0c4a48..6f95d44 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java @@ -1,6 +1,7 @@ package com.ComNCheck.ComNCheck.domain.developerQuestion.service; +import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; import com.ComNCheck.ComNCheck.domain.member.exception.MemberNotFoundException; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; @@ -8,7 +9,7 @@ import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.response.DeveloperQuestionResponseDTO; import com.ComNCheck.ComNCheck.domain.developerQuestion.model.entity.DeveloperQuestion; import com.ComNCheck.ComNCheck.domain.developerQuestion.repository.DeveloperQuestionRepository; -import com.ComNCheck.ComNCheck.domain.global.exception.UnauthorizedException; + import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -56,7 +57,7 @@ public DeveloperQuestionResponseDTO updateDeveloperQuestion(Long developerQuesti .orElseThrow(() -> new IllegalArgumentException("질문글을 찾을 수 없습니다.")); if(!developerQuestion.getWriter().getMemberId().equals(writerId)) - throw new UnauthorizedException("게시글 작성자가 아닙니다."); + throw new ForbiddenException("게시글 작성자가 아닙니다."); developerQuestion.updateDeveloperQuestion(requestDTO.getContent()); return DeveloperQuestionResponseDTO.of(developerQuestion); @@ -68,7 +69,7 @@ public void deleteDeveloperQuestion(Long developerQuestionId, Long writerId) { .orElseThrow(() -> new IllegalArgumentException("질문글을 찾을 수 없습니다.")); if(!developerQuestion.getWriter().getMemberId().equals(writerId)) - throw new UnauthorizedException("게시글 작성자가 아닙니다."); + throw new ForbiddenException("게시글 작성자가 아닙니다."); developerQuestionRepository.delete(developerQuestion); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/UnauthorizedException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java similarity index 66% rename from src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/UnauthorizedException.java rename to src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java index c15755a..48b59fd 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/UnauthorizedException.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java @@ -3,10 +3,9 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; - @ResponseStatus(HttpStatus.FORBIDDEN) -public class UnauthorizedException extends RuntimeException { - public UnauthorizedException(String message) { +public class ForbiddenException extends RuntimeException { + public ForbiddenException(String message) { super(message); } -} +} \ No newline at end of file diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java index 6ff51f4..af01690 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java @@ -1,6 +1,7 @@ package com.ComNCheck.ComNCheck.domain.majorEvent.service; import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService; +import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventCreateRequestDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventUpdateRequestDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.EventListResponseDTO; @@ -189,8 +190,7 @@ private boolean isNotPassed(MajorEvent majorEvent, LocalDate today, LocalTime cu public void isCheckRole(Member member) { Role checkRole = member.getRole(); if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) { - System.out.println("접근 권한이 없음"); - throw new IllegalArgumentException("접근 권한이 없습니다."); + throw new ForbiddenException("접근 권한이 없습니다."); } } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java index e65bc62..7306f89 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java @@ -1,5 +1,6 @@ package com.ComNCheck.ComNCheck.domain.majorQuestion.service; +import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; @@ -74,7 +75,7 @@ public void deleteAnswer(Long answerId, Long memberId) { public void isCheckRole(Member member) { Role checkRole = member.getRole(); if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) { - throw new IllegalArgumentException("접근 권한이 없습니다."); + throw new ForbiddenException("접근 권한이 없습니다."); } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index 9879583..96d8e21 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -1,10 +1,10 @@ package com.ComNCheck.ComNCheck.domain.majorQuestion.service; +import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; -import com.ComNCheck.ComNCheck.domain.global.exception.UnauthorizedException; import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.QuestionRequestDTO; import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.QuestionResponseDTO; import com.ComNCheck.ComNCheck.domain.majorQuestion.model.entity.Question; @@ -58,7 +58,7 @@ public QuestionResponseDTO updateQuestion(Long questionId, QuestionRequestDTO re .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); if (!question.getWriter().getMemberId().equals(writerId)) { - throw new UnauthorizedException("작성자가 아닙니다."); + throw new ForbiddenException("작성자가 아닙니다."); } question.updateQuestion(requestDTO.getTitle(), requestDTO.getContent()); @@ -71,7 +71,7 @@ public void deleteQuestion(Long questionId, Long writerId) { .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); if(!question.getWriter().getMemberId().equals(writerId)) { - throw new UnauthorizedException("작성자가 아닙니다."); + throw new ForbiddenException("작성자가 아닙니다."); } questionRepository.delete(question); } From 13c8f67237e7cd6cc24a17cdd6fc0c83ad1c46b3 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Wed, 12 Feb 2025 01:34:35 +0900 Subject: [PATCH 24/67] =?UTF-8?q?Feat:=20GCS=EC=97=90=20=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 743a7bc..7afd08a 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ dependencies { implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' implementation group: 'com.google.cloud', name: 'spring-cloud-gcp-starter', version: '6.0.0' implementation group: 'com.google.cloud', name: 'spring-cloud-gcp-storage', version: '6.0.0' + implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '4.29.3' } tasks.named('test') { From dd72da73deb03e7f01676791a0b20e6e50013d71 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Wed, 12 Feb 2025 07:52:36 +0900 Subject: [PATCH 25/67] =?UTF-8?q?=20Refactor:=20=ED=95=99=EC=83=9D?= =?UTF-8?q?=ED=9A=8C=20=EC=8B=A0=EC=B2=AD=20API=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=EC=82=AC=ED=95=AD=EC=97=90=20=EC=9D=98?= =?UTF-8?q?=ED=95=9C=20PUT=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=EC=97=90=20=EC=83=81=ED=83=9C=20=EB=B3=B4=EC=97=AC?= =?UTF-8?q?=EC=A3=BC=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../controller/RoleChangeController.java | 24 +------------------ .../model/dto/response/RoleChangeListDTO.java | 3 +++ .../service/RoleChangeRequestService.java | 17 ------------- 4 files changed, 5 insertions(+), 40 deletions(-) diff --git a/build.gradle b/build.gradle index c77d1b0..b532281 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ dependencies { implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' implementation group: 'com.google.cloud', name: 'spring-cloud-gcp-starter', version: '6.0.0' implementation group: 'com.google.cloud', name: 'spring-cloud-gcp-storage', version: '6.0.0' + implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '4.29.3' } tasks.named('test') { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java index 35bc8fa..386e43a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java @@ -44,7 +44,7 @@ public ResponseEntity createRoleChangeRequest( } @GetMapping - @Operation(summary = "학새회 등급 신청 목록 조회", description = "학생회 등급 신청 목록을 조회한다.") + @Operation(summary = "학생회 등급 신청 목록 조회", description = "학생회 등급 신청 목록을 조회한다.") public ResponseEntity> getAllRequest(Authentication authentication) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); @@ -73,28 +73,6 @@ public ResponseEntity approveRequest(@PathVariable Long requestId return ResponseEntity.ok("승인완료"); } - - @GetMapping("/approved") - @Operation(summary = "승인된 학생회 등급 신청 목록 조회", description = "승인된 학생회 등급 신청 목록을 조회한다.") - public ResponseEntity> getApprovedRequests(Authentication authentication) { - CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); - Long memberId = principal.getMemberDTO().getMemberId(); - List approvedList = roleChangeRequestService.getApproveRequests(memberId); - return ResponseEntity.ok(approvedList); - } - - @PutMapping("/{requestId}/change-role") - @Operation(summary = "특정 학생회 등급 조정", description = "승인된 학생회 등급 신청에서 등급을 조정한다.") - public ResponseEntity changeMemberRole( - @PathVariable Long requestId, @RequestBody RoleChangeRequestDTO requestDTO, - Authentication authentication - ) { - CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); - Long memberId = principal.getMemberDTO().getMemberId(); - roleChangeRequestService.changeMemberRole(requestId, requestDTO, memberId); - return ResponseEntity.ok("등급 재변경 완료"); - } - @DeleteMapping("/{requestId}") @Operation(summary = "특정 학생회 등급 신청 요청 삭제", description = "요청온 학생회 등급 신청 요청을 삭제한다.") public ResponseEntity deleteRequest(@PathVariable Long requestId, diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeListDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeListDTO.java index 23ee679..884b2fb 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeListDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeListDTO.java @@ -1,6 +1,7 @@ package com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response; +import com.ComNCheck.ComNCheck.domain.roleChange.model.entity.RequestStatus; import com.ComNCheck.ComNCheck.domain.roleChange.model.entity.RoleChange; import lombok.Builder; import lombok.Getter; @@ -12,12 +13,14 @@ public class RoleChangeListDTO { private Long requestId; private String name; private String requestPosition; + private RequestStatus status; public static RoleChangeListDTO of(RoleChange roleChange) { return RoleChangeListDTO.builder() .requestId(roleChange.getRequestId()) .name(roleChange.getMember().getName()) .requestPosition(roleChange.getRequestPosition()) + .status(roleChange.getStatus()) .build(); } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java index df7b568..24cd594 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java @@ -91,23 +91,6 @@ public List getApproveRequests(Long memberId) { .collect(Collectors.toList()); } - @Transactional - public void changeMemberRole(Long requestId, RoleChangeRequestDTO requestDTO, Long memberId) { - RoleChange request = roleChangeRequestRepository.findById(requestId) - .orElseThrow(() -> new IllegalArgumentException("요청이 없습니다.")); - - if(request.getStatus() != RequestStatus.APPROVED) { - throw new IllegalArgumentException("한번 변경된 요청만 수정 가능합니다."); - } - - Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); - isCheckRole(member); - - Member updateMember = request.getMember(); - updateMember.updateRole(requestDTO.getRequestRole()); - updateMember.updatePosition(requestDTO.getRequestPosition()); - } @Transactional public void deleteRequest(Long requestId, Long memberId) { From 49f7728f291e5d8b533ff910d3bd3eb4fe67e090 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Wed, 12 Feb 2025 08:46:03 +0900 Subject: [PATCH 26/67] =?UTF-8?q?=20Merge=20=ED=95=99=EC=83=9D=ED=9A=8C=20?= =?UTF-8?q?=EC=8B=A0=EC=B2=AD=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20?= =?UTF-8?q?=EB=B3=80=EB=8F=99=20=EB=B3=91=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ buildDockerWindow.sh | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) delete mode 100755 buildDockerWindow.sh diff --git a/.gitignore b/.gitignore index ab47ae6..9836877 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,5 @@ docker-compose.yaml data/ gradle/ + +buildDockerWindow.sh diff --git a/buildDockerWindow.sh b/buildDockerWindow.sh deleted file mode 100755 index 4c112e4..0000000 --- a/buildDockerWindow.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -docker buildx build --platform linux/amd64 -t comncheck/spring-backend-oauth:1.2.1 . - From 0c050500cebb49d2f63540cbfcd31f9cb456f316 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Wed, 12 Feb 2025 09:01:33 +0900 Subject: [PATCH 27/67] =?UTF-8?q?Feat:=20=ED=95=99=EB=B6=80=20=EC=A7=88?= =?UTF-8?q?=EB=AC=B8=20=EC=A0=84=EC=B2=B4=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../majorQuestion/controller/QuestionController.java | 11 +++++++++++ .../domain/majorQuestion/service/QuestionService.java | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java index c901901..47ede8e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java @@ -44,6 +44,17 @@ public ResponseEntity createQuestion(@RequestBody QuestionR return ResponseEntity.created(location).body(responseDTO); } + @GetMapping("/all") + @Operation(summary = "FAQ 모든 게시글 - 학생회만 열람 가능", description = "댓글 작성 여부, 공개 여부오 상관없는 모든 질문들") + public ResponseEntity> getAllQuestion( + Authentication authentication + ) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + List questions = questionService.getAllQuestion(memberId); + return ResponseEntity.ok(questions); + } + @GetMapping("/{majorQuestionId}") @Operation(summary = "FAQ 특정 게시글 조회", description = "FAQ의 특정 게시글을 클릭했을 때 자세히 볼 수 있다") public ResponseEntity getQuestion(@PathVariable Long majorQuestionId) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index 96d8e21..9e73c45 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -38,6 +38,17 @@ public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO, Long me return QuestionResponseDTO.of(saveQuestion); } + public List getAllQuestion(Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다.")); + isCheckRole(member); + + return questionRepository.findAll() + .stream() + .map(QuestionResponseDTO::of) + .toList(); + } + public QuestionResponseDTO getQuestion(Long questionId) { Question question = questionRepository.findById(questionId) .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); From 2db9c677af8cbd27f03803be153042c4b42daadb Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 13 Feb 2025 00:22:31 +0900 Subject: [PATCH 28/67] =?UTF-8?q?Feat:=20=EB=82=B4=EA=B0=80=20=EC=93=B4=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C=EC=9E=90=20=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 4 ++-- .../controller/DeveloperQuestionController.java | 11 +++++++++++ .../repository/DeveloperQuestionRepository.java | 4 +++- .../service/DeveloperQuestionService.java | 10 ++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5394b6e..bf87811 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM openjdk:17 ARG JAR_FILE=build/libs/*.jar -COPY ${JAR_FILE} test-app.jar +COPY ${JAR_FILE} prod.jar COPY src/main/resources/gcp/ancient-pipe-447417-i4-755ce59fbf03.json /app/ancient-pipe-447417-i4-755ce59fbf03.json ENV GOOGLE_APPLICATION_CREDENTIALS="app/ancient-pipe-447417-i4-755ce59fbf03.json" @@ -8,5 +8,5 @@ ENV GOOGLE_APPLICATION_CREDENTIALS="app/ancient-pipe-447417-i4-755ce59fbf03.json COPY src/main/resources/firebase/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json /app/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json EXPOSE 8080 -CMD ["java", "-Dtest.customName=${CUSTOM_NAME}", "-jar", "test-app.jar"] +CMD ["java", "-Dtest.customName=${CUSTOM_NAME}", "-jar", "prod.jar"] diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java index 7de32d7..ca2d376 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java @@ -87,4 +87,15 @@ public ResponseEntity deleteDeveloperQuestion( developerQuestionService.deleteDeveloperQuestion(developerQuestionId, writerId); return ResponseEntity.noContent().build(); } + + @GetMapping("/my") + @Operation(summary = "내가 쓴 개발자 질문 게시글 보기", description = "내가 쓴 글만 조회한다.") + public ResponseEntity> getAllMyDeveloperQuestion( + Authentication authentication + ) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long writerId = principal.getMemberDTO().getMemberId(); + List developerQuestions = developerQuestionService.getAllMyDeveloperQuestion(writerId); + return ResponseEntity.ok(developerQuestions); + } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/repository/DeveloperQuestionRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/repository/DeveloperQuestionRepository.java index ca2ac92..cf2000a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/repository/DeveloperQuestionRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/repository/DeveloperQuestionRepository.java @@ -1,6 +1,8 @@ package com.ComNCheck.ComNCheck.domain.developerQuestion.repository; import com.ComNCheck.ComNCheck.domain.developerQuestion.model.entity.DeveloperQuestion; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,6 +11,6 @@ public interface DeveloperQuestionRepository extends JpaRepository { //Optional findByDeveloperQuestionId(Long id); - + List findAllByWriter(Member writer); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java index 6f95d44..8a4966e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java @@ -74,6 +74,16 @@ public void deleteDeveloperQuestion(Long developerQuestionId, Long writerId) { developerQuestionRepository.delete(developerQuestion); } + public List getAllMyDeveloperQuestion(Long writerId) { + Member writer = memberRepository.findById(writerId) + .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다.")); + + return developerQuestionRepository.findAllByWriter(writer) + .stream() + .map(DeveloperQuestionResponseDTO::of) + .toList(); + } + From 31e28c35df7cad551ebde2b184e4d8f5bdc475bf Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 13 Feb 2025 03:16:35 +0900 Subject: [PATCH 29/67] =?UTF-8?q?Refactor:=20=EB=AA=A8=EB=93=A0=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EC=99=80=20=ED=95=A8=EA=BB=98=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DeveloperQuestionController.java | 4 --- .../service/DeveloperQuestionService.java | 10 +++--- .../domain/fcm/service/FcmService.java | 3 +- .../exception/AnswerNotFoundException.java | 7 +++++ .../exception/ApplyNotFoundException.java | 7 +++++ .../global/exception/BadRequestException.java | 11 ------- .../global/exception/ForbiddenException.java | 4 --- .../exception/GlobalExceptionHandler.java | 31 ++++++++++++------- .../exception/MemberNotFoundException.java | 2 +- .../MissingAuthenticationException.java | 11 ------- .../exception/PostNotFoundException.java | 7 +++++ .../exception/ValidationException.java | 2 +- .../majorEvent/service/MajorEventService.java | 14 +++++---- .../majorQuestion/service/AnswerService.java | 15 +++++---- .../service/QuestionService.java | 16 +++++----- .../domain/member/service/MemberService.java | 17 +++++----- .../service/RoleChangeRequestService.java | 23 ++++++++------ .../domain/testController/MyController.java | 19 ------------ 18 files changed, 97 insertions(+), 106 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/AnswerNotFoundException.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ApplyNotFoundException.java delete mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/BadRequestException.java rename src/main/java/com/ComNCheck/ComNCheck/domain/{member => global}/exception/MemberNotFoundException.java (72%) delete mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MissingAuthenticationException.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/PostNotFoundException.java rename src/main/java/com/ComNCheck/ComNCheck/domain/{member => global}/exception/ValidationException.java (71%) delete mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java index ca2d376..ee354f6 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java @@ -4,7 +4,6 @@ import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.request.DeveloperQuestionRequestDTO; import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.response.DeveloperQuestionResponseDTO; import com.ComNCheck.ComNCheck.domain.developerQuestion.service.DeveloperQuestionService; -import com.ComNCheck.ComNCheck.domain.global.exception.MissingAuthenticationException; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; import io.swagger.v3.oas.annotations.Operation; import java.net.URI; @@ -34,9 +33,6 @@ public ResponseEntity createDeveloperQuestion( @RequestBody DeveloperQuestionRequestDTO requestDTO, Authentication authentication ) { - if (authentication == null) { - throw new MissingAuthenticationException("인증 정보가 필요합니다."); - } CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long memberId = principal.getMemberDTO().getMemberId(); DeveloperQuestionResponseDTO createdDTO = developerQuestionService diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java index 8a4966e..13b3ee4 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java @@ -2,14 +2,14 @@ import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; -import com.ComNCheck.ComNCheck.domain.member.exception.MemberNotFoundException; +import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException; +import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.request.DeveloperQuestionRequestDTO; import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.response.DeveloperQuestionResponseDTO; import com.ComNCheck.ComNCheck.domain.developerQuestion.model.entity.DeveloperQuestion; import com.ComNCheck.ComNCheck.domain.developerQuestion.repository.DeveloperQuestionRepository; - import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -39,7 +39,7 @@ public DeveloperQuestionResponseDTO createDeveloperQuestion(Long memberId, Devel public DeveloperQuestionResponseDTO getDeveloperQuestion(Long developerQuestionId) { DeveloperQuestion developerQuestion = developerQuestionRepository.findById(developerQuestionId) - .orElseThrow(() -> new IllegalArgumentException("질문글을 찾을 수 없습니다.")); + .orElseThrow(() -> new PostNotFoundException("질문글을 찾을 수 없습니다.")); return DeveloperQuestionResponseDTO.of(developerQuestion); } public List getAllQuestion() { @@ -54,7 +54,7 @@ public DeveloperQuestionResponseDTO updateDeveloperQuestion(Long developerQuesti DeveloperQuestionResponseDTO requestDTO, Long writerId) { DeveloperQuestion developerQuestion = developerQuestionRepository.findById(developerQuestionId) - .orElseThrow(() -> new IllegalArgumentException("질문글을 찾을 수 없습니다.")); + .orElseThrow(() -> new PostNotFoundException("질문글을 찾을 수 없습니다.")); if(!developerQuestion.getWriter().getMemberId().equals(writerId)) throw new ForbiddenException("게시글 작성자가 아닙니다."); @@ -66,7 +66,7 @@ public DeveloperQuestionResponseDTO updateDeveloperQuestion(Long developerQuesti @Transactional public void deleteDeveloperQuestion(Long developerQuestionId, Long writerId) { DeveloperQuestion developerQuestion = developerQuestionRepository.findById(developerQuestionId) - .orElseThrow(() -> new IllegalArgumentException("질문글을 찾을 수 없습니다.")); + .orElseThrow(() -> new PostNotFoundException("질문글을 찾을 수 없습니다.")); if(!developerQuestion.getWriter().getMemberId().equals(writerId)) throw new ForbiddenException("게시글 작성자가 아닙니다."); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java index 8d1ea40..fa59763 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java @@ -2,6 +2,7 @@ import com.ComNCheck.ComNCheck.domain.fcm.model.entity.FcmToken; import com.ComNCheck.ComNCheck.domain.fcm.repository.FcmRepository; +import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; import com.google.firebase.messaging.FirebaseMessaging; @@ -35,7 +36,7 @@ public void sendMessageToToken(String token, String title, String body) throws F @Transactional public void registerFcmToken(Long memberId, String token) { Member member = memberRepository.findById(memberId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원입니다.")); + .orElseThrow(() -> new MemberNotFoundException("존재하지 않는 회원입니다.")); FcmToken existing = fcmRepository.findByToken(token).orElse(null); if(existing != null) return; // 학습 후 추가 기능 구현해야함 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/AnswerNotFoundException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/AnswerNotFoundException.java new file mode 100644 index 0000000..8075724 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/AnswerNotFoundException.java @@ -0,0 +1,7 @@ +package com.ComNCheck.ComNCheck.domain.global.exception; + +public class AnswerNotFoundException extends RuntimeException{ + public AnswerNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ApplyNotFoundException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ApplyNotFoundException.java new file mode 100644 index 0000000..06cf02a --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ApplyNotFoundException.java @@ -0,0 +1,7 @@ +package com.ComNCheck.ComNCheck.domain.global.exception; + +public class ApplyNotFoundException extends RuntimeException{ + public ApplyNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/BadRequestException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/BadRequestException.java deleted file mode 100644 index f195630..0000000 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/BadRequestException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ComNCheck.ComNCheck.domain.global.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.BAD_REQUEST) -public class BadRequestException extends RuntimeException { - public BadRequestException(String message) { - super(message); - } -} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java index 48b59fd..38f1729 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java @@ -1,9 +1,5 @@ package com.ComNCheck.ComNCheck.domain.global.exception; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.FORBIDDEN) public class ForbiddenException extends RuntimeException { public ForbiddenException(String message) { super(message); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java index eba91c0..169744a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java @@ -1,7 +1,5 @@ package com.ComNCheck.ComNCheck.domain.global.exception; -import com.ComNCheck.ComNCheck.domain.member.exception.MemberNotFoundException; -import com.ComNCheck.ComNCheck.domain.member.exception.ValidationException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -15,6 +13,21 @@ public ResponseEntity handleMemberNotFound(MemberNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()); } + @ExceptionHandler(PostNotFoundException.class) + public ResponseEntity handlePostNotFound(PostNotFoundException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()); + } + + @ExceptionHandler(ForbiddenException.class) + public ResponseEntity handleForbiddenException(ForbiddenException ex) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ex.getMessage()); + } + + @ExceptionHandler(AnswerNotFoundException.class) + public ResponseEntity handleAnswerNotFoundException(AnswerNotFoundException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()); + } + @ExceptionHandler(FastApiException.class) public ResponseEntity handleFastApiException(FastApiException ex) { return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(ex.getMessage()); @@ -25,10 +38,10 @@ public ResponseEntity handleValidationException(ValidationException ex) return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); } -// @ExceptionHandler(Exception.class) -// public ResponseEntity handleGeneralException(Exception ex) { -// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("서버 내부 오류가 발생했습니다."); -// } + @ExceptionHandler(ApplyNotFoundException.class) + public ResponseEntity handleApplyNotFoundException(ApplyNotFoundException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()); + } @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity handleResourceNotFound(ResourceNotFoundException ex) { @@ -37,12 +50,6 @@ public ResponseEntity handleResourceNotFound(ResourceNotFoundExce } - @ExceptionHandler(BadRequestException.class) - public ResponseEntity handleBadRequest(BadRequestException ex) { - ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage()); - return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); - } - public static class ErrorResponse { private int status; private String message; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/MemberNotFoundException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MemberNotFoundException.java similarity index 72% rename from src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/MemberNotFoundException.java rename to src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MemberNotFoundException.java index a20acba..cfb3e75 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/MemberNotFoundException.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MemberNotFoundException.java @@ -1,4 +1,4 @@ -package com.ComNCheck.ComNCheck.domain.member.exception; +package com.ComNCheck.ComNCheck.domain.global.exception; public class MemberNotFoundException extends RuntimeException { public MemberNotFoundException(String message) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MissingAuthenticationException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MissingAuthenticationException.java deleted file mode 100644 index aa3e032..0000000 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MissingAuthenticationException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ComNCheck.ComNCheck.domain.global.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.BAD_REQUEST) -public class MissingAuthenticationException extends RuntimeException { - public MissingAuthenticationException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/PostNotFoundException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/PostNotFoundException.java new file mode 100644 index 0000000..7ed2d41 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/PostNotFoundException.java @@ -0,0 +1,7 @@ +package com.ComNCheck.ComNCheck.domain.global.exception; + +public class PostNotFoundException extends RuntimeException{ + public PostNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/ValidationException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ValidationException.java similarity index 71% rename from src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/ValidationException.java rename to src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ValidationException.java index f742872..d92df8a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/ValidationException.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ValidationException.java @@ -1,4 +1,4 @@ -package com.ComNCheck.ComNCheck.domain.member.exception; +package com.ComNCheck.ComNCheck.domain.global.exception; public class ValidationException extends RuntimeException { public ValidationException(String message) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java index af01690..88f708a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java @@ -2,6 +2,8 @@ import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService; import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; +import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException; +import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventCreateRequestDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventUpdateRequestDTO; import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.EventListResponseDTO; @@ -43,7 +45,7 @@ public class MajorEventService { @Transactional public EventResponseDTO createMajorEvent(EventCreateRequestDTO requestDTO, Long writerId) { Member writer = memberRepository.findByMemberId(writerId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원입니다.")); + .orElseThrow(() -> new MemberNotFoundException("존재하지 않는 회원입니다.")); isCheckRole(writer); @@ -90,7 +92,7 @@ public EventResponseDTO createMajorEvent(EventCreateRequestDTO requestDTO, Long public EventResponseDTO getMajorEvent(Long majorEventId) { MajorEvent majorEvent = majorEventRepository.findById(majorEventId) - .orElseThrow(() -> new IllegalArgumentException("해당 학부 행사 정보가 없습니다.")); + .orElseThrow(() -> new PostNotFoundException("요청하신 학부 행사가 없습니다.")); return EventResponseDTO.of(majorEvent); } @@ -116,11 +118,11 @@ public List getAllMajorEventsNotPassed() { @Transactional public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDTO requestDTO, Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); MajorEvent majorEvent = majorEventRepository.findById(majorEventId) - .orElseThrow(() -> new IllegalArgumentException("해당 학부 행사 정보가 없습니다.")); + .orElseThrow(() -> new PostNotFoundException("요청하신 학부 행사가 없습니다.")); LocalDate eventDate = requestDTO.getParsedDate(); LocalTime eventTime = requestDTO.getParsedTime(); @@ -144,11 +146,11 @@ public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDT @Transactional public void deleteMajorEvent(Long majorEventId, Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); MajorEvent majorEvent = majorEventRepository.findById(majorEventId) - .orElseThrow(() -> new IllegalArgumentException("해당 학부 행사 정보가 없습니다.")); + .orElseThrow(() -> new PostNotFoundException("요청하신 학부 행사가 없습니다.")); majorEventRepository.delete(majorEvent); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java index 7306f89..3b4a676 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java @@ -1,6 +1,9 @@ package com.ComNCheck.ComNCheck.domain.majorQuestion.service; +import com.ComNCheck.ComNCheck.domain.global.exception.AnswerNotFoundException; import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; +import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException; +import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; @@ -27,11 +30,11 @@ public class AnswerService { @Transactional public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO, Long memberId) { Member writer = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("해당 회원이 존재하지 않습니다.")); + .orElseThrow(() -> new MemberNotFoundException("해당 회원이 존재하지 않습니다.")); isCheckRole(writer); Question question = questionRepository.findById(requestDTO.getQuestionId()) - .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); + .orElseThrow(() -> new PostNotFoundException("요청하신 질문이 존재하지 않습니다.")); Answer answer = answerRepository.findByQuestionId(question.getId()).orElse(null); @@ -53,10 +56,10 @@ public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO, Long @Transactional public AnswerResponseDTO updateAnswer(Long answerId, String content, Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); Answer answer = answerRepository.findById(answerId) - .orElseThrow(() -> new IllegalArgumentException("해당 답글이 존재하지 않습니다.")); + .orElseThrow(() -> new AnswerNotFoundException("답변이 존재하지 않습니다.")); answer.updateAnswer(content); return AnswerResponseDTO.of(answer); @@ -65,10 +68,10 @@ public AnswerResponseDTO updateAnswer(Long answerId, String content, Long member @Transactional public void deleteAnswer(Long answerId, Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); Answer answer = answerRepository.findById(answerId) - .orElseThrow(() -> new IllegalArgumentException("해당 답글이 존재하지 않습니다.")); + .orElseThrow(() -> new AnswerNotFoundException("답변이 존재하지 않습니다.")); answerRepository.delete(answer); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index 9e73c45..c48e68c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -2,6 +2,8 @@ import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; +import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException; +import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; @@ -25,7 +27,7 @@ public class QuestionService { @Transactional public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO, Long memberId) { Member writer = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다.")); + .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다.")); Question question = Question.builder() .title(requestDTO.getTitle()) @@ -40,7 +42,7 @@ public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO, Long me public List getAllQuestion(Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다.")); + .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다.")); isCheckRole(member); return questionRepository.findAll() @@ -51,7 +53,7 @@ public List getAllQuestion(Long memberId) { public QuestionResponseDTO getQuestion(Long questionId) { Question question = questionRepository.findById(questionId) - .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); + .orElseThrow(() -> new PostNotFoundException("질문이 존재하지 않습니다.")); return QuestionResponseDTO.of(question); } @@ -66,7 +68,7 @@ public List getQuestionsWithAnswer() { @Transactional public QuestionResponseDTO updateQuestion(Long questionId, QuestionRequestDTO requestDTO, Long writerId) { Question question = questionRepository.findById(questionId) - .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); + .orElseThrow(() -> new PostNotFoundException("질문이 존재하지 않습니다.")); if (!question.getWriter().getMemberId().equals(writerId)) { throw new ForbiddenException("작성자가 아닙니다."); @@ -79,7 +81,7 @@ public QuestionResponseDTO updateQuestion(Long questionId, QuestionRequestDTO re @Transactional public void deleteQuestion(Long questionId, Long writerId) { Question question = questionRepository.findById(questionId) - .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다.")); + .orElseThrow(() -> new PostNotFoundException("해당 질문이 존재하지 않습니다.")); if(!question.getWriter().getMemberId().equals(writerId)) { throw new ForbiddenException("작성자가 아닙니다."); @@ -97,7 +99,7 @@ public List getMyQuestions(Long writerId) { @Transactional public List getUnanswerdAllQuestion(Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다.")); + .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다.")); isCheckRole(member); return questionRepository.findByAnswerIsNull() .stream() @@ -108,7 +110,7 @@ public List getUnanswerdAllQuestion(Long memberId) { public void isCheckRole(Member member) { Role checkRole = member.getRole(); if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) { - throw new IllegalArgumentException("접근 권한이 없습니다."); + throw new ForbiddenException("접근 권한이 없습니다."); } } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java index 4eb5e3b..2b1bef4 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java @@ -1,11 +1,12 @@ package com.ComNCheck.ComNCheck.domain.member.service; -import com.ComNCheck.ComNCheck.domain.member.exception.ValidationException; +import com.ComNCheck.ComNCheck.domain.global.exception.FastApiException; +import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException; +import com.ComNCheck.ComNCheck.domain.global.exception.ValidationException; import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.CouncilDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO.ExtractedText; -import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberInformationResponseDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentDTO; @@ -31,7 +32,7 @@ public class MemberService { @Transactional public MemberInformationResponseDTO registerStudentNumber(Long id, MultipartFile studentCardImage) { Member member = memberRepository.findByMemberId(id) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); FastApiStudentCardDTO fastApiResponse = fastApiClient.sendImage(studentCardImage); FastApiStudentCardDTO.ExtractedText extractedText = fastApiResponse.getExtractedText(); @@ -77,13 +78,13 @@ private void validateFastApiResponse(ExtractedText extractedText) { extractedText.getName() == null || extractedText.getMajor() == null || extractedText.getStudentId() == null) { - throw new ValidationException("FastAPI 응답이 유효하지 않습니다."); + throw new FastApiException("FastAPI 응답이 유효하지 않습니다."); } } public MemberInformationResponseDTO getMemberInformation(Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); return MemberInformationResponseDTO.of(member); } @@ -100,7 +101,7 @@ public void logout(HttpServletResponse response) { @Transactional public void changeAlarmMajorEvent(Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); if(member.isAlarmMajorEvent()) { member.offAlarmMajorEvent(); } @@ -113,7 +114,7 @@ public void changeAlarmMajorEvent(Long memberId) { @Transactional public void changeAlarmMajorNotice(Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); if(member.isAlarmMajorNotice()) { member.offAlarmMajorNotice(); } @@ -126,7 +127,7 @@ public void changeAlarmMajorNotice(Long memberId) { @Transactional public void changeAlarmEmploymentNotice(Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); if(member.isAlarmEmploymentNotice()) { member.offAlarmEmploymentNotice(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java index 24cd594..308062b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java @@ -1,6 +1,9 @@ package com.ComNCheck.ComNCheck.domain.roleChange.service; +import com.ComNCheck.ComNCheck.domain.global.exception.ApplyNotFoundException; +import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; +import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException; import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request.RoleChangeRequestDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.ApprovedRoleListDTO; @@ -27,7 +30,7 @@ public class RoleChangeRequestService { @Transactional public RoleChangeResponseDTO createRoleChangeRequest(Long memberId, RoleChangeRequestDTO requestDTO) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); RoleChange roleChange = RoleChange.builder() .member(member) @@ -41,7 +44,7 @@ public RoleChangeResponseDTO createRoleChangeRequest(Long memberId, RoleChangeRe public List getAllRequests(Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); List requests = roleChangeRequestRepository.findAll(); @@ -52,22 +55,22 @@ public List getAllRequests(Long memberId) { public RoleChangeResponseDTO getRequestDetail(Long requestId, Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); RoleChange request = roleChangeRequestRepository.findById(requestId) - .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다.")); + .orElseThrow(() -> new ApplyNotFoundException("등록된 학생회 신청이 없습니다.")); return RoleChangeResponseDTO.of(request); } @Transactional public void approveRequest(Long requestId, Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); RoleChange request = roleChangeRequestRepository.findById(requestId) - .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다.")); + .orElseThrow(() -> new ApplyNotFoundException("등록된 학생회 신청이 없습니다.")); request.approve(); @@ -79,7 +82,7 @@ public void approveRequest(Long requestId, Long memberId) { public List getApproveRequests(Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); List requests = roleChangeRequestRepository.findAll().stream() @@ -95,18 +98,18 @@ public List getApproveRequests(Long memberId) { @Transactional public void deleteRequest(Long requestId, Long memberId) { Member member = memberRepository.findByMemberId(memberId) - .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다.")); + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); RoleChange request = roleChangeRequestRepository.findById(requestId) - .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다.")); + .orElseThrow(() -> new ApplyNotFoundException("등록된 학생회 신청이 없습니다.")); roleChangeRequestRepository.delete(request); } public void isCheckRole(Member member) { Role checkRole = member.getRole(); if (checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_ADMIN) { - throw new IllegalArgumentException("접근 권한이 없습니다."); + throw new ForbiddenException("접근 권한이 없습니다."); } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java deleted file mode 100644 index 7e10d71..0000000 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.ComNCheck.ComNCheck.domain.testController; - -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -@Controller -public class MyController { - - @GetMapping("/my") - @Operation(summary = "CORS 에러 체크", description = "CORS 여부를 따지기 위한 API 였으므로, 신경 안써도됨 삭제 예정") - @ResponseBody - public String myAPI() { - return "my route"; - } - - -} From cd073a398f0b4d2d9d7875d59554066dcd3d2848 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 13 Feb 2025 03:48:57 +0900 Subject: [PATCH 30/67] =?UTF-8?q?Fix:=20FAQ=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20=EC=95=88=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/majorQuestion/model/entity/Question.java | 8 +++++--- .../domain/majorQuestion/service/QuestionService.java | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java index e09068b..6dcd737 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java @@ -1,6 +1,7 @@ package com.ComNCheck.ComNCheck.domain.majorQuestion.model.entity; +import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.QuestionRequestDTO; import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; @@ -60,9 +61,10 @@ public void setAnswer(Answer answer) { answer.setQuestion(this); } - public void updateQuestion(String title, String content) { - this.title = title; - this.content = content; + public void updateQuestion(QuestionRequestDTO dto) { + this.title = dto.getTitle(); + this.content = dto.getContent(); + this.shared = dto.isShared(); this.updatedAt = LocalDateTime.now(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index c48e68c..0d200c0 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -74,7 +74,7 @@ public QuestionResponseDTO updateQuestion(Long questionId, QuestionRequestDTO re throw new ForbiddenException("작성자가 아닙니다."); } - question.updateQuestion(requestDTO.getTitle(), requestDTO.getContent()); + question.updateQuestion(requestDTO); return QuestionResponseDTO.of(question); } From 67459bec06b1cf5952c4cfff47b9f17033f15fed Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sat, 15 Feb 2025 18:11:53 +0900 Subject: [PATCH 31/67] =?UTF-8?q?Refactor:=20=EB=A1=9C=EC=BB=AC=EC=9D=B4?= =?UTF-8?q?=20=EC=95=84=EB=8B=8C=20=EB=B0=B0=ED=8F=AC=EC=84=B8=ED=8C=85?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EC=B6=B0=EC=84=9C=20=EC=8B=9C=ED=81=90?= =?UTF-8?q?=EB=A6=AC=ED=8B=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/security/config/CorsMvcConfig.java | 4 +++- .../ComNCheck/domain/security/config/SecurityConfig.java | 2 +- .../ComNCheck/domain/security/filter/JWTFilter.java | 1 - .../domain/security/handler/CustomSuccessHandler.java | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java index 0a0d397..5159e0b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java @@ -11,6 +11,8 @@ public class CorsMvcConfig implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .exposedHeaders("Set-Cookie") - .allowedOrigins("http://localhost:3000"); + .allowedOrigins("http://localhost:3000", + "https://com-n-check.vercel.app" + ); } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 01a5fe2..4eb0711 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -32,7 +32,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); + configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000","https://com-n-check.vercel.app")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("*")); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java index f920e9f..924e4d7 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java @@ -34,7 +34,6 @@ public class JWTFilter extends OncePerRequestFilter { "/webjars/**", "/login/**", "/oauth2/**", - "/h2-console/**", "api/v1/**" }; private final AntPathMatcher pathMatcher = new AntPathMatcher(); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index 6956ac2..b31c03b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -39,10 +39,10 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo response.addCookie(createCookie("AccessToken", token)); if(!checkStudentCard) { - response.sendRedirect("http://localhost:3000/login/first"); + response.sendRedirect("https://com-n-check.vercel.app/login/first"); } else { - response.sendRedirect("http://localhost:3000/notice"); + response.sendRedirect("https://com-n-check.vercel.app/notice"); } //response.sendRedirect("http://localhost:3000/login/first"); @@ -51,7 +51,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo private Cookie createCookie(String key, String value) { Cookie cookie = new Cookie(key, value); cookie.setMaxAge(60*60*60); - //cookie.setSecure(true); // https에서만 작동 + cookie.setSecure(true); // https에서만 작동 cookie.setPath("/"); cookie.setHttpOnly(true); From 0c04cd3d6a8dad8e83c37e0bb9a3e233e01f079c Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 16 Feb 2025 03:11:27 +0900 Subject: [PATCH 32/67] =?UTF-8?q?Refactor:=20yaml=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yaml | 1 - .../resources/yaml/application-local.yaml | 19 +++++++++++++++--- src/main/resources/yaml/application-log.yaml | 20 +++++++++---------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index d164b6e..e3da5cb 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -31,7 +31,6 @@ spring: credentials: location: classpath:/firebase/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json - security: oauth2: client: diff --git a/src/main/resources/yaml/application-local.yaml b/src/main/resources/yaml/application-local.yaml index 00e5bef..d88694d 100644 --- a/src/main/resources/yaml/application-local.yaml +++ b/src/main/resources/yaml/application-local.yaml @@ -1,9 +1,15 @@ spring: config: - on-profile: dev + activate: + on-profile: local jpa: hibernate: - ddl-auto: create + ddl-auto: update + properties: + hibernate: + show_sql: true + format_sql: true + highlight_sql: true datasource: driver-class-name: org.h2.Driver url: ${H2_DB_URL:jdbc:h2:mem:test} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode) @@ -14,4 +20,11 @@ spring: enabled: true path: /h2-console settings: - web-allow-others: true \ No newline at end of file + web-allow-others: true + +logging.level: + org.hibernate: + type: trace + orm: + jdbc: + bind: trace \ No newline at end of file diff --git a/src/main/resources/yaml/application-log.yaml b/src/main/resources/yaml/application-log.yaml index bee3dd2..ac3684b 100644 --- a/src/main/resources/yaml/application-log.yaml +++ b/src/main/resources/yaml/application-log.yaml @@ -3,17 +3,17 @@ spring: activate: on-profile: log jpa: + hibernate: + ddl-auto: update properties: hibernate: - show_sql: true # System.out 방식 로그 + show_sql: true format_sql: true highlight_sql: true - use_sql_comments: true -#logging: -# level: -# org: -# hibernate: -# SQL: debug # logger 방식 로그 -# orm: -# jdbc: -# bind: trace \ No newline at end of file + +logging.level: + org.hibernate: + type: trace + orm: + jdbc: + bind: trace \ No newline at end of file From 3c1c2b2160240e9b1862d91da000c518fd5b9d5d Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 16 Feb 2025 03:49:08 +0900 Subject: [PATCH 33/67] =?UTF-8?q?Fix:=20=EA=B3=BC=ED=96=89=EC=82=AC=20?= =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=20=EA=B0=80=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../majorEvent/model/dto/response/EventListResponseDTO.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java index 56aa2bd..99eb5dc 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java @@ -13,6 +13,7 @@ public class EventListResponseDTO { private String eventName; private LocalDate date; private LocalTime time; + private String googleFormLink; public static EventListResponseDTO of(MajorEvent majorEvent) { return EventListResponseDTO.builder() From ba2cef60a84ff2a60cc01e9f01e6d5938a7ff802 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 16 Feb 2025 16:43:23 +0900 Subject: [PATCH 34/67] =?UTF-8?q?Fix:=20=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=8B=9C=20=EA=B5=AC=EA=B8=80=ED=8F=BC,=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=A0=84=EB=8B=AC=20=EC=95=88?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/dto/request/EventUpdateRequestDTO.java | 1 + .../model/dto/response/EventListResponseDTO.java | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java index a7979b1..796c7aa 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java @@ -19,6 +19,7 @@ public class EventUpdateRequestDTO { private String location; private String notice; private String googleFormLink; + private String firstImageUrl; private List cardNewsImages; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java index 99eb5dc..96673a9 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java @@ -14,12 +14,20 @@ public class EventListResponseDTO { private LocalDate date; private LocalTime time; private String googleFormLink; + private String firstImageUrl; + public static EventListResponseDTO of(MajorEvent majorEvent) { + String firstImage = null; + if (majorEvent.getCardNewsImageUrls() != null && !majorEvent.getCardNewsImageUrls().isEmpty()) { + firstImage = majorEvent.getCardNewsImageUrls().get(0); + } return EventListResponseDTO.builder() .eventName(majorEvent.getEventName()) .date(majorEvent.getDate()) .time(majorEvent.getTime()) + .googleFormLink(majorEvent.getGoogleFormLink()) + .firstImageUrl(firstImage) .build(); } } From 14b4e17aa5e29818598f2dc69296d224cbb1074f Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 16 Feb 2025 22:08:57 +0900 Subject: [PATCH 35/67] =?UTF-8?q?Refactor:=20=ED=94=84=EB=A1=A0=ED=8A=B8?= =?UTF-8?q?=20=EB=A1=9C=EC=BB=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EB=8A=94=20=EB=B8=8C=EB=9E=9C=EC=B9=98=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/security/config/CorsMvcConfig.java | 5 ++--- .../ComNCheck/domain/security/config/SecurityConfig.java | 2 +- .../domain/security/handler/CustomSuccessHandler.java | 4 ++-- src/main/resources/yaml/application-prod.yaml | 3 --- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java index 5159e0b..689a160 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java @@ -11,8 +11,7 @@ public class CorsMvcConfig implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .exposedHeaders("Set-Cookie") - .allowedOrigins("http://localhost:3000", - "https://com-n-check.vercel.app" - ); + .allowedOrigins("http://localhost:3000" + ); // "https://com-n-check.vercel.app" } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 4eb0711..01a5fe2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -32,7 +32,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000","https://com-n-check.vercel.app")); + configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("*")); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index b31c03b..c3925a2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -39,10 +39,10 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo response.addCookie(createCookie("AccessToken", token)); if(!checkStudentCard) { - response.sendRedirect("https://com-n-check.vercel.app/login/first"); + response.sendRedirect("http://localhost:3000/login/first"); //https://com-n-check.vercel.app } else { - response.sendRedirect("https://com-n-check.vercel.app/notice"); + response.sendRedirect("http://localhost:3000/notice"); } //response.sendRedirect("http://localhost:3000/login/first"); diff --git a/src/main/resources/yaml/application-prod.yaml b/src/main/resources/yaml/application-prod.yaml index f70ef20..9a40706 100644 --- a/src/main/resources/yaml/application-prod.yaml +++ b/src/main/resources/yaml/application-prod.yaml @@ -7,7 +7,4 @@ spring: url: ${MYSQL_URL} username: ${MYSQL_USERNAME} password: ${MYSQL_PASSWORD} - jpa: - hibernate: - ddl-auto: update From d87d5919988f0325076e7a56eb8fb49836e118ae Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 16 Feb 2025 22:33:21 +0900 Subject: [PATCH 36/67] =?UTF-8?q?Fix:=20=EC=BF=BC=EB=A6=AC=EB=AC=B8=20?= =?UTF-8?q?=EC=A0=9C=EB=8C=80=EB=A1=9C=20=EC=95=88=EB=82=A0=EB=9D=BC?= =?UTF-8?q?=EC=98=A4=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 52b24c3..76acdfa 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -7,7 +7,7 @@ spring: config: import: - classpath:/yaml/application-prod.yaml - - classpath:/yaml/application-local.yaml + - classpath:/yaml/application-log.yaml profiles: group: setting: prod, log From f2174dd0b2a809812633090453cb01df52a6a42b Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 16 Feb 2025 23:06:35 +0900 Subject: [PATCH 37/67] =?UTF-8?q?Fix:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EA=B8=B0=EB=8A=A5=20=EB=B3=80=EA=B2=BD=20CustomMem?= =?UTF-8?q?berSuccessHandler=EB=A1=9C=20=EC=9C=84=EC=B9=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=B0=8F=20JESSIONID=20=EC=BF=A0=ED=82=A4=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/MemberController.java | 8 ++++++-- .../domain/member/service/MemberService.java | 8 -------- .../handler/CustomSuccessHandler.java | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java index e7e5f1c..4585e61 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java @@ -2,9 +2,12 @@ import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberInformationResponseDTO; import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO; +import com.ComNCheck.ComNCheck.domain.member.service.CustomOAuthMemberService; import com.ComNCheck.ComNCheck.domain.member.service.MemberService; +import com.ComNCheck.ComNCheck.domain.security.handler.CustomSuccessHandler; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; import io.swagger.v3.oas.annotations.Operation; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -22,6 +25,7 @@ @RequestMapping("/api/v1/member") public class MemberController { private final MemberService memberService; + private final CustomSuccessHandler customSuccessHandler; @PostMapping("/student/number") @Operation(summary = "학번 등록", description = "모바일 학생증으로 학번을 등록한다.") @@ -52,8 +56,8 @@ public ResponseEntity getMemberInformation(Authent @PostMapping("/logout") @Operation(summary = "로그아웃", description = "쿠키의 jwt를 강제로 만료시켜 로그아웃 시킨다.") - public ResponseEntity logout(HttpServletResponse response) { - memberService.logout(response); + public ResponseEntity logout(HttpServletRequest request, HttpServletResponse response) { + customSuccessHandler.clearAuthenticationSuccess(request, response); return ResponseEntity.ok("로그아웃 성공"); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java index 2b1bef4..b062af5 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java @@ -89,14 +89,6 @@ public MemberInformationResponseDTO getMemberInformation(Long memberId) { } - public void logout(HttpServletResponse response) { - Cookie cookie = new Cookie("AccessToken", null); - cookie.setPath("/"); - cookie.setHttpOnly(true); - //cookie.setSecure(true); - cookie.setMaxAge(0); - response.addCookie(cookie); - } @Transactional public void changeAlarmMajorEvent(Long memberId) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index 6956ac2..d5be2ce 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -6,6 +6,7 @@ import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import java.io.IOException; import java.util.Collection; import java.util.Iterator; @@ -48,6 +49,24 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo } + public void clearAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response) { + HttpSession session = request.getSession(false); + if (session != null) { + session.invalidate(); + } + + Cookie jsessionCookie = new Cookie("JSESSIONID", null); + jsessionCookie.setPath("/"); + jsessionCookie.setMaxAge(0); + response.addCookie(jsessionCookie); + + Cookie accessTokenCookie = new Cookie("AccessToken", null); + accessTokenCookie.setPath("/"); + accessTokenCookie.setHttpOnly(true); + accessTokenCookie.setMaxAge(0); + response.addCookie(accessTokenCookie); + } + private Cookie createCookie(String key, String value) { Cookie cookie = new Cookie(key, value); cookie.setMaxAge(60*60*60); From 8e6472873d696b1862bd01fa81807a3f7f786dbc Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Mon, 17 Feb 2025 23:40:03 +0900 Subject: [PATCH 38/67] =?UTF-8?q?Refactor=20=20RoleChange=20requestRole=20?= =?UTF-8?q?Enumerated=20=EC=84=A4=EC=A0=95=20=EC=95=88=EB=90=98=EC=96=B4?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20=EB=B6=80=EB=B6=84=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/roleChange/model/entity/RoleChange.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java index 11f175d..ea5d702 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java @@ -39,6 +39,7 @@ public class RoleChange { private String requestPosition; @Column(name = "request_role", nullable = false) + @Enumerated(EnumType.STRING) private Role requestRole; @Builder From 639bd649c9a352c54934bf5816ee4d09c8d1fe4a Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 18 Feb 2025 00:41:54 +0900 Subject: [PATCH 39/67] =?UTF-8?q?Refactor:=20test=5Flocal=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EA=B2=8C=20=EC=BF=A0=ED=82=A4=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/security/handler/CustomSuccessHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index 72a1bba..e16e388 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -69,8 +69,8 @@ public void clearAuthenticationSuccess(HttpServletRequest request, HttpServletRe private Cookie createCookie(String key, String value) { Cookie cookie = new Cookie(key, value); - cookie.setMaxAge(60*60*60); - cookie.setSecure(true); // https에서만 작동 +// cookie.setMaxAge(60*60*60); +// cookie.setSecure(true); // https에서만 작동 cookie.setPath("/"); cookie.setHttpOnly(true); From 760ba0f02a9afab1bd08f6368d1dfb053ca2d783 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 18 Feb 2025 01:22:54 +0900 Subject: [PATCH 40/67] =?UTF-8?q?Refactor:=20=EC=A7=88=EB=AC=B8=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EB=AA=A9=EB=A1=9D=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20=EC=88=9C=EC=84=9C=EB=A1=9C=20=EB=82=B4=EB=A6=BC?= =?UTF-8?q?=EC=B0=A8=EC=88=9C=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/majorQuestion/controller/AnswerController.java | 6 +++--- .../domain/majorQuestion/repository/QuestionRepository.java | 4 ++++ .../domain/majorQuestion/service/QuestionService.java | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java index d67162e..ed93970 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java @@ -18,7 +18,7 @@ public class AnswerController { private final AnswerService answerService; @PostMapping - @Operation(summary = "fAQ 댓글 작성", description = "학생회권한만 댓글을 달 수 있다.") + @Operation(summary = "FAQ 댓글 작성", description = "학생회권한만 댓글을 달 수 있다.") public ResponseEntity createOrUpdateAnswer( @RequestBody AnswerRequestDTO requestDTO, Authentication authentication @@ -31,7 +31,7 @@ public ResponseEntity createOrUpdateAnswer( } @PutMapping("/{answerId}") - @Operation(summary = "fAQ 댓글 수정", description = "학생회권한만 댓글 작성자의 관계없이 댓글 수정이 가능하다.") + @Operation(summary = "FAQ 댓글 수정", description = "학생회권한만 댓글 작성자의 관계없이 댓글 수정이 가능하다.") public ResponseEntity updateAnswer( @PathVariable Long answerId, @RequestBody AnswerRequestDTO answerRequestDTO, @@ -44,7 +44,7 @@ public ResponseEntity updateAnswer( } @DeleteMapping("/{answerId}") - @Operation(summary = "fAQ 댓글 삭제", description = "학생회권한만 작성자의 관계없이 댓글 삭제가 가능하다") + @Operation(summary = "FAQ 댓글 삭제", description = "학생회권한만 작성자의 관계없이 댓글 삭제가 가능하다") public ResponseEntity deleteAnswer( @PathVariable Long answerId, Authentication authentication diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java index e270d01..43dc703 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface QuestionRepository extends JpaRepository { List findAllByWriterMemberId(Long writerId); @@ -11,4 +12,7 @@ public interface QuestionRepository extends JpaRepository { Optional findByIdAndSharedTrue(Long id); List findByAnswerIsNotNullAndSharedTrue(); List findByAnswerIsNull(); + + @Query("SELECT q FROM Question q ORDER BY q.updatedAt DESC") + List findAllOrderedByUpdatedAt(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java index 0d200c0..e5b319c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java @@ -13,6 +13,7 @@ import com.ComNCheck.ComNCheck.domain.majorQuestion.repository.QuestionRepository; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -45,7 +46,7 @@ public List getAllQuestion(Long memberId) { .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다.")); isCheckRole(member); - return questionRepository.findAll() + return questionRepository.findAllOrderedByUpdatedAt() .stream() .map(QuestionResponseDTO::of) .toList(); From 06a3f6af6a9905475d0d5cb89bb60b89144728c2 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 18 Feb 2025 02:23:15 +0900 Subject: [PATCH 41/67] =?UTF-8?q?Refactor:=20FAQ=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=A7=88=EB=AC=B8=20=EC=A0=95=EB=A0=AC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/entity/DeveloperQuestion.java | 13 +++++++++++++ .../repository/QuestionRepository.java | 1 + 2 files changed, 14 insertions(+) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/entity/DeveloperQuestion.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/entity/DeveloperQuestion.java index f6d19fa..5091989 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/entity/DeveloperQuestion.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/entity/DeveloperQuestion.java @@ -10,6 +10,8 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.PrePersist; +import java.time.LocalDateTime; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -32,9 +34,20 @@ public class DeveloperQuestion { @JoinColumn(name = "writer_id") private Member writer; + @Column + private LocalDateTime createdAt; + @Column + private LocalDateTime updatedAt; + public void updateDeveloperQuestion(String content) { this.content = content; } + @PrePersist + public void prePersist() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java index 43dc703..0fc301e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java @@ -10,6 +10,7 @@ public interface QuestionRepository extends JpaRepository { List findAllByWriterMemberId(Long writerId); List findByAnswerIsNotNull(); Optional findByIdAndSharedTrue(Long id); + @Query("SELECT q FROM Question q WHERE q.answer IS NOT NULL AND q.shared = true ORDER BY q.updatedAt DESC") List findByAnswerIsNotNullAndSharedTrue(); List findByAnswerIsNull(); From fe8e94c8e7d8ba2a1290b32317443c25ecb54849 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 23 Feb 2025 18:13:25 +0900 Subject: [PATCH 42/67] =?UTF-8?q?Refactor:=20=ED=95=99=EC=83=9D=ED=9A=8C?= =?UTF-8?q?=20=ED=96=89=EC=82=AC=20=EA=B8=B0=EA=B0=84=20=EC=A7=80=EB=82=9C?= =?UTF-8?q?=EA=B2=83=EB=8F=84=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20?= =?UTF-8?q?=EC=8B=9D=EC=9C=BC=EB=A1=9C=20API=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/majorEvent/service/MajorEventService.java | 11 +++++------ .../domain/security/config/CorsMvcConfig.java | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java index 88f708a..f127071 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java @@ -103,14 +103,13 @@ public List getAllMajorEventsNotPassed() { LocalDate today = LocalDate.now(); LocalTime currentTime = LocalTime.now(); - List filtered = all.stream() - .filter(e -> isNotPassed(e, today, currentTime)) - .collect(Collectors.toList()); - - filtered.sort(Comparator.comparing(MajorEvent::getDate) +// List filtered = all.stream() // 기간 지난 행사 제외 +// .filter(e -> isNotPassed(e, today, currentTime)) +// .collect(Collectors.toList()); + all.sort(Comparator.comparing(MajorEvent::getDate) .thenComparing(MajorEvent::getTime)); - return filtered.stream() + return all.stream() .map(EventListResponseDTO::of) .collect(Collectors.toList()); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java index 689a160..607b452 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java @@ -11,7 +11,7 @@ public class CorsMvcConfig implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .exposedHeaders("Set-Cookie") - .allowedOrigins("http://localhost:3000" + .allowedOrigins("http://210.91.77.225:3000" ); // "https://com-n-check.vercel.app" } } From 550ced831aa753b6627dbc456cbdcd4bde7ef4ad Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 23 Feb 2025 18:20:35 +0900 Subject: [PATCH 43/67] =?UTF-8?q?Refactor:=20=EC=8B=9C=ED=81=90=EB=A6=AC?= =?UTF-8?q?=ED=8B=B0=20=EB=8F=84=EB=A9=94=EC=9D=B8=20Local=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=B0=B0=ED=8F=AC=EC=9A=A9=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/security/config/CorsMvcConfig.java | 2 +- .../ComNCheck/domain/security/config/SecurityConfig.java | 2 +- .../domain/security/handler/CustomSuccessHandler.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java index 607b452..b0db652 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java @@ -11,7 +11,7 @@ public class CorsMvcConfig implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .exposedHeaders("Set-Cookie") - .allowedOrigins("http://210.91.77.225:3000" + .allowedOrigins("https://com-n-check.vercel.app/" ); // "https://com-n-check.vercel.app" } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 01a5fe2..1f208e8 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -32,7 +32,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); + configuration.setAllowedOrigins(Arrays.asList("https://com-n-check.vercel.app/")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("*")); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index e16e388..cfa3476 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -40,10 +40,10 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo response.addCookie(createCookie("AccessToken", token)); if(!checkStudentCard) { - response.sendRedirect("http://localhost:3000/login/first"); //https://com-n-check.vercel.app + response.sendRedirect("https://com-n-check.vercel.app/login/first"); //https://com-n-check.vercel.app } else { - response.sendRedirect("http://localhost:3000/notice"); + response.sendRedirect("https://com-n-check.vercel.app//notice"); } //response.sendRedirect("http://localhost:3000/login/first"); From 0fe9bbde159fdbf3c7f9cca4b839051dd80d7eb4 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 25 Feb 2025 23:03:08 +0900 Subject: [PATCH 44/67] =?UTF-8?q?Refactor:=20front=20URL=20localhost=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/security/config/CorsMvcConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java index 607b452..689a160 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java @@ -11,7 +11,7 @@ public class CorsMvcConfig implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .exposedHeaders("Set-Cookie") - .allowedOrigins("http://210.91.77.225:3000" + .allowedOrigins("http://localhost:3000" ); // "https://com-n-check.vercel.app" } } From fc6670008e2237d6cdf551b7ef72ac852bf1605f Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Fri, 28 Feb 2025 20:03:55 +0900 Subject: [PATCH 45/67] =?UTF-8?q?Fix:=20=EA=B3=BC=ED=96=89=EC=82=AC=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20id(pk)=EA=B0=80=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../majorEvent/model/dto/response/EventListResponseDTO.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java index 96673a9..b32745a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java @@ -10,6 +10,7 @@ @Getter @Builder public class EventListResponseDTO { + private Long id; private String eventName; private LocalDate date; private LocalTime time; @@ -23,6 +24,7 @@ public static EventListResponseDTO of(MajorEvent majorEvent) { firstImage = majorEvent.getCardNewsImageUrls().get(0); } return EventListResponseDTO.builder() + .id(majorEvent.getMajorEventId()) .eventName(majorEvent.getEventName()) .date(majorEvent.getDate()) .time(majorEvent.getTime()) From 0292442907e1469c81f6930e6600ca9d658bb3ed Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sat, 1 Mar 2025 23:45:39 +0900 Subject: [PATCH 46/67] =?UTF-8?q?Refactor:=20=EC=BF=A0=ED=82=A4=20?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=ED=8C=8C=ED=8B=B0=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/security/config/CorsMvcConfig.java | 4 ++- .../handler/CustomSuccessHandler.java | 33 ++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java index e41aa66..24960cb 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java @@ -11,6 +11,8 @@ public class CorsMvcConfig implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .exposedHeaders("Set-Cookie") - .allowedOrigins("https://com-n-check.vercel.app/"); // "https://com-n-check.vercel.app" + .allowedOrigins("https://com-n-check.vercel.app") + .allowedMethods("*") + .allowCredentials(true); } } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index cfa3476..9a21805 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.Iterator; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseCookie; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; @@ -38,7 +39,9 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo String token = jwtUtil.createJwt(memberId, username, role, 365L * 24 * 60 * 60 * 1000); // 60 * 60 * 1000L - response.addCookie(createCookie("AccessToken", token)); + ResponseCookie cookie = createCookie("AccessToken", token); + response.setHeader("Set-Cookie", cookie.toString()); + //response.addCookie(createCookie("AccessToken", token)); // Cookie로 했을때 if(!checkStudentCard) { response.sendRedirect("https://com-n-check.vercel.app/login/first"); //https://com-n-check.vercel.app } @@ -67,15 +70,27 @@ public void clearAuthenticationSuccess(HttpServletRequest request, HttpServletRe response.addCookie(accessTokenCookie); } - private Cookie createCookie(String key, String value) { - Cookie cookie = new Cookie(key, value); -// cookie.setMaxAge(60*60*60); -// cookie.setSecure(true); // https에서만 작동 - cookie.setPath("/"); - cookie.setHttpOnly(true); - - return cookie; + private ResponseCookie createCookie(String key, String value) { + return ResponseCookie.from(key, value) + .maxAge(60 * 60 * 60) + .secure(true) + .sameSite("None") + .path("/") + .domain("com-n-check.vercel.app") + .httpOnly(true) + .build(); } +// private Cookie createCookie(String key, String value) { +// Cookie cookie = new Cookie(key, value); +// cookie.setMaxAge(60 * 60 * 60); +// cookie.setSecure(true); +// cookie.setHttpOnly(true); +// cookie.setPath("/"); +// cookie.setDomain("com-n-check.vercel.app"); +// cookie.setAttribute("SameSite", "None"); +// return cookie; +// } + } From b1abd0e050761fe35a43779a5a8b31345659c778 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 2 Mar 2025 20:15:42 +0900 Subject: [PATCH 47/67] =?UTF-8?q?Refactor:=20=ED=94=84=EB=A1=A0=ED=8A=B8?= =?UTF-8?q?=20=EB=8F=84=EB=A9=94=EC=9D=B8=20(=EB=B0=B0=ED=8F=AC=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98)=20=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=8B=9C=ED=81=90=EB=A6=AC=ED=8B=B0=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/security/config/CorsMvcConfig.java | 2 +- .../ComNCheck/domain/security/config/SecurityConfig.java | 2 +- .../domain/security/handler/CustomSuccessHandler.java | 4 ++-- src/main/resources/yaml/application-log.yaml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java index 24960cb..e720699 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java @@ -11,7 +11,7 @@ public class CorsMvcConfig implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .exposedHeaders("Set-Cookie") - .allowedOrigins("https://com-n-check.vercel.app") + .allowedOrigins("https://www.comncheck.com") .allowedMethods("*") .allowCredentials(true); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 1f208e8..a63db6a 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -32,7 +32,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("https://com-n-check.vercel.app/")); + configuration.setAllowedOrigins(Arrays.asList("https://www.comncheck.com")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("*")); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index 9a21805..08034e2 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -43,10 +43,10 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo response.setHeader("Set-Cookie", cookie.toString()); //response.addCookie(createCookie("AccessToken", token)); // Cookie로 했을때 if(!checkStudentCard) { - response.sendRedirect("https://com-n-check.vercel.app/login/first"); //https://com-n-check.vercel.app + response.sendRedirect("https://www.comncheck.com/login/first"); //https://com-n-check.vercel.app } else { - response.sendRedirect("https://com-n-check.vercel.app//notice"); + response.sendRedirect("https://www.comncheck.com/notice"); } //response.sendRedirect("http://localhost:3000/login/first"); diff --git a/src/main/resources/yaml/application-log.yaml b/src/main/resources/yaml/application-log.yaml index ac3684b..d96612c 100644 --- a/src/main/resources/yaml/application-log.yaml +++ b/src/main/resources/yaml/application-log.yaml @@ -4,7 +4,7 @@ spring: on-profile: log jpa: hibernate: - ddl-auto: update + ddl-auto: none properties: hibernate: show_sql: true From 2b60d731a193dbb02c93132631bc99bebcc90dbb Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Mon, 3 Mar 2025 18:41:34 +0900 Subject: [PATCH 48/67] =?UTF-8?q?Refactor:=20=EC=BF=A0=ED=82=A4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=8B=9C=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/security/handler/CustomSuccessHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java index 08034e2..0105c1e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java @@ -76,7 +76,7 @@ private ResponseCookie createCookie(String key, String value) { .secure(true) .sameSite("None") .path("/") - .domain("com-n-check.vercel.app") + .domain("www.comncheck.com") .httpOnly(true) .build(); } From ff5a1838ca0a7fcb56165b8a535741b2db510055 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Wed, 5 Mar 2025 03:10:53 +0900 Subject: [PATCH 49/67] =?UTF-8?q?Refactor:=20=ED=95=99=EB=B6=80=20?= =?UTF-8?q?=EA=B3=B5=EC=A7=80,=20=EC=B7=A8=EC=97=85=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=98=A4=EB=A6=84=EC=B0=A8=EC=88=9C=20=EB=B3=B4=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/EmploymentNoticeRepository.java | 5 +++++ .../employmentNotice/service/EmploymentNoticeService.java | 5 ++--- .../domain/majorNotice/model/entity/MajorNotice.java | 1 - .../majorNotice/repository/MajorNoticeRepository.java | 6 ++++++ .../domain/majorNotice/service/MajorNoticeService.java | 4 ++-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java index 2fd87b2..1db1641 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java @@ -1,9 +1,14 @@ package com.ComNCheck.ComNCheck.domain.employmentNotice.repository; import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface EmploymentNoticeRepository extends JpaRepository { Optional findByEmploymentNoticeId(int employmentNoticeId); + + @Query("SELECT e FROM EmploymentNotice e ORDER BY e.employmentNoticeId DESC") + List findAllOrderedById(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java index 454602e..436ef44 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java @@ -12,7 +12,6 @@ import com.google.firebase.messaging.FirebaseMessagingException; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -88,8 +87,8 @@ public List getAllEmploymentNotices() { } public PageEmploymentNoticeResponseDTO getEmploymentNoticesPage(int page, int size) { - List allEmploymentNotices = employmentNoticeRepository.findAll(); - allEmploymentNotices.sort(Comparator.comparing(EmploymentNotice::getDate).reversed()); + List allEmploymentNotices = employmentNoticeRepository.findAllOrderedById(); + long totalElements = allEmploymentNotices.size(); int totalPages = (int) Math.ceil((double) totalElements / size); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java index ca6a18a..30959ed 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java @@ -1,6 +1,5 @@ package com.ComNCheck.ComNCheck.domain.majorNotice.model.entity; -import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO; import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO; import jakarta.persistence.Column; import jakarta.persistence.Entity; diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java index 7be0912..f602f06 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java @@ -1,10 +1,16 @@ package com.ComNCheck.ComNCheck.domain.majorNotice.repository; + import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface MajorNoticeRepository extends JpaRepository { Optional findByNoticeId(int noticeId); + @Query("SELECT e FROM MajorNotice e ORDER BY e.noticeId DESC") + List findAllOrderedById(); + } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java index 122c60e..41d28ab 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java @@ -87,8 +87,8 @@ public List getAllMajorNotices() { } public PageMajorNoticeResponseDTO getMajorNoticesPage(int page, int size) { - List allNotices = majorNoticeRepository.findAll(); - allNotices.sort(Comparator.comparing(MajorNotice::getDate).reversed()); + List allNotices = majorNoticeRepository.findAllOrderedById(); + long totalElements = allNotices.size(); int totalPages = (int) Math.ceil((double) totalElements / size); From 03dffe1df172da55a41c8e79c5aa3e034bd627dc Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Fri, 7 Mar 2025 23:46:15 +0900 Subject: [PATCH 50/67] =?UTF-8?q?Refactor:=20majorQuestion=20DTO=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=EB=AA=85=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?AnswerUpdateRequestDTO=20=EC=82=AC=EC=9A=A9=EC=95=88=ED=96=88?= =?UTF-8?q?=EB=8D=98=20=EB=B6=80=EB=B6=84=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/majorQuestion/controller/AnswerController.java | 5 +++-- .../domain/majorQuestion/controller/QuestionController.java | 2 +- .../majorQuestion/model/dto/request/AnswerRequestDTO.java | 4 ++-- .../majorQuestion/model/dto/response/AnswerResponseDTO.java | 4 ++-- .../model/dto/response/QuestionResponseDTO.java | 4 ++-- .../domain/majorQuestion/service/AnswerService.java | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java index ed93970..3abff5b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java @@ -1,6 +1,7 @@ package com.ComNCheck.ComNCheck.domain.majorQuestion.controller; import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.AnswerRequestDTO; +import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.AnswerUpdateRequestDTO; import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.AnswerResponseDTO; import com.ComNCheck.ComNCheck.domain.majorQuestion.service.AnswerService; import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member; @@ -34,12 +35,12 @@ public ResponseEntity createOrUpdateAnswer( @Operation(summary = "FAQ 댓글 수정", description = "학생회권한만 댓글 작성자의 관계없이 댓글 수정이 가능하다.") public ResponseEntity updateAnswer( @PathVariable Long answerId, - @RequestBody AnswerRequestDTO answerRequestDTO, + @RequestBody AnswerUpdateRequestDTO answerUpdateRequestDTO, Authentication authentication ) { CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); Long writerId = principal.getMemberDTO().getMemberId(); - AnswerResponseDTO responseDTO = answerService.updateAnswer(answerId, answerRequestDTO.getContent(), writerId); + AnswerResponseDTO responseDTO = answerService.updateAnswer(answerId, answerUpdateRequestDTO.getContent(), writerId); return ResponseEntity.ok(responseDTO); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java index 47ede8e..7fea237 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java @@ -38,7 +38,7 @@ public ResponseEntity createQuestion(@RequestBody QuestionR URI location = ServletUriComponentsBuilder.fromCurrentRequest() .path("/{majorQuestionId}") - .buildAndExpand(responseDTO.getId()) + .buildAndExpand(responseDTO.getMajorQuestionId()) .toUri(); return ResponseEntity.created(location).body(responseDTO); diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java index f474ffe..df0d454 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java @@ -7,6 +7,6 @@ @Setter public class AnswerRequestDTO { private String content; - private Long questionId; + private Long majorQuestionId; -} +} \ No newline at end of file diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java index 264643f..7f5e834 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java @@ -8,7 +8,7 @@ @Getter @Builder public class AnswerResponseDTO { - private Long id; + private Long answerId; private String content; private Long questionId; private Long writerId; @@ -17,7 +17,7 @@ public class AnswerResponseDTO { public static AnswerResponseDTO of(Answer answer) { return AnswerResponseDTO.builder() - .id(answer.getId()) + .answerId(answer.getId()) .content(answer.getContent()) .questionId(answer.getQuestion().getId()) .writerId(answer.getWriter().getMemberId()) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java index db00297..024218b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java @@ -8,7 +8,7 @@ @Getter @Builder public class QuestionResponseDTO { - private Long id; + private Long majorQuestionId; private String title; private String content; //private Long writerId; @@ -19,7 +19,7 @@ public class QuestionResponseDTO { public static QuestionResponseDTO of(Question question) { return QuestionResponseDTO.builder() - .id(question.getId()) + .majorQuestionId(question.getId()) .title(question.getTitle()) .content(question.getContent()) .shared(question.isShared()) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java index 3b4a676..622eefe 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java @@ -33,7 +33,7 @@ public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO, Long .orElseThrow(() -> new MemberNotFoundException("해당 회원이 존재하지 않습니다.")); isCheckRole(writer); - Question question = questionRepository.findById(requestDTO.getQuestionId()) + Question question = questionRepository.findById(requestDTO.getMajorQuestionId()) .orElseThrow(() -> new PostNotFoundException("요청하신 질문이 존재하지 않습니다.")); Answer answer = answerRepository.findByQuestionId(question.getId()).orElse(null); From 1803f1b9406305782474e82f00e68981344d673b Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sat, 8 Mar 2025 01:19:41 +0900 Subject: [PATCH 51/67] =?UTF-8?q?Refactor:=20AnswerResponseDTO=20questionI?= =?UTF-8?q?d=20->=20majorQuestionId=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../majorQuestion/model/dto/response/AnswerResponseDTO.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java index 7f5e834..a115830 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java @@ -10,7 +10,7 @@ public class AnswerResponseDTO { private Long answerId; private String content; - private Long questionId; + private Long majorQuestionId; private Long writerId; private LocalDateTime createdAt; private LocalDateTime updatedAt; @@ -19,7 +19,7 @@ public static AnswerResponseDTO of(Answer answer) { return AnswerResponseDTO.builder() .answerId(answer.getId()) .content(answer.getContent()) - .questionId(answer.getQuestion().getId()) + .majorQuestionId(answer.getQuestion().getId()) .writerId(answer.getWriter().getMemberId()) .createdAt(answer.getCreatedAt()) .updatedAt(answer.getUpdatedAt()) From d0c4745d3cee4fab3e296f520355e02021369e46 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Sun, 9 Mar 2025 23:44:04 +0900 Subject: [PATCH 52/67] =?UTF-8?q?Feat:=20=EC=8A=B9=EC=9D=B8=20=EC=97=86?= =?UTF-8?q?=EC=9D=B4=20=EB=B0=94=EB=A1=9C=20=EB=93=B1=EA=B8=89=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EB=90=98=EB=8A=94=20API=20=EA=B0=9C=EB=B0=9C=20-=20?= =?UTF-8?q?=EA=B3=BC=ED=9A=8C=EC=9E=A5=20=EB=93=B1=EA=B8=89=EB=A7=8C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=20=EA=B0=80=EB=8A=A5=ED=95=9C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/global/config/SwaggerConfig.java | 11 ++++++++++- .../controller/RoleChangeController.java | 14 ++++++++++++++ .../dto/request/RoleChangeUpdateRequestDTO.java | 12 ++++++++++++ .../roleChange/model/entity/RoleChange.java | 5 +++++ .../service/RoleChangeRequestService.java | 17 +++++++++++++++++ .../domain/security/config/CorsMvcConfig.java | 4 ++-- 6 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeUpdateRequestDTO.java diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/SwaggerConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/SwaggerConfig.java index ccd7de2..dac2fdf 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/SwaggerConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/SwaggerConfig.java @@ -3,15 +3,24 @@ import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.security.SecurityScheme.In; +import io.swagger.v3.oas.models.security.SecurityScheme.Type; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SwaggerConfig { + SecurityScheme securityScheme = new SecurityScheme() + .type(Type.APIKEY) + .in(In.COOKIE).name("AccessToken"); + SecurityRequirement securityRequirement = new SecurityRequirement().addList("cookieAuth"); @Bean public OpenAPI openAPI() { return new OpenAPI() - .components(new Components()) + .components(new Components().addSecuritySchemes("cookieAuth", securityScheme)) + .addSecurityItem(securityRequirement) .info(apiInfo()); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java index 386e43a..314157d 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java @@ -2,6 +2,7 @@ import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request.RoleChangeRequestDTO; +import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request.RoleChangeUpdateRequestDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.ApprovedRoleListDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeListDTO; import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeResponseDTO; @@ -83,4 +84,17 @@ public ResponseEntity deleteRequest(@PathVariable Long requestId, return ResponseEntity.noContent().build(); } + @PutMapping("/{requestId}") + @Operation(summary = "특정 학생회 직책이나 등급을 변경", description = "과회장이 특정 학생회 인원의 직책이나 등급을 변경한다") + public ResponseEntity putRoleChange(@PathVariable Long requestId, + @RequestBody RoleChangeUpdateRequestDTO roleChangeUpdateRequestDTO, + Authentication authentication) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + String updatePosition = roleChangeUpdateRequestDTO.getRequestPosition(); + Role updateRole = roleChangeUpdateRequestDTO.getRequestRole(); + RoleChangeResponseDTO responseDTO = roleChangeRequestService.updateRoleChange(requestId, memberId, updatePosition, updateRole); + return ResponseEntity.ok(responseDTO); + } + } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeUpdateRequestDTO.java new file mode 100644 index 0000000..5dd4b7a --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeUpdateRequestDTO.java @@ -0,0 +1,12 @@ +package com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request; + +import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RoleChangeUpdateRequestDTO { + private String requestPosition; + private Role requestRole; +} \ No newline at end of file diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java index ea5d702..4f6eb2c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java @@ -54,5 +54,10 @@ public void approve() { this.status = RequestStatus.APPROVED; } + public void update(String requestPosition, Role requestRole) { + this.requestPosition = requestPosition; + this.requestRole = requestRole; + } + } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java index 308062b..9290c00 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java @@ -106,6 +106,23 @@ public void deleteRequest(Long requestId, Long memberId) { roleChangeRequestRepository.delete(request); } + @Transactional + public RoleChangeResponseDTO updateRoleChange(Long requestId, Long memberId, String updatePosition, Role updateRole) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); + isCheckRole(member); + + RoleChange role = roleChangeRequestRepository.findById(requestId) + .orElseThrow(() -> new ApplyNotFoundException("등록된 학생회 신청이 없습니다.")); + + role.update(updatePosition, updateRole); + Member updateMember = role.getMember(); + updateMember.updateRole(role.getRequestRole()); + updateMember.updatePosition(role.getRequestPosition()); + + return RoleChangeResponseDTO.of(role); + } + public void isCheckRole(Member member) { Role checkRole = member.getRole(); if (checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_ADMIN) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java index 689a160..35e4eca 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java @@ -11,7 +11,7 @@ public class CorsMvcConfig implements WebMvcConfigurer { public void addCorsMappings(CorsRegistry corsRegistry) { corsRegistry.addMapping("/**") .exposedHeaders("Set-Cookie") - .allowedOrigins("http://localhost:3000" - ); // "https://com-n-check.vercel.app" + .allowedOrigins("http://localhost:3000"); // "https://com-n-check.vercel.app" + //.allowCredentials(true); } } From 9d9ad604f550021652ac89288541aaa05ef43806 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Mar 2025 03:58:42 +0900 Subject: [PATCH 53/67] =?UTF-8?q?Feat:=20hufs=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20&=20=EA=B4=80=EB=A6=AC=EC=9E=90=20=EA=B3=84?= =?UTF-8?q?=EC=A0=95=EB=A7=8C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=90=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/service/CustomOAuthMemberService.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index 7fe4f88..612c072 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -32,14 +32,14 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic //String sub = oAuth2User.getAttribute("sub"); 이메일 변경 여부 따지고 변경될경우 findByEmail 대신 findBySub 사용 String hd = oAuth2User.getAttribute("hd"); -// if (!"hufs.ac.kr".equals(hd)) { // 테스트떄는 주석처리 -> 이후 실제 서비스에서는 주석 헤제 -// OAuth2Error oauth2Error = new OAuth2Error( -// "invalid_hosted_domain", -// "허용되지 않은 호스팅 도메인입니다.", -// null -// ); -// throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); -// } + if (!"hufs.ac.kr".equals(hd) && !"comncheck0306@gmail.com".equals(email)) { + OAuth2Error oauth2Error = new OAuth2Error( + "invalid_hosted_domain", + "허용되지 않은 호스팅 도메인입니다.", + null + ); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); + } // 이메일 변경 가능시 sub 변 Member member = memberRepository.findByEmail(email).orElseGet(() -> { From 8ade4d0438e429566497ce224314eb85635780ab Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Mar 2025 04:19:15 +0900 Subject: [PATCH 54/67] =?UTF-8?q?Refactor:=20=EA=B3=BC=ED=96=89=EC=82=AC?= =?UTF-8?q?=20=EC=98=A4=EB=A6=84=EC=B0=A8=EC=88=9C=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=82=B4=EB=A6=BC=EC=B0=A8=EC=88=9C=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A0=A4=20=EB=B3=80=EA=B2=BD=20->=20=EC=95=88?= =?UTF-8?q?=EB=81=9D=EB=82=9C=20=ED=96=89=EC=82=AC=EA=B0=80=20=EB=A7=A8?= =?UTF-8?q?=EC=9C=84=EB=A1=9C=20=EA=B0=88=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/majorEvent/service/MajorEventService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java index f127071..7458cab 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java @@ -106,8 +106,11 @@ public List getAllMajorEventsNotPassed() { // List filtered = all.stream() // 기간 지난 행사 제외 // .filter(e -> isNotPassed(e, today, currentTime)) // .collect(Collectors.toList()); - all.sort(Comparator.comparing(MajorEvent::getDate) - .thenComparing(MajorEvent::getTime)); + all.sort( + Comparator + .comparing(MajorEvent::getDate, Comparator.reverseOrder()) // 날짜 내림차순 + .thenComparing(MajorEvent::getTime, Comparator.reverseOrder()) // 시간 내림차순 + ); return all.stream() .map(EventListResponseDTO::of) From 4dbf2a1f18033b46fe135931ffeb22819b632024 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Mar 2025 04:46:51 +0900 Subject: [PATCH 55/67] =?UTF-8?q?=EB=93=B1=EA=B8=89=20=EC=8B=A0=EC=B2=AD?= =?UTF-8?q?=20=EC=98=A4=EB=A6=84=EC=B0=A8=EC=88=9C=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roleChange/repository/RoleChangeRequestRepository.java | 5 +++++ .../domain/roleChange/service/RoleChangeRequestService.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/repository/RoleChangeRequestRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/repository/RoleChangeRequestRepository.java index 37de7e4..e18d02f 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/repository/RoleChangeRequestRepository.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/repository/RoleChangeRequestRepository.java @@ -1,7 +1,12 @@ package com.ComNCheck.ComNCheck.domain.roleChange.repository; import com.ComNCheck.ComNCheck.domain.roleChange.model.entity.RoleChange; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface RoleChangeRequestRepository extends JpaRepository { + + @Query("SELECT r FROM RoleChange r ORDER BY r.requestId DESC") + List findAllOrderByIdDesc(); } diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java index 9290c00..257e557 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java @@ -47,7 +47,7 @@ public List getAllRequests(Long memberId) { .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); isCheckRole(member); - List requests = roleChangeRequestRepository.findAll(); + List requests = roleChangeRequestRepository.findAllOrderByIdDesc(); return requests.stream() .map(RoleChangeListDTO::of) .collect(Collectors.toList()); From 8e9cf297e90572a3d011f71c6fc5501dd10fdb21 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Mar 2025 06:31:39 +0900 Subject: [PATCH 56/67] =?UTF-8?q?Refactor:=20=EB=82=B4=20=EA=B3=84?= =?UTF-8?q?=EC=A0=95=20=EA=B4=80=EB=A6=AC=EC=9E=90=20=EA=B3=84=EC=A0=95=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/service/CustomOAuthMemberService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index 612c072..29a886d 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -32,7 +32,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic //String sub = oAuth2User.getAttribute("sub"); 이메일 변경 여부 따지고 변경될경우 findByEmail 대신 findBySub 사용 String hd = oAuth2User.getAttribute("hd"); - if (!"hufs.ac.kr".equals(hd) && !"comncheck0306@gmail.com".equals(email)) { + if (!"hufs.ac.kr".equals(hd) && !"comncheck0306@gmail.com".equals(email) && !"another0306@gmail.com".equals(email)) { OAuth2Error oauth2Error = new OAuth2Error( "invalid_hosted_domain", "허용되지 않은 호스팅 도메인입니다.", From 8aec1db79cc553a890e8dfd8a7c9b4cb7371505b Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Mar 2025 07:43:03 +0900 Subject: [PATCH 57/67] =?UTF-8?q?Fix:=20=EB=A1=9C=EC=A7=81=EC=83=81=20hufs?= =?UTF-8?q?=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EC=95=84=EB=8B=90=EC=8B=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EC=B2=98=EB=A6=AC=20=EC=95=88=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EB=B6=80=EB=B6=84=20=ED=95=B4=EA=B2=B0=20=EB=A6=AC?= =?UTF-8?q?=EB=8B=A4=EC=9D=B4=EB=9E=99=ED=8A=B8=EB=A5=BC=20=ED=99=9C?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20=EC=97=90=EB=9F=AC=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/CustomOAuthMemberService.java | 24 ++++++++++++++----- .../security/config/CustomFailureHandler.java | 24 +++++++++++++++++++ .../security/config/SecurityConfig.java | 5 +++- 3 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java index 29a886d..4da58a3 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java @@ -21,6 +21,9 @@ public class CustomOAuthMemberService extends DefaultOAuth2UserService { private final MemberRepository memberRepository; + private final static String ADMIN_EMAIL_1 = "comncheck0306@gmail.com"; + private final static String ADMIN_EMAIL_2 = "another0306@gmail.com"; + @Override @Transactional public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { @@ -32,16 +35,16 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic //String sub = oAuth2User.getAttribute("sub"); 이메일 변경 여부 따지고 변경될경우 findByEmail 대신 findBySub 사용 String hd = oAuth2User.getAttribute("hd"); - if (!"hufs.ac.kr".equals(hd) && !"comncheck0306@gmail.com".equals(email) && !"another0306@gmail.com".equals(email)) { + if (!isAllowedUser(email, hd)) { OAuth2Error oauth2Error = new OAuth2Error( "invalid_hosted_domain", - "허용되지 않은 호스팅 도메인입니다.", - null + "허용되지 않은 호스팅 도메인 혹은 계정입니다.", + "https://www.comncheck.com/login?error=invalid_domain" ); throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); } - // 이메일 변경 가능시 sub 변 + // 이메일 변경 가능시 sub 변수 Member member = memberRepository.findByEmail(email).orElseGet(() -> { Member newMember = Member.builder() .email(email) @@ -52,9 +55,18 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic .build(); memberRepository.save(newMember); return newMember; - }); + }); + + return new CustomOAuth2Member(MemberDTO.of(member)); + } - return new CustomOAuth2Member(MemberDTO.of(member)); + private boolean isAllowedUser(String email, String hd) { + if ("hufs.ac.kr".equals(hd) + || ADMIN_EMAIL_1.equals(email) + || ADMIN_EMAIL_2.equals(email)) { + return true; + } + return false; } private String cleanString(String input) { diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java new file mode 100644 index 0000000..602f09c --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java @@ -0,0 +1,24 @@ +package com.ComNCheck.ComNCheck.domain.security.config; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; + +public class CustomFailureHandler extends SimpleUrlAuthenticationFailureHandler { + + public CustomFailureHandler(String defaultFailureUrl) { + super(defaultFailureUrl); + } + + @Override + public void onAuthenticationFailure( + HttpServletRequest request, + HttpServletResponse response, + AuthenticationException exception + ) throws IOException, ServletException { + super.onAuthenticationFailure(request, response, exception); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index a63db6a..386d302 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -32,7 +32,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("https://www.comncheck.com")); + configuration.setAllowedOrigins(Arrays.asList("http://r-cube.iptime.org:3000")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("*")); @@ -70,6 +70,9 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig .userService(customOAuth2MemberService)) .successHandler(customSuccessHandler) + .failureHandler(new CustomFailureHandler( + "http://r-cube.iptime.org:3000/login?error=invalid_domain" + )) ); http.addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class); From 421d73afa86737a21df5b2ed5e033b1f87febc56 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 11 Mar 2025 10:10:15 +0900 Subject: [PATCH 58/67] =?UTF-8?q?Fix=20SecurityConfig=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/security/config/SecurityConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 386d302..b894111 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -32,7 +32,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://r-cube.iptime.org:3000")); + configuration.setAllowedOrigins(Arrays.asList("https://www.comncheck.com")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("*")); @@ -71,7 +71,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { .userService(customOAuth2MemberService)) .successHandler(customSuccessHandler) .failureHandler(new CustomFailureHandler( - "http://r-cube.iptime.org:3000/login?error=invalid_domain" + "https://www.comncheck.com/login?error=invalid_domain" )) ); From 08e202f70da693ebf97650745a1507819d54667a Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 13 Mar 2025 23:49:06 +0900 Subject: [PATCH 59/67] =?UTF-8?q?Refactor=20:=20MajorEvent=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20notice=20=EC=BB=AC=EB=9F=BC=20TEXT=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/majorEvent/model/entity/MajorEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java index 9876800..06fa58c 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java @@ -42,7 +42,7 @@ public class MajorEvent { @Column(name = "localtion", nullable = false) private String location; - @Column(name = "notice", nullable = false) + @Column(name = "notice", nullable = false, columnDefinition = "TEXT") private String notice; @Column(name = "google_form_link") From b9d8943cfae64403b8a4dab548cfffbab617a254 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Fri, 14 Mar 2025 01:15:28 +0900 Subject: [PATCH 60/67] =?UTF-8?q?Refactor:=20MajorEvent=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComNCheck/domain/majorEvent/model/entity/MajorEvent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java index 9876800..1b1300e 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java @@ -39,10 +39,10 @@ public class MajorEvent { @Column(name = "time", nullable = false) private LocalTime time; - @Column(name = "localtion", nullable = false) + @Column(name = "location", nullable = false) private String location; - @Column(name = "notice", nullable = false) + @Column(name = "notice", nullable = false, columnDefinition = "TEXT") private String notice; @Column(name = "google_form_link") From f2cf50e737645de070f56cca7e0bac9b3adec192 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Mon, 17 Mar 2025 22:52:37 +0900 Subject: [PATCH 61/67] =?UTF-8?q?Feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EA=B3=84=EC=A0=95=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=EB=90=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20CustomAuthorizationRequestResolver=EB=A5=BC=20?= =?UTF-8?q?=ED=99=9C=EC=9A=A9=ED=95=98=EC=97=AC=20prompt=3Dselect=5Faccoun?= =?UTF-8?q?t=20=EB=A5=BC=20=EB=AC=B4=EC=A1=B0=EA=B1=B4=20=EB=B6=99?= =?UTF-8?q?=EC=9D=B4=EA=B2=8C=EB=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomAuthorizationRequestResolver.java | 42 +++++++ .../security/config/CustomFailureHandler.java | 25 ++++ .../security/config/SecurityConfig.java | 112 +++++++++++------- 3 files changed, 134 insertions(+), 45 deletions(-) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomAuthorizationRequestResolver.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomAuthorizationRequestResolver.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomAuthorizationRequestResolver.java new file mode 100644 index 0000000..bf6c7a9 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomAuthorizationRequestResolver.java @@ -0,0 +1,42 @@ +package com.ComNCheck.ComNCheck.domain.security.config; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.LinkedHashMap; +import java.util.Map; +import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; + +public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver { + + private final OAuth2AuthorizationRequestResolver defaultResolver; + + public CustomAuthorizationRequestResolver(OAuth2AuthorizationRequestResolver defaultResolver) { + this.defaultResolver = defaultResolver; + } + + @Override + public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { + OAuth2AuthorizationRequest oAuth2AuthorizationRequest = this.defaultResolver.resolve(request); + return customizeRequest(oAuth2AuthorizationRequest); + } + + @Override + public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) { + OAuth2AuthorizationRequest oAuth2AuthorizationRequest = this.defaultResolver.resolve(request, clientRegistrationId); + return customizeRequest(oAuth2AuthorizationRequest); + } + + private OAuth2AuthorizationRequest customizeRequest(OAuth2AuthorizationRequest oAuth2AuthorizationRequest) { + if (oAuth2AuthorizationRequest == null) { + return null; + } + + Map extraParameters = new LinkedHashMap<>(oAuth2AuthorizationRequest.getAdditionalParameters()); + extraParameters.put("prompt", "select_account"); + + return OAuth2AuthorizationRequest.from(oAuth2AuthorizationRequest) + .additionalParameters(extraParameters) + .build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java new file mode 100644 index 0000000..ad73d1c --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java @@ -0,0 +1,25 @@ +package com.ComNCheck.ComNCheck.domain.security.config; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; + +public class CustomFailureHandler extends SimpleUrlAuthenticationFailureHandler { + + public CustomFailureHandler(String defaultFailureUrl) { + super(defaultFailureUrl); + } + + @Override + public void onAuthenticationFailure( + HttpServletRequest request, + HttpServletResponse response, + AuthenticationException exception + ) throws IOException, ServletException { + + super.onAuthenticationFailure(request, response, exception); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java index 01a5fe2..0d4e489 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java @@ -1,18 +1,23 @@ package com.ComNCheck.ComNCheck.domain.security.config; +import com.ComNCheck.ComNCheck.domain.member.service.CustomOAuthMemberService; import com.ComNCheck.ComNCheck.domain.security.filter.JWTFilter; import com.ComNCheck.ComNCheck.domain.security.handler.CustomSuccessHandler; -import com.ComNCheck.ComNCheck.domain.member.service.CustomOAuthMemberService; import com.ComNCheck.ComNCheck.domain.security.util.JWTUtil; import jakarta.servlet.http.HttpServletRequest; import java.util.Arrays; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; @@ -21,59 +26,76 @@ @RequiredArgsConstructor @EnableWebSecurity public class SecurityConfig { + private final CustomOAuthMemberService customOAuth2MemberService; private final CustomSuccessHandler customSuccessHandler; private final JWTUtil jwtUtil; + private final ClientRegistrationRepository clientRegistrationRepository; + private final OAuth2AuthorizedClientRepository authorizedClientRepository; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http - .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() { - @Override - public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { - CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); - configuration.setAllowCredentials(true); - configuration.setAllowedHeaders(Arrays.asList("*")); - configuration.setMaxAge(3600L); - configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "AccessToken")); - return configuration; - } - })) - .csrf(csrf -> csrf.disable()) - .formLogin(form -> form.disable()) - .httpBasic(httpBasic -> httpBasic.disable()) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(auth -> auth - .requestMatchers( - "/login/**", - "/oauth2/**", - "/swagger-ui.html", - "/swagger-ui/**", - "/V3/api-docs", - "/v3/api-docs/**", - "/swagger-resources/**", - "/webjars/**", - "/api/v1/**" - ).permitAll() - .anyRequest().authenticated() - ) - .oauth2Login(oauth2 -> oauth2 - .authorizationEndpoint(authorization -> authorization - .baseUri("/oauth2/authorize") - ) - .redirectionEndpoint(redirection -> redirection - .baseUri("/login/oauth2/code/*") - ) - .userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig - .userService(customOAuth2MemberService)) - .successHandler(customSuccessHandler) - ); + http.cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() { + @Override + public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); + configuration.setAllowCredentials(true); + configuration.setAllowedHeaders(Arrays.asList("*")); + configuration.setMaxAge(3600L); + configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "AccessToken")); + return configuration; + } + })); + + http.csrf(csrf -> csrf.disable()) + .formLogin(Customizer.withDefaults()).formLogin(form -> form.disable()) + .httpBasic(Customizer.withDefaults()).httpBasic(httpBasic -> httpBasic.disable()) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + + http.authorizeHttpRequests(auth -> auth + .requestMatchers( + "/login/**", + "/oauth2/**", + "/swagger-ui.html", + "/swagger-ui/**", + "/V3/api-docs", + "/v3/api-docs/**", + "/swagger-resources/**", + "/webjars/**", + "/api/v1/**" + ).permitAll() + .anyRequest().authenticated() + ); + + http.oauth2Login(oauth2 -> oauth2 + .authorizationEndpoint(authorization -> authorization + .baseUri("/oauth2/authorize") + // ★ 커스텀 AuthorizationRequestResolver 등록 + .authorizationRequestResolver(customAuthorizationRequestResolver()) + ) + .redirectionEndpoint(redirection -> redirection + .baseUri("/login/oauth2/code/*") + ) + .userInfoEndpoint(userInfoEndpointConfig -> + userInfoEndpointConfig.userService(customOAuth2MemberService) + ) + .successHandler(customSuccessHandler) + .failureHandler(new CustomFailureHandler("http://localhost:3000/login?error=invalid_domain")) + ); http.addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class); return http.build(); } + + @Bean + public OAuth2AuthorizationRequestResolver customAuthorizationRequestResolver() { + DefaultOAuth2AuthorizationRequestResolver defaultResolver = + new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, "/oauth2/authorize"); + + return new CustomAuthorizationRequestResolver(defaultResolver); + } } From 3b72828fa7b359171e3c314fd78c46fc631ff697 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 27 Mar 2025 01:18:17 +0900 Subject: [PATCH 62/67] =?UTF-8?q?Docs:=20README.md=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a494f0a..48d6c55 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,68 @@ -# backend +

Image -## branch 특징 -### main : 배포 -### develop : 개발 + + +# 1. OverView(프로젝트 개요) +- 프로젝트 이름: ComNCheck +- 프로젝트 설명: 한국외국어대학교 컴퓨터공학부 알리미 +- 프로젝트 시작 계기 : 학창시절 과회장을 하면서 학부 행사 같은 경우 카톡방에 쌓이고, 학교 공지는 홈페이지에 수시로 들어가야 하는 불편함을 하나의 서비스로 해결하기 위해 +- 프로젝트 사이트 : https://www.comncheck.com +- 프로젝트에서 하고 싶었던 부분 : Spring, FastAPI 백엔드 개발, 쿠버네티스 기반 서버 구축 및 운영 +# 2. Team Members (팀원 및 팀 소개) +| 조성민 | 노성원 | 이예림 | +|:------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:| +| Lead, BE, Server | FE, UI/UX Designer | FE, UI/UX Designer | +|

|

|

| +| [@sungmin306](https://github.com/sungmin306) | [@sungwonnoh](https://github.com/sungwonnoh) | [@YerimLee](https://github.com/yerimi00) | +# 3. Project Preview +

+ +- 약 134명의 사용자가 현재 접속하여 사용중(2025.03.24 기준) + +# 4. Architecture +

+ +1. 단일 노드에서 `K3s` 기반으로 구축했다.(기존 GCP에서 미니PC 설치 후 서버 이동) +2. 클라이언트(Client)는 `Nginx` 서버로 접속한다. → 80 또는 **`443`** + - Nginx 내부적으로 Certbot을 이용하여 SSL 인증을 진행 +3. `Nginx`는 “/” 경로로 온 요청은 Next.js 컨테이너로 요청을 보낸다. +4. `Nginx`는 “/api” 경로로 온 요청은 `Spring` 컨테이너로 요청을 보낸다. + - 직접적으로 외부 통신 하지 않는 파드 같은 경우 Cluster IP로 설정하여 외부 서버에서 접근하는것을 막았다. + - `FastAPI` 및 `Next.js` 같은 경우 Replicaset 기반으로 5개의 파드가 동작해 비스의 확장성과 안정성이 보장한다. +5. 모든 요청과 응답은 `Nginx`를 통해 전달한다. +6. DB 서버는 백업기능을 위해 서버 로컬에서 관리한다. + +# 5. Service Detail +| 일정 관리 | 알람 기능 | +|:---------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:| +| Image | Image | +| **익명 질문** | **추가 기능** | +| Image | Image | + +# 4. Tech stack + +### Backend + + + + + + + + + +# 5. 앞으로의 목표 + +백엔드 + +- [ ] 테스트코드 작성 +- [ ] 레디스 이용 → 성능 최적화 +- [ ] 코드 리펙토링(클린코드 만들기) +- [ ] 로직개선 + +클라우드 + +- [ ] control-plane, worker 노드 분리(고가용성) +- [ ] HPA 설정 +- [ ] 모니터링 툴 세팅 +- [ ] CI/CD 환경구성 From c43ece289b2815defda652b05a6d6db7fd6bcfcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=84=B1=EB=AF=BC?= <101984130+sungmin306@users.noreply.github.com> Date: Thu, 27 Mar 2025 01:21:21 +0900 Subject: [PATCH 63/67] Update README.md --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index 48d6c55..69aec04 100644 --- a/README.md +++ b/README.md @@ -43,12 +43,7 @@ ### Backend - - - - - - + # 5. 앞으로의 목표 From ffb1782aaa434e5ac3aa2d60e4ceafef4b32e62b Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Mon, 19 May 2025 22:17:46 +0900 Subject: [PATCH 64/67] =?UTF-8?q?Feat:=20=EB=8B=A4=EB=A5=B8=20=EA=B3=B5?= =?UTF-8?q?=EC=A7=80=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ComNCheck/ComNCheck/domain/.DS_Store | Bin 0 -> 10244 bytes .../controller/AnotherEventController.java | 90 +++++++++ .../dto/request/EventCreateRequestDTO.java | 31 +++ .../dto/request/EventUpdateRequestDTO.java | 33 ++++ .../dto/response/EventListResponseDTO.java | 29 +++ .../model/dto/response/EventResponseDTO.java | 36 ++++ .../response/PagedEventListResponseDTO.java | 25 +++ .../model/entity/AnotherEvent.java | 90 +++++++++ .../repository/AnotherEventRepository.java | 7 + .../service/AnotherEventService.java | 178 ++++++++++++++++++ .../domain/developerQuestion/.DS_Store | Bin 0 -> 6148 bytes .../domain/developerQuestion/model/.DS_Store | Bin 0 -> 6148 bytes .../domain/employmentNotice/.DS_Store | Bin 0 -> 6148 bytes .../domain/employmentNotice/model/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/ComNCheck/domain/fcm/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/fcm/model/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/global/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/majorEvent/.DS_Store | Bin 0 -> 6148 bytes .../domain/majorEvent/model/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/majorNotice/.DS_Store | Bin 0 -> 6148 bytes .../domain/majorNotice/model/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/majorQuestion/.DS_Store | Bin 0 -> 6148 bytes .../domain/majorQuestion/model/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/member/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/member/model/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/roleChange/.DS_Store | Bin 0 -> 6148 bytes .../domain/roleChange/model/.DS_Store | Bin 0 -> 6148 bytes .../ComNCheck/domain/security/.DS_Store | Bin 0 -> 6148 bytes 28 files changed, 519 insertions(+) create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/controller/AnotherEventController.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventCreateRequestDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventUpdateRequestDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventListResponseDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventResponseDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/PagedEventListResponseDTO.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/repository/AnotherEventRepository.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/service/AnotherEventService.java create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/fcm/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/global/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/member/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/member/model/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/.DS_Store create mode 100644 src/main/java/com/ComNCheck/ComNCheck/domain/security/.DS_Store diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3848306592aefd2dc70db7f83adef0938cae4051 GIT binary patch literal 10244 zcmeHMJ8#oa6h3ZC9xX*dq7o8|r7jE+O&>Ikx`Z?p6$7FTf`L|P+?Y14V@G*3s;Wv^ zSYYYE%*X(LfROMO{3xm)CT3z$eJ(L`bQBIvOinGXW%sP2?L1}=r|}5_#@inDNqT*V>VGL zf-V%^!KmL?_qd|t`<+-)x z9}~4Xu1(VbY}4^$Kn^UK%dH7SN&OgZGm7Ik2fH|S%dkx6 za~#VupGP;5PuDz=*X%Qwmq%`kpI@%blZXgo0#9M4k(qAnd1s1Tr%EnYkL!w~%|Bb> z3v`T)3w&2WdN0bHpOSY_k8F|m^Pk_E-uFbbl91UvXmwQ<~-GM`$&D^KLL^wQzxbr?qwd3!vj#BDY?75-;{Wq~z32DWDWk3Md7X z0s|^A%&VN&%(7Syn(BNoUe2WY}CfYbQ(A+I4K3*vLlm8Z1%> z?&xwnM!Fo2CuBMPDmIc!ix7UC createAnotherEvent( + @ModelAttribute EventCreateRequestDTO requestDTO, + Authentication authentication + ) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + EventResponseDTO responseDTO = anotherEventService.createAnotherEvent(requestDTO, memberId); + return ResponseEntity.ok(responseDTO); + } + + @Operation( + summary = "특정 AnotherEvent 게시글 조회", + description = "특정 AnotherEvent 게시글을 조회한다." + ) + @GetMapping("/{anotherEventId}") + public ResponseEntity getAnotherEvent( + @PathVariable Long anotherEventId + ) { + EventResponseDTO responseDTO = anotherEventService.getAnotherEvent(anotherEventId); + return ResponseEntity.ok(responseDTO); + } + + @Operation( + summary = "AnotherEvent 게시글 목록 조회", + description = "AnotherEvent 게시글 목록을 조회한다. 이미 지난 행사는 제외된다." + ) + @GetMapping + public ResponseEntity> getAllAnotherEventsNotPassed() { + List list = anotherEventService.getAllAnotherEventsNotPassed(); + return ResponseEntity.ok(list); + } + + @Operation( + summary = "AnotherEvent 게시글 수정", + description = "작성된 AnotherEvent 게시글을 수정한다. 관리자, 과회장, 학생회만 가능하다." + ) + @PutMapping("/{anotherEventId}") + public ResponseEntity updateAnotherEvent( + @PathVariable Long anotherEventId, + @ModelAttribute EventUpdateRequestDTO requestDTO, + Authentication authentication + ) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + EventResponseDTO updateDTO = anotherEventService.updateAnotherEvent(anotherEventId, requestDTO, memberId); + return ResponseEntity.ok(updateDTO); + } + + @Operation( + summary = "AnotherEvent 게시글 삭제", + description = "작성된 AnotherEvent 게시글을 삭제한다. 관리자, 과회장, 학생회만 가능하다." + ) + @DeleteMapping("/{anotherEventId}") + public ResponseEntity deleteAnotherEvent( + @PathVariable Long anotherEventId, + Authentication authentication + ) { + CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal(); + Long memberId = principal.getMemberDTO().getMemberId(); + anotherEventService.deleteAnotherEvent(anotherEventId, memberId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventCreateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventCreateRequestDTO.java new file mode 100644 index 0000000..0b45482 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventCreateRequestDTO.java @@ -0,0 +1,31 @@ +package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.multipart.MultipartFile; + +@Getter +@Setter +public class EventCreateRequestDTO { + + private String eventName; + private String date; + private String time; + private String location; + private String notice; + private String googleFormLink; + + private List cardNewsImages; + + public LocalDate getParsedDate() { + return date != null ? LocalDate.parse(date) : null; + } + + public LocalTime getParsedTime() { + return time != null ? LocalTime.parse(time) : null; + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventUpdateRequestDTO.java new file mode 100644 index 0000000..c2e261c --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventUpdateRequestDTO.java @@ -0,0 +1,33 @@ +package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +@Getter +@Setter +public class EventUpdateRequestDTO { + + private String eventName; + private String date; + private String time; + private String location; + private String notice; + private String googleFormLink; + private String firstImageUrl; + + private List cardNewsImages; + + public LocalDate getParsedDate() { + return date != null ? LocalDate.parse(date) : null; + } + + public LocalTime getParsedTime() { + return time != null ? LocalTime.parse(time) : null; + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventListResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventListResponseDTO.java new file mode 100644 index 0000000..7b7d9a5 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventListResponseDTO.java @@ -0,0 +1,29 @@ +package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response; + +import com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity.AnotherEvent; +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDate; +import java.time.LocalTime; + +@Getter +@Builder +public class EventListResponseDTO { + + private Long id; + private String eventName; + private LocalDate date; + private LocalTime time; + private String location; + + public static EventListResponseDTO of(AnotherEvent anotherEvent) { + return EventListResponseDTO.builder() + .id(anotherEvent.getAnotherEventId()) + .eventName(anotherEvent.getEventName()) + .date(anotherEvent.getDate()) + .time(anotherEvent.getTime()) + .location(anotherEvent.getLocation()) + .build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventResponseDTO.java new file mode 100644 index 0000000..7ae08f7 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventResponseDTO.java @@ -0,0 +1,36 @@ +package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response; + +import com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity.AnotherEvent; +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +@Getter +@Builder +public class EventResponseDTO { + + private Long id; + private String eventName; + private LocalDate date; + private LocalTime time; + private String location; + private String notice; + private String googleFormLink; + private List cardNewsImageUrls; + + public static EventResponseDTO of(AnotherEvent anotherEvent) { + return EventResponseDTO.builder() + .id(anotherEvent.getAnotherEventId()) + .eventName(anotherEvent.getEventName()) + .date(anotherEvent.getDate()) + .time(anotherEvent.getTime()) + .location(anotherEvent.getLocation()) + .notice(anotherEvent.getNotice()) + .googleFormLink(anotherEvent.getGoogleFormLink()) + .cardNewsImageUrls(anotherEvent.getCardNewsImageUrls()) + .build(); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/PagedEventListResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/PagedEventListResponseDTO.java new file mode 100644 index 0000000..7b97da6 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/PagedEventListResponseDTO.java @@ -0,0 +1,25 @@ +package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class PagedEventListResponseDTO { + private int currentPage; + private int totalPages; + private long totalElements; + private int size; + private List content; + + public PagedEventListResponseDTO(int currentPage, int totalPages, long totalElements, + int size, List content) + { + this.currentPage = currentPage; + this.totalPages = totalPages; + this.totalElements = totalElements; + this.size = size; + this.content = content; + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java new file mode 100644 index 0000000..a42ac3a --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java @@ -0,0 +1,90 @@ +package com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity; + +import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.List; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class AnotherEvent { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long anotherEventId; + + @Column(name = "event_name", nullable = false) + private String eventName; + + @Column(name = "date", nullable = false) + private LocalDate date; + + @Column(name = "time", nullable = false) + private LocalTime time; + + @Column(name = "location", nullable = false) + private String location; + + @Column(name = "notice", nullable = false, columnDefinition = "TEXT") + private String notice; + + @Column(name = "google_form_link") + private String googleFormLink; + + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "event_card_news_images", joinColumns = @JoinColumn(name = "event_id")) + @Column(name = "image_url") + private List cardNewsImageUrls = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "writer_id") + private Member writer; + + @Builder + public AnotherEvent(Member writer, String eventName, LocalDate date, LocalTime time, + String location, String notice, String googleFormLink, + List cardNewsImageUrls) { + this.writer = writer; + this.eventName = eventName; + this.date = date; + this.time = time; + this.location = location; + this.notice = notice; + this.googleFormLink = googleFormLink; + if (cardNewsImageUrls != null) { + this.cardNewsImageUrls = cardNewsImageUrls; + } + } + + public void updateEvent(String eventName, LocalDate date, LocalTime time, + String location, String notice, String googleFormLink) { + this.eventName = eventName; + this.date = date; + this.time = time; + this.location = location; + this.notice = notice; + this.googleFormLink = googleFormLink; + } + + public void updateCardNewsImages(List newImageUrls) { + this.cardNewsImageUrls.clear(); + this.cardNewsImageUrls.addAll(newImageUrls); + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/repository/AnotherEventRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/repository/AnotherEventRepository.java new file mode 100644 index 0000000..5dfe0b3 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/repository/AnotherEventRepository.java @@ -0,0 +1,7 @@ +package com.ComNCheck.ComNCheck.domain.anotherEvent.repository; + +import com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity.AnotherEvent; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AnotherEventRepository extends JpaRepository { +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/service/AnotherEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/service/AnotherEventService.java new file mode 100644 index 0000000..7b78413 --- /dev/null +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/service/AnotherEventService.java @@ -0,0 +1,178 @@ +package com.ComNCheck.ComNCheck.domain.anotherEvent.service; + +import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService; +import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException; +import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException; +import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException; +import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request.EventCreateRequestDTO; +import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request.EventUpdateRequestDTO; +import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response.EventListResponseDTO; +import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response.EventResponseDTO; +import com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity.AnotherEvent; +import com.ComNCheck.ComNCheck.domain.anotherEvent.repository.AnotherEventRepository; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Member; +import com.ComNCheck.ComNCheck.domain.member.model.entity.Role; +import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository; +import com.google.cloud.storage.BlobInfo; +import com.google.cloud.storage.Storage; +import com.google.firebase.messaging.FirebaseMessagingException; +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class AnotherEventService { + + private final AnotherEventRepository anotherEventRepository; + private final MemberRepository memberRepository; + private final FcmService fcmService; + + @Value("${spring.cloud.gcp.storage.bucket}") + private String bucketName; + + private final Storage storage; + + @Transactional + public EventResponseDTO createAnotherEvent(EventCreateRequestDTO requestDTO, Long writerId) { + Member writer = memberRepository.findByMemberId(writerId) + .orElseThrow(() -> new MemberNotFoundException("존재하지 않는 회원입니다.")); + + isCheckRole(writer); + + List imageUrls = uploadImagesToGcs(requestDTO.getCardNewsImages()); + + LocalDate eventDate = requestDTO.getParsedDate(); + LocalTime eventTime = requestDTO.getParsedTime(); + AnotherEvent anotherEvent = AnotherEvent.builder() + .writer(writer) + .eventName(requestDTO.getEventName()) + .date(eventDate) + .time(eventTime) + .location(requestDTO.getLocation()) + .notice(requestDTO.getNotice()) + .googleFormLink(requestDTO.getGoogleFormLink()) + .cardNewsImageUrls(imageUrls) + .build(); + AnotherEvent savedAnotherEvent = anotherEventRepository.save(anotherEvent); + + String title = "새로운 행사 등록"; + String body = requestDTO.getEventName() + " 행사가 등록되었습니다."; + memberRepository.findAll().forEach(member -> { + member.getFcmTokens().forEach(fcmToken -> { + if (fcmToken.isValid() && fcmToken.getToken() != null && !fcmToken.getToken().isBlank()) { + try { + fcmService.sendMessageToToken(fcmToken.getToken(), title, body); + } catch (FirebaseMessagingException e) { + System.out.println("전송 실패"); + } + } + }); + }); + + return EventResponseDTO.of(savedAnotherEvent); + } + + @Transactional + public void deleteAnotherEvent(Long anotherEventId, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); + isCheckRole(member); + + AnotherEvent anotherEvent = anotherEventRepository.findById(anotherEventId) + .orElseThrow(() -> new PostNotFoundException("요청하신 행사가 없습니다.")); + anotherEventRepository.delete(anotherEvent); + } + + public EventResponseDTO getAnotherEvent(Long anotherEventId) { + AnotherEvent anotherEvent = anotherEventRepository.findById(anotherEventId) + .orElseThrow(() -> new PostNotFoundException("요청하신 행사가 없습니다.")); + return EventResponseDTO.of(anotherEvent); + } + + public List getAllAnotherEventsNotPassed() { + List all = anotherEventRepository.findAll(); + + LocalDate today = LocalDate.now(); + LocalTime currentTime = LocalTime.now(); + + all.sort( + Comparator + .comparing(AnotherEvent::getDate, Comparator.reverseOrder()) + .thenComparing(AnotherEvent::getTime, Comparator.reverseOrder()) + ); + + return all.stream() + .map(EventListResponseDTO::of) + .collect(Collectors.toList()); + } + + @Transactional + public EventResponseDTO updateAnotherEvent(Long anotherEventId, EventUpdateRequestDTO requestDTO, Long memberId) { + Member member = memberRepository.findByMemberId(memberId) + .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다.")); + isCheckRole(member); + + AnotherEvent anotherEvent = anotherEventRepository.findById(anotherEventId) + .orElseThrow(() -> new PostNotFoundException("요청하신 행사가 없습니다.")); + + LocalDate eventDate = requestDTO.getParsedDate(); + LocalTime eventTime = requestDTO.getParsedTime(); + + anotherEvent.updateEvent( + requestDTO.getEventName(), + eventDate, + eventTime, + requestDTO.getLocation(), + requestDTO.getNotice(), + requestDTO.getGoogleFormLink() + ); + if (requestDTO.getCardNewsImages() != null && !requestDTO.getCardNewsImages().isEmpty()) { + List newImageUrls = uploadImagesToGcs(requestDTO.getCardNewsImages()); + anotherEvent.updateCardNewsImages(newImageUrls); + } + + return EventResponseDTO.of(anotherEvent); + } + + private List uploadImagesToGcs(List images) { + if (images == null || images.isEmpty()) { + return new ArrayList<>(); + } + List uploadUrls = new ArrayList<>(); + for (MultipartFile file : images) { + try { + String uuid = UUID.randomUUID().toString(); + String contentType = file.getContentType() != null ? file.getContentType() : "application/octet-stream"; + BlobInfo blobInfo = BlobInfo.newBuilder(bucketName, uuid) + .setContentType(contentType) + .build(); + storage.create(blobInfo, file.getInputStream()); + uploadUrls.add("https://storage.googleapis.com/" + bucketName + "/" + uuid); + } catch (IOException e) { + throw new RuntimeException("이미지 업로드 실패", e); + } + } + return uploadUrls; + } + + public void isCheckRole(Member member) { + Role role = member.getRole(); + if (role != Role.ROLE_ADMIN + && role != Role.ROLE_MAJOR_PRESIDENT + && role != Role.ROLE_STUDENT_COUNCIL) { + throw new ForbiddenException("접근 권한이 없습니다."); + } + } +} diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..112e67d682e80413f145c884312a380ca4731377 GIT binary patch literal 6148 zcmeHKJ5B>J5FLjgqNIsLL+KuxRJ2R9^hlvdiSpy4-E5Qq5>(3xI0QWs1zZ4$BhXWD z1?s%9O|aRlph6LviR|Yc&)9F@%63dds(mqN5jBaZhQe5_qgrCz&!u1$=iy{!#+Xt@ z34TMG7NW%=3Wx%$rU0+qI`y$`$8?TWyI8-;ajVnM(upO!`Cb;6W^vq0vL5vK9Bb)RN;hLe|{W?xK}M}+eq@ceb? zGo%SP%;*$qWq7^{nN)Vm;(SgYqu25Ez0+yQm_ECoVnd$%IcWp@cn7`&%RUW5hRx?< zgwO4!vGe&2zm4OwDvt{JXyzlfnhM~|W~((UN-YYA0;0e|0p1@p3S;Cjw`jHwROSi* ztio*!ZF2?zH9LTj!`vb~FlAGLHdVPRhO+7KYZn(e%q`k41|P*+D8|sIxdDtE<`&_B$sYkDgH)oxpDHj1@G+Tv literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4d557817dcdcf244f6514e1274f21f2961d4bea5 GIT binary patch literal 6148 zcmeHKJ5B^K47HgBjYP90Wh6?fy+K$F1@&G4Era-IhpYq?baMj^!5O#$7only05pha zI}0-~P$C4jl)S`_?aW(koDdODuj&cWn21U=L6*UQhI0OHb0n}`fa?{XzXTTY72HqHu z^C6%K#*D3@9v$fP2>={Ht%9-MErCH4z?iW$ga*Rq3N%;FPYgD9=tEu?Gq#52POO;` zCud$gUO3-uIp}iYXz0B&;0*K`C~P{G`oD+2(%>V%@8UCOz!~^s4DhI$Ra1OauC1Rw zPik#IJ3teWb*&5_7;7m8YAMD<&XFxOnmx!E_L#9XlqjNCcc5Pclo0QnfgfPt6%rmv AO8@`> literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7c31c49b462708deecdb5589c6b78e2f527f2c19 GIT binary patch literal 6148 zcmeHKJxjwt7=EvoNt;Lu;; z;*W3?eC~rb*Ccckk@qckPx9V#cTb*>yB-mV_NCtT3}%t!sa4_R@S-x^l-1qlLaz+#H>26hfa5 zb%CvJ?;Yw=t!YgMcXa>#s5DuOg_3-RJ%1Myz^52?11e+S>HC~{(n?_{CS_h?zB17^Ljj9VOvmL7oxfSoCs6d+|FMzJWL?bc? P{v)7l;EEmiRR?|mH;%d7 literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3f0a47688c233d75258b4425f46b47aaa6fcf1f0 GIT binary patch literal 6148 zcmeHK!A`?447KSrD#2k#j`;-k2W2V;&ies0iU4V)JJ18Sdjt5E=-ZE6`jyJu%qap$}tL6;(m#c3pC@WHW0( z#bX>(uivXT+i^6=u_Yl6hy#Dk0sZc-P@7^pr9;ZSzopmN_9za+RzGebU%7aHy85`A z?BqF}g`B}rcAwDu4^^#>5e=cIk6)LD?tbFk&f{fueLlQ>J>Rpg!ZD*b)whUSptD2~ z^mU-F@2cC_gSt#>R#SB{)#NZzCB+PP{%zya5OWWp;S4J_0uJfYRigIUrvhG9)A(ho zsfsajV`hC?#C3J@dX}LND@f;1*`}_mu>1{$GmNaZo6W70>qlP094qx~KC3{F_D&*o z0B5$2%Bn%B#Q||Z9GE(w_Xi(EV_-2c$Xf?0{saJeNORzt_kN(S6TrY?Vh|aGGF^eD ztFoUM%5+EGx4gh&V$gIa#WQ0ZJF~K1D2iuC-e)?gz@XIPfH>efuxxH?`uyLW|NZZF zk~?ug9QaobC@*Y=4Lp)PTXPSm&srbl07Zx9B?h?*DtjFBg+7YcQ8>`%>kD9DF)@e? PLjDM_4N{2%zv{pbkG{jm literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..db040e55315761dbf8cfbe59aff3bb49b255062c GIT binary patch literal 6148 zcmeHK%T2^E5S?Ko6p71TkT|-9?I5fI4J-wq5CljYvIjVDO9wOp1<(LU9H@di5N|%P zganQV!Hi@-dwzD_YCSd)@%*x$5lx9GM-yZjjEJa5O&jhkMwT42#ZlX=MpFD6p&3;u+dif7NUsd3*Mc zYhOP+zdYXR+Mj&ZJNU|{zYqDnLxO=|AQ%V+{wV{f*&_LtVf4X3Fc1v9Ga%(CHHZm_e3xASuhX`{4oYND;MP)ALX@m@Oe^e6WSq~ ti1>9ffMBep7^tNf6FEnA)M)l3W7rGF&QP+5Uc-TL5l}*+3kH6GfmcvONTmP( literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/global/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f5daaeb3284f25cde4506a862d63969ebabe56f5 GIT binary patch literal 6148 zcmeHK!AiqG5S^_>QWXgz(&L^*kX}5;62BlnplxGSS`%Um9`gZ${(%VIJbUrbqyOO_ z_zAw*U20-t>q$grVE1iiXEtwNLMBT@syiKYh^o(-TfYn;R$~TBW74zY zdlFy?YEewr;1W|x6L0~i^4qlaSRYm7^l-m-areTazyqJSuXn$6~|Ta;cD z5CuemxdQxs&}fW-!`!0zbf7aw0ALetV;J*Uf^)RPz+r9?GcaXSfi_jSBZji+@M{+r zILs~DbW-l{q1>I7JE16ZcdV~XIH|y*^rC<$P*z~YUiw`BkG?(|6 zMqw9Qa<#RxIj*%D?HG-X<8q7h6bwu$Ml6@&HkvW`H4lJ+!`vb~F!>QMGDs&1{Hg*U D$@_j2 literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f531e70c4b3bd35084f79a54cda2d061815f4480 GIT binary patch literal 6148 zcmeHKy-EW?5S}#=kJtn&!RF8xFooEj;e<3+d4ZT8)OhEG_ydB)y^4)sX(S5oW(FJzxZ2u-ljdm|fM~3iPTo#vRaokO^F2;kW z*5qO9ezI2{+y8a!=-6F9#FVs5Dfsnqx+FfkodbW=<+Snk-kH8?PELNBeKDCI;jf?b z`Zee?pbNl)NHn3)u8mEfG8je%oO1BAw*-0EanFF z(Sc510f1Gwwc%OUAYjN2U}P~j2oFq|RG>*!_KKlQI{cxHi!9~_O*$#PGUl->D|V?0O18EZz8u%u5Uqp8 p#&Nkpor2DmWBtITcpXg}#zKAoMiz5}@WAAcfR;fzQQ%J%_ylSyo16du literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..20a2c97e5ccad25ff129fee116c66057bbf9b925 GIT binary patch literal 6148 zcmeHKu}%Xq47F)hom2@`OpI9>`v=!@>`46qR1N`BkLv&fTfTuAvGE7|01E>PU&05l z@oWcrM-N7Xs4XQgv12>;s>TTs@${-36OD){Lla~fbcm=sOR?VbV3)%c#d}6 z&N|%xYH#L#e%QOYd(_;m7*)O6!FOxg`;gz;#Tjr0oB?NGLm5EL7RiQ&-a7-%fHUyP zfSeBjO)yUw4fW_ir%wQ2A8Hkh^==6aq5$Rzqaid9Hdmmza(ZI0xkDe)x;$YtGt{;IGvA$Zxy&%o%V7{uu+@FJ{FQAC+qB z+UH5F4QNMbBC;;Z0D`fWVxX2{OynHdRioL1jA73cMnj1rdUXf-ML-Gh&KdXx2HpYb C;z;iR literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..29bbb6e61fce8f5568baf60ed88965aa3fadca77 GIT binary patch literal 6148 zcmeHKJxjwt7=EvAWqH}+`9Q2 zw41ZPz~??_b4@}w5qaNo_ayH{-Dw7hQTn!<^(&y4*WF-M7Pl7LgV6Ije%L|2@;QCJzkQq> zra8T(oZ(q=osjDfRgI1jMbP8p*Qdx{Ps$s4yri!6!Q^H8N$JWQGYIGUmT@z5u22Ad zJ*e|-bvy4+muO9DdN}xQe|;!T7Gtg?n_xWpS90VBGxl@#{#cu7rr z$9L1WSL0L0m`R_Oac!OIeU_mQZ;-B`vP*qiVSN`07Z^!x Q83g|kP&RPI4*aSEKd!XB=>Px# literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a2f8e3e10b9a4c939bf90ac2ec9ae1832f0d6f7e GIT binary patch literal 6148 zcmeHKu}%Xq47ItcI*FxXfia)JNqoRj9beENK;;l1^|%f&Fd$`RjjT0i`>2+NYO^7H*6J!|-h^PlmTWPTvSz;8kleSq7g!sKG z*?UGcT~WI@>+XNNyRtNGRm~Ue9GZNm$X;(BUJkp~dV_U&-i^8sHyYC^T_WQJ+Ra+l z$8~!*_uaw$+w+s=?!{=@)egQ})8B{u-Y(97GvEw31OJo()NGM_+t7Pwz!`7`J{gen zA)pDC38SGN9q9B4031QBg0bE$fk70&GGR1?2EyhFG*?bf3^sS@Lt0lRjE3e;teFuf zW&U`)aJt!Y(B;IXq4&;!Gtg%sv*|?Y{}KL5gOB{ai_e?^XW)-9z@utbP4Q8wwto3M zskH&^7)?ahMHxUa)=~`AQjCe5BYSEzdyp~gWx{AEQADrqK)(nmA>KIyKfu5{p=(9X literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6af873ebb488b070a469578416c8f2ea9b88519b GIT binary patch literal 6148 zcmeHKJ5B>J5FNuJqR^zIwD=TA6v+XQmS{OaE)XRf@zE|Dg^xtHH-H-;(Na^=Qotc7 zfszX#-q=>K*{q;K5t@nY=e1|-w{K-nOhl@CmUf6*MASfGjGCxs7>{$Q*n;cfU}ff* zP(c}fBbrpar9%`D1?Eiw-n&g2V&5LqDR%92|7QE0-mu8Wmhk#*onKxg$sj8R7;o%s zv>&hUA9m|~(_j0J5B&ApOk;_1@Jn&JWFfoGRygW&+AQAtug`{)7oQhjOlEt8>tFHu zP3SYCF*uyiA=E1Hd=WBqJStM3QQH?^FgC9#tuu1=IB6W zt^mLY-Nw*vaRaCw#tuu17=bAp3bdihT``mmN56J{vBT1$4JYL;AIhz)+zmyU)iJ*| z?xbRiQi}qjK&Zf?eQa_5->bj>he7fr3Wx&#N&yumy`+m*a=Eqga-3^5N*{%d{Yr}_ k1eHt2ropLr6~!3FG&g{;!_p#pVDd-6$RL#{@TUrV0`A$IVE_OC literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2417f74cb109b7343b033aca53923073e91a4fac GIT binary patch literal 6148 zcmeHKJ5Iwu5S<|rvOq#9Dfa+0X{b%K^oUe+C>RA$j8l+;&Ntu++yQX~F2FrF18;T) z;sryA5X?xsZ$01jlf3I8BA%?OG0}*K3JgJ(MURNO*R)~IVr0oNo}M-JvM0swRmt85 zRM8DJi+OkdThD7t-NZOsG&5+5)&9x+;r{8MYpuSqE-$)Sj}S(ibWYc(c!_bFSKT@O zXz$jJFMC&akEwQ+qi)ta_{t~WN05EEI0MdrGvEyTPX=&jixk_6K05=>fHUyUfSeBj zL$EY#71PmyDYXE=A=F8*mR>?)f?;XcD#8L`4Fzf_TZ_RO4t+4c(y&$3aAIpd*ebs@ zFPy3)e@O1crJ~QyfHROYFwn=5-2aF8WO|$YJj9=z0cYTkF~Gw(jT5|--L0QqPwv`) uaf%@#eyuDZSZ6;0c#v~sHyPC)WDUR4uvL^SqEF#K{}D)p_~Z=y00XZ|6-F`u literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/member/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..10fdb6ed334ba702e002bca360d0adbfda158e2c GIT binary patch literal 6148 zcmeHKJxc>Y5S@*Ygb0!%g^jX>mO|2toZ+;v%^wK)zz^gUJa*Aew=(UnH}M; z|HSLppwE!T;BZ1mP%FXvh0mn)Q52Wuw7vg4y1aEd&6qRG?x$FvC;yyO0Y5&0&%v@! zL!aTsLp~zQ?Pc}my7_3heVZrCsyNE$(_}tk^Qi!8Hd}ScqV%GGC?E<<72xwhqcH{! zQ;X*4KxeK1z%ty%@N8-jP_qLVI7}_V15-8?Xj7HDVknyqzjkqf!_=ZpCuLT~JZ@#> zZYavE4!<_xqymf5ivps6ufT$Rt#kd~Ex!NzN%AHNhywpg0aXq=VH;n`)z;jX<65iH rx@c@1ms&I_=v+BA4_t~@(2QYB^8+w&m|BDfCVvEs4AO}Lf2zPIs>7H- literal 0 HcmV?d00001 diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f882310f24f2fc278d072ca42782d2bc85034417 GIT binary patch literal 6148 zcmeHKJ5Iwu5S<|rvXp`pNKoz-aswwaCrC?yf)OCaI0Y1RJ_7W#l+bVo3XVWe%MlQ7 zb_U`lh7zGLBkjKReAiF%u7`+ta#4u&x#zDgLfX z_THnC&Z(XsxA(t&zqC|!QOxG`44Uk9=lS~P_Ho>{mOoe*C+)0P2%}9pqBB%H#kfqX zZtZ`yw`&g`Uf!PWV(lbHRWEn&olm-tAp3A}2AlzBz!~_T4B*Zd$p(r(I|I&uGw{iP zoDTs*FgI)zqR-BNGmtXS)5oFQ|9kjkI-C47#Gjl2XJE}3;C?YJCU_~kTUTCB x?%IHHfFUA&jVvHoCqDsrkaJ`=8r2?T4Zqy5QIssAkKsW75r~BN{!+*^={cvNCgw zD5n&k0gX!0;t&Nyfkjh*_ilsw*th3&iCsI}zv)S<)6cV^CA>bVip%mi?xlGT-@Uy?#u)?_2Co z2J{)w5F9S(3~J?gzX_SBaaEkpX?O4L;qlq&G-pnq-A}P0PyRV+75w-Fz6Q%a4MK(+ zZ{-M|+t%TX+qZdqR@G4BH5;*&(44|;0$~)Am>BC z5X=o*#dvgJiY)+e2z3;!rI(PHV3-@Wim*UfLxCE~)?%=RLm$j9H*6I(oY#KR`spMzpsO1iKW1 zXl?5c_zAw5U6S40MLSX1f!%jEGrRNdEw`Hs5vfwQzD!gkq5>LYFoQ0~IL<9&W5%-x zR5HgtHCm13N-b%3GTGkY74QoDHU;?IounEibU=HQd4I$6;dnbKmv>vqF8qb7t?RR; zr`~Edr~YkDr)lpKo0x*8DW+p^iK#k^zRq;{ z@%{*%SfLiU#dPR0o4*^5+nhe$;){uUqmwm<&1O`N%OhkSQ`Dp?)~gOK876bv*$kV@ z#$kWWhUT%^jLvfTh%OUYsVa4$OVd>)=z)tBwRv1lo~|F?iY89RV14p4a_R?C8!O{h zFTA39KW5i{K2a<0H&WY*4=U%ybLwLHKW#X(*$T57eeV_U3U~$j3h@3AqA^AWQ;o89 zpp#DkU;wumuH{SshU@@F22+jjz?2>e)I*i|#87%T{GrK<45k|Oa8gnk^O(xYe4!|* z4u2@=q#}*J_X>CgTm{DUZIRFawb9@I?jV2X74QoDD+N?gu9Qo7By+ZA9*)o25N!vI qjq_5CG6bDDj^%=nV*X!246%?efRVveBRnwwLqKHkomb#T75D_Vc+DLE literal 0 HcmV?d00001 From 7fb7715026d559a202c446a3bac2de2d7bc32f61 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 29 May 2025 22:32:59 +0900 Subject: [PATCH 65/67] =?UTF-8?q?=20Fix=20:=20=EA=B3=BC=ED=96=89=EC=82=AC?= =?UTF-8?q?=20=EC=99=B8=20=EB=8B=A4=EB=A5=B8=20=ED=96=89=EC=82=AC=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EC=B6=A9=EB=8F=8C=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/anotherEvent/model/entity/AnotherEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java index a42ac3a..7955f69 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java @@ -49,7 +49,7 @@ public class AnotherEvent { private String googleFormLink; @ElementCollection(fetch = FetchType.LAZY) - @CollectionTable(name = "event_card_news_images", joinColumns = @JoinColumn(name = "event_id")) + @CollectionTable(name = "anotehr_event_card_news_images", joinColumns = @JoinColumn(name = "event_id")) @Column(name = "image_url") private List cardNewsImageUrls = new ArrayList<>(); From 96882a53106cae3fafae0d765fefe6da6bd6caee Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Thu, 29 May 2025 23:05:04 +0900 Subject: [PATCH 66/67] =?UTF-8?q?Fix=20:=20anotherEvent=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EB=AA=85=20?= =?UTF-8?q?=EC=98=A4=ED=83=88=EC=9E=90=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?FK=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/anotherEvent/model/entity/AnotherEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java index 7955f69..a970c3b 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java @@ -49,7 +49,7 @@ public class AnotherEvent { private String googleFormLink; @ElementCollection(fetch = FetchType.LAZY) - @CollectionTable(name = "anotehr_event_card_news_images", joinColumns = @JoinColumn(name = "event_id")) + @CollectionTable(name = "another_event_card_news_images", joinColumns = @JoinColumn(name = "another_event_id")) @Column(name = "image_url") private List cardNewsImageUrls = new ArrayList<>(); From c27fafe3c64309cecf520f303249a596f5861eb5 Mon Sep 17 00:00:00 2001 From: sungmin306 Date: Tue, 5 Aug 2025 02:30:35 +0900 Subject: [PATCH 67/67] =?UTF-8?q?Merge=20:=20anotherEvent=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C=20=EB=B0=8F=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 ++- .../ComNCheck/domain/security/oauth/CustomOAuth2Member.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 7afd08a..f32fbcb 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,8 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - runtimeOnly 'mysql:mysql-connector-java:8.0.33' + // runtimeOnly 'mysql:mysql-connector-java:8.0.33' + runtimeOnly 'com.mysql:mysql-connector-j' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'com.google.firebase:firebase-admin:8.1.0' compileOnly 'org.projectlombok:lombok' diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java index 232fc4b..b7440ed 100644 --- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java +++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java @@ -9,7 +9,8 @@ import org.springframework.security.oauth2.core.user.OAuth2User; @RequiredArgsConstructor -public class CustomOAuth2Member implements OAuth2User { +public class +CustomOAuth2Member implements OAuth2User { private final MemberDTO memberDTO; public MemberDTO getMemberDTO() {