Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feature/#74 사용자 등록 기능 #95

Merged
Show file tree
Hide file tree
Changes from 71 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
1ae318e
feat: 로그인 기능 구현
tmdgh1592 Jul 18, 2023
3d49927
feat: 온보딩 이름 입력화면 와이어프레임 형식으로 구현
tmdgh1592 Jul 18, 2023
255b058
fix: OnBoardingViewModel의 name을 LiveData에서 MutableLiveData로 변경
tmdgh1592 Jul 19, 2023
35d8708
feat: DistinctListLiveData 구현
tmdgh1592 Jul 19, 2023
c6a5e92
feat: ListLiveData 구현
tmdgh1592 Jul 19, 2023
c0cabfa
feat: 교육이력 추가하는 기능 구현
tmdgh1592 Jul 19, 2023
439e459
feat: 파이어베이스 의존성 추가
tmdgh1592 Jul 19, 2023
d006ba8
refactor: Education 관련 클래스명을 ResumeTag로 변경
tmdgh1592 Jul 20, 2023
46e32a1
feat: 컨퍼런스 이력 추가하는 기능 구현
tmdgh1592 Jul 20, 2023
744ec05
feat: 컨퍼런스, 교육 이력 조회 기능 서버와 연동
tmdgh1592 Jul 20, 2023
cca6236
refactor: 공통 ViewModelFactory 구현
tmdgh1592 Jul 20, 2023
c481a4d
refactor: 커리어 Spinner id 변경
tmdgh1592 Jul 20, 2023
ec9959b
feat: 동아리 이력 추가하는 기능 구현
tmdgh1592 Jul 20, 2023
64a0714
feat: 관심 직무 추가하는 기능 구현
tmdgh1592 Jul 20, 2023
b6dafc3
refactor: 커리어 목록에서 특정 커리어를 찾는 로직을 CareersUiState 클래스 내부로 이동
tmdgh1592 Jul 20, 2023
5300669
feat: 커리어를 선택/해제할 때마다 커리어 아이디를 추가, 삭제하는 기능 구현
tmdgh1592 Jul 20, 2023
653a288
feat: 컨퍼런스 이력 선택 제거 및 동아리 선택 안 되는 버그 수정
tmdgh1592 Jul 21, 2023
8b6528e
feat: 교육 이력 선택을 Chip을 사용하도록 변경
tmdgh1592 Jul 22, 2023
6bf0f26
feat: 동아리 이력 선택을 Chip을 사용하도록 변경
tmdgh1592 Jul 22, 2023
668f6d9
feat: 관심 직무 이력 선택을 Chip을 사용하도록 변경
tmdgh1592 Jul 22, 2023
9e553a2
feat: 온보딩 관련 클래스에서 중복되는 코드 제거
tmdgh1592 Jul 22, 2023
2ef4e61
refactor : Activity -> ActivityType으로 변경
java-saeng Jul 17, 2023
3b392ab
feat : mock data 추가
java-saeng Jul 17, 2023
701365b
feat : 저장된 활동들 전체 조회 API 구현
java-saeng Jul 17, 2023
48a0985
docs : careers http 생성
java-saeng Jul 17, 2023
4795f19
feat : 로그인 기능 구현 전 가짜 ArgumentResolver 추가(추후 로그인 기능 이후 변경해야함)
java-saeng Jul 17, 2023
cbcac8f
feat : 초기 사용자의 이력들을 저장하는 API 구현
java-saeng Jul 17, 2023
e5953af
docs : 초기 사용자의 이력들을 저장하는 API http 테스트
java-saeng Jul 17, 2023
9552a03
refactor : MockMvcTestHelper 추가
java-saeng Jul 17, 2023
ef37ffb
refactor : 서비스 통합 테스트 추상화
java-saeng Jul 17, 2023
de30bbd
refactor : 항상 일정한 형식의 데이터를 반환하기 위해 정렬함
java-saeng Jul 18, 2023
700bd28
chore: RestDocs 관련 의존성 설정
hyeonjerry Jul 11, 2023
10cbefa
feat: RestDocs 문서화 위한 컨트롤러 및 테스트 구현
hyeonjerry Jul 11, 2023
b6ee58e
docs: RestDocs 문서 파일 작성 및 html 파일 생성
hyeonjerry Jul 11, 2023
39fd809
refactor: REST Docs uri path 수정
hyeonjerry Jul 17, 2023
264b9d8
test: 중복 request/response snippet 제거
hyeonjerry Jul 17, 2023
8e1bd46
hotfix : Rest docs 테스트 실패 수정
java-saeng Jul 18, 2023
f371e97
feat : Custom Exception 스켈레톤 코드 작성
java-saeng Jul 18, 2023
a30f126
chore: CICD를 위한 main.yml 스크립트 초안 작성
Jul 18, 2023
76f6c4e
chore: CICD를 위한 main.yml 스크립트 초안 수정
Jul 18, 2023
4bc1267
chore: CICD를 위한 main.yml 스크립트 초안 수정2
Jul 18, 2023
d00395e
chore: CICD를 위한 yml 스크립트를 테스트용과 배포용으로 분리
Jul 19, 2023
44d64b0
chore: 테스트용 스크립트 수정
Jul 19, 2023
c51345e
chore: 테스트용 스크립트 수정
Jul 19, 2023
14e912b
chore: 테스트용 스크립트 수정
Jul 19, 2023
ebb4622
chore: 테스트용 스크립트 수정
Jul 19, 2023
fe4b74c
chore: 테스트용 스크립트 수정
Jul 19, 2023
3dccbad
chore: 테스트용 스크립트 수정
Jul 19, 2023
d3928ff
chore: 배포용 스크립트 수정
Jul 19, 2023
ff99068
chore: 배포용 스크립트 수정
Jul 19, 2023
226ce9e
chore: 배포용 스크립트 수정
Jul 19, 2023
7a78248
chore: 배포용 스크립트 수정 및 테스트용 스크립트 삭제
Jul 19, 2023
7f4a349
feat: backend-main으로 보내는 PR이 있을 때 새로 빌드를 실행하는 스크립트 추가
hong-sile Jul 19, 2023
4a688d0
feat: 빌드 하기전 backend-main으로 체크아웃하는 기능 추가
hong-sile Jul 19, 2023
1db80da
feat: 깃허브 백엔드 자동 테스트 스크립트 작성
hong-sile Jul 19, 2023
c6c7ec4
fix: 인식 안되는 특수문자 제거
hong-sile Jul 19, 2023
75c7455
fix: github workflow jdk의 distribution 추가
hong-sile Jul 19, 2023
6562aa5
feat: 수동 DI 구현
tmdgh1592 Jul 25, 2023
4aa24c0
refactor: Career 네이밍을 Activity로 변경
tmdgh1592 Jul 25, 2023
a5276c9
refactor: UiState에서 특정카테고리 액티비티를 찾는 로직을 뷰모델로 이동
tmdgh1592 Jul 25, 2023
ed2ee3e
feat: 멤버 정보를 업데이트 하는 기능 구현
tmdgh1592 Jul 25, 2023
ea38f20
refactor: 닉네임 입력 화면에 피그마 디자인 적용
tmdgh1592 Jul 25, 2023
0bbddf9
feat: px, dp 변환 기능 구현
tmdgh1592 Jul 25, 2023
3e5fee1
refactor: 관심 분야 선택 화면에 피그마 디자인 적용
tmdgh1592 Jul 25, 2023
75ad06c
refactor: 교육 이력 선택 화면에 피그마 디자인 적용
tmdgh1592 Jul 25, 2023
d51dd02
refactor: 동아리 활동 선택 화면에 피그마 디자인 적용
tmdgh1592 Jul 25, 2023
5572ed1
refactor: 관심 카테고리 <-> 교육 이력 화면 순서 변경
tmdgh1592 Jul 25, 2023
62a8a22
refactor: 온보딩 화면을 스와이프 대신에 버튼을 클릭하여 넘어가도록 변경
tmdgh1592 Jul 25, 2023
7035d1a
refactor: di 패키지 이동
tmdgh1592 Jul 25, 2023
01bb9f0
feat: Interceptor에 Token 추가하는 기능 구현
tmdgh1592 Jul 25, 2023
a8d32e6
fix: 동아리 활동 선택 화면 버튼 텍스트를 완료로 변경
tmdgh1592 Jul 26, 2023
4c2f926
feat: android-main 브랜치 pull하고 충돌 해결
tmdgh1592 Jul 27, 2023
697be4c
refactor: handleApi 메서드 개선
tmdgh1592 Jul 27, 2023
c2057ee
refactor: 깃허브 코드를 파싱하는 함수를 분리
tmdgh1592 Jul 27, 2023
15487d6
refactor: 정적 팩토리 메서드에 적합하도록 변경 (토마스 리뷰 반영)
tmdgh1592 Jul 27, 2023
ca8c42d
refactor: SharedPreferenceContainer를 주입받도록 변경
tmdgh1592 Jul 27, 2023
32f983a
refactor: nameUiState 변수명을 name으로 변경
tmdgh1592 Jul 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/backend-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: Kerdy Backend Dev Server CI/CD

on:
workflow_dispatch:

jobs:
build:
runs-on: self-hosted
steps:
- name: deploy
run: ~/deploy.sh
44 changes: 44 additions & 0 deletions .github/workflows/backend-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Kerdy Backend Build Test

on:
pull_request:
types: [ opened, synchronize, reopened ]
branches:
- backend-main

jobs:
build:
name: Build with Gradle
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0.28
env:
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: 1234
MYSQL_DATABASE: kerdy
ports:
- 13306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: backend-main

- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: 11
distribution: 'temurin'

- name: cd backend directory
run: cd backend/emm-sale

- name: Give permission for Gradle
run: chmod +x gradlew

- name: Build with Gradle
run: gradlew clean build
Binary file added .gradle/8.0.2/checksums/checksums.lock
Binary file not shown.
Binary file added .gradle/8.0.2/checksums/md5-checksums.bin
Binary file not shown.
Binary file added .gradle/8.0.2/checksums/sha1-checksums.bin
Binary file not shown.
Binary file not shown.
Empty file.
Binary file not shown.
Binary file added .gradle/8.0.2/fileChanges/last-build.bin
Binary file not shown.
Binary file added .gradle/8.0.2/fileHashes/fileHashes.lock
Binary file not shown.
Empty file added .gradle/8.0.2/gc.properties
Empty file.
Binary file added .gradle/buildOutputCleanup/buildOutputCleanup.lock
Binary file not shown.
2 changes: 2 additions & 0 deletions .gradle/buildOutputCleanup/cache.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#Wed Jul 19 21:44:15 KST 2023
gradle.version=8.0.2
Binary file added .gradle/file-system.probe
Binary file not shown.
Empty file added .gradle/vcs-1/gc.properties
Empty file.
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/2023-emmsale.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 14 additions & 4 deletions android/2023-emmsale/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
plugins {
id("org.jetbrains.kotlin.android")
id("com.android.application") version "8.0.2"
id("com.google.gms.google-services")
kotlin("plugin.serialization") version "1.8.21"
id("kotlin-kapt")
}

android {
namespace = "com.emmsale"
compileSdk = 33

defaultConfig {
applicationId = "come.emmsale"
applicationId = "com.emmsale"
minSdk = 28
targetSdk = 33
versionCode = 1
Expand All @@ -27,11 +30,11 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "11"
jvmTarget = "17"
}
dataBinding {
enable = true
Expand All @@ -43,11 +46,18 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("androidx.fragment:fragment-ktx:1.6.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.okhttp3:okhttp:4.11.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")

implementation(platform("com.google.firebase:firebase-bom:32.2.0"))
implementation("com.google.firebase:firebase-analytics-ktx")
}

This file was deleted.

7 changes: 6 additions & 1 deletion android/2023-emmsale/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">

<application
android:name=".presentation.KerdyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand All @@ -11,9 +12,13 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Emmsale"
android:usesCleartextTraffic="true"
tools:targetApi="33">
<activity
android:name="com.emmsale.MainActivity"
android:name=".presentation.ui.onboarding.OnboardingActivity"
android:exported="true" />
<activity
android:name=".presentation.ui.login.LoginActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
12 changes: 0 additions & 12 deletions android/2023-emmsale/app/src/main/java/com/emmsale/MainActivity.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.emmsale.data.activity

import com.emmsale.data.activity.dto.ActivitiesApiModel
import com.emmsale.data.activity.dto.ActivityApiModel

data class Activities(
val category: String,
val activities: List<Activity>
) {
companion object {
fun from(activitiesApiModels: List<ActivitiesApiModel>): List<Activities> =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

데이터 모델이 ApiModel에 의존해서는 안된다고 생각합니다. apiModel.toExternal() 혹은 apiModel.toDomain()이런 식으로 바꾸는 게 좋을 것 같습니다. 만약 로컬 데이터 저장소에서 로그인 데이터를 불러온다면 Login.from(entity: LoginEntity) 이렇게 새로 만들어줘야 하기 때문입니다. 즉, 데이터 소스 모델에 의해 데이터 모델이 변경되면 안된다고 생각합니다.

정적 팩토리 메서드는 해당 클래스 혹은 그 하위 타입을 반환하는 것이 좋다고 생각합니다! 리스트처럼 다른 타입으로 변환하는 일은 다른 Activities 외부에서 하는 것이 좋지 않을까요? 이처럼 다른 타입으로 변환하는 일을 Activities에 포함한다면 Activities 클래스가 하는 일이 많아질 거라고 생각합니다.

Copy link
Member Author

@tmdgh1592 tmdgh1592 Jul 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정리하자면,
이후에 같은 데이터 모델에 대해 여러 타입으로 변환될 일이 생길 수 있기 때문에,
변환을 모두 데이터 모델에 맡기면 한 클래스가 하는 일이 많아질 수 있고, 기존 클래스의 변경을 최소화하자는 말씀으로 이해하고 리뷰 반영하겠습니다.

activitiesApiModels.map(::from)

private fun from(activitiesApiModel: ActivitiesApiModel): Activities = Activities(
category = activitiesApiModel.category,
activities = Activity.from(activitiesApiModel.activities)
)
}
}

data class Activity(
val id: Int,
val name: String,
) {
companion object {
fun from(activitiesApiModel: List<ActivityApiModel>): List<Activity> =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위의 ApiModel 및 정적 팩토리 메서드 리뷰와 마찬가지입니다.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

동일하게 반영 완료하였습니다 : )

activitiesApiModel.map(::from)

private fun from(activityApiModel: ActivityApiModel): Activity =
Activity(
id = activityApiModel.id,
name = activityApiModel.name
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.emmsale.data.activity

import com.emmsale.data.common.ApiResult

interface ActivityRepository {
suspend fun getActivities(): ApiResult<List<Activities>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.emmsale.data.activity

import com.emmsale.data.common.ApiError
import com.emmsale.data.common.ApiException
import com.emmsale.data.common.ApiResult
import com.emmsale.data.common.ApiSuccess
import com.emmsale.data.common.handleApi
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class ActivityRepositoryImpl(
private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
private val activityService: ActivityService,
) : ActivityRepository {

override suspend fun getActivities(): ApiResult<List<Activities>> = withContext(dispatcher) {
when (val activitiesApiResult = handleApi { activityService.getActivities() }) {
is ApiSuccess -> ApiSuccess(Activities.from(activitiesApiResult.data))
is ApiError -> ApiError(activitiesApiResult.code, activitiesApiResult.message)
is ApiException -> ApiException(activitiesApiResult.e)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.emmsale.data.activity

import com.emmsale.data.activity.dto.ActivitiesApiModel
import retrofit2.Response
import retrofit2.http.GET

interface ActivityService {
@GET("/careers")
suspend fun getActivities(): Response<List<ActivitiesApiModel>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.emmsale.data.activity.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ActivitiesApiModel(
@SerialName("activityName")
val category: String = "-",
@SerialName("activityResponses")
val activities: List<ActivityApiModel> = emptyList()
)

@Serializable
data class ActivityApiModel(
@SerialName("id")
val id: Int,
@SerialName("name")
val name: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.emmsale.data.common

import retrofit2.HttpException
import retrofit2.Response

sealed interface ApiResult<T : Any>
class ApiSuccess<T : Any>(val data: T) : ApiResult<T>
class ApiError<T : Any>(val code: Int, val message: String?) : ApiResult<T>
class ApiException<T : Any>(val e: Throwable) : ApiResult<T>

suspend fun <T : Any> handleApi(
execute: suspend () -> Response<T>,
): ApiResult<T> {
return try {
val response = execute()
val body = response.body()

when {
response.isSuccessful && body != null -> ApiSuccess(body)
else -> ApiError(code = response.code(), message = response.message())
}
} catch (e: HttpException) {
ApiError(code = e.code(), message = e.message())
} catch (e: Throwable) {
ApiException(e)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.emmsale.data.common

import com.emmsale.presentation.KerdyApplication
import okhttp3.Interceptor
import okhttp3.Response

class AuthInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val token = KerdyApplication.repositoryContainer.tokenRepository.getToken()
?: return chain.proceed(chain.request())

val newRequest = chain.request().newBuilder()
.addHeader(ACCESS_TOKEN_HEADER, token.accessToken)
.build()
return chain.proceed(newRequest)
}

companion object {
private const val ACCESS_TOKEN_HEADER = "accessToken"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.emmsale.data.common

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import java.util.concurrent.TimeUnit

class ServiceFactory {
private val jsonMediaType = "application/json".toMediaType()
private val json = Json {
coerceInputValues = true
encodeDefaults = true
isLenient = true
}
private val jsonConverterFactory = json.asConverterFactory(jsonMediaType)

private val okhttpClient = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor())
.connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.build()

private val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(jsonConverterFactory)
.client(okhttpClient)
.build()

fun <T> create(service: Class<T>): T = retrofit.create(service)

companion object {
private const val BASE_URL = "http://13.125.212.56/"
}
}
Loading
Loading