Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: add api for login&join #292

Merged
merged 5 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/mobile/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("com.google.android.gms:play-services-basement:18.3.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
Expand Down
1 change: 1 addition & 0 deletions src/mobile/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.smilegate.Easel.data

import android.content.Context
import android.content.SharedPreferences

object TokenManager {
private const val PREF_NAME = "TokenPrefs"
private const val KEY_ACCESS_TOKEN = "accessToken"
private const val KEY_REFRESH_TOKEN = "refreshToken"

private var sharedPreferences: SharedPreferences? = null

// SharedPreferences 인스턴스 가져오기
private fun getSharedPreferences(context: Context): SharedPreferences {
if (sharedPreferences == null) {
sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
}
return sharedPreferences!!
}

// AccessToken 저장
fun saveAccessToken(context: Context, accessToken: String) {
val editor = getSharedPreferences(context).edit()
editor.putString(KEY_ACCESS_TOKEN, accessToken)
editor.apply()
}

// RefreshToken 저장
fun saveRefreshToken(context: Context, refreshToken: String) {
val editor = getSharedPreferences(context).edit()
editor.putString(KEY_REFRESH_TOKEN, refreshToken)
editor.apply()
}

// AccessToken 가져오기
fun getAccessToken(context: Context): String? {
return getSharedPreferences(context).getString(KEY_ACCESS_TOKEN, null)
}

// RefreshToken 가져오기
fun getRefreshToken(context: Context): String? {
return getSharedPreferences(context).getString(KEY_REFRESH_TOKEN, null)
}

// 토큰 삭제
fun clearTokens(context: Context) {
val editor = getSharedPreferences(context).edit()
editor.remove(KEY_ACCESS_TOKEN)
editor.remove(KEY_REFRESH_TOKEN)
editor.apply()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.smilegate.Easel.domain.api

import com.smilegate.Easel.domain.model.auth.EmailAuth
import com.smilegate.Easel.domain.model.auth.EmailRequest
import com.smilegate.Easel.domain.model.auth.EmailResponse
import com.smilegate.Easel.domain.model.join.JoinRequest
import com.smilegate.Easel.domain.model.join.TemporaryJoinRequest
import com.smilegate.Easel.domain.model.join.VerifyUsernameRequest
import com.smilegate.Easel.domain.model.join.VerifyUsernameResponse
import com.smilegate.Easel.domain.model.login.LoginRequest
import com.smilegate.Easel.domain.model.login.LoginResponse
import com.smilegate.Easel.domain.model.user.UserProfileResponse
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST

interface ApiService {
@POST("api/auth")
suspend fun sendCode(@Body request: EmailAuth): Response<ResponseBody>

@POST("api/users/verify-email")
suspend fun verifyEmail(@Body request: EmailRequest): Response<EmailResponse>

@POST("api/users/temporary-join")
suspend fun temporaryJoin(@Body request: TemporaryJoinRequest): Response<Unit>

@POST("api/users/verify-username")
suspend fun verifyUsername(@Body request: VerifyUsernameRequest): Response<VerifyUsernameResponse>

@POST("api/users/join")
suspend fun joinUser(@Body joinRequest: JoinRequest): Response<Unit>

@POST("api/auth/mobile")
suspend fun login(@Body loginRequest: LoginRequest): Response<LoginResponse>

@GET("api/users/me")
suspend fun getUserProfile(@Header("Authorization") token: String): Response<UserProfileResponse>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.smilegate.Easel.domain.model.auth

data class EmailAuth(
val email: String,
val payload: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.smilegate.Easel.domain.model.auth

data class EmailRequest(
val email: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.smilegate.Easel.domain.model.auth

data class EmailResponse(
val isDuplicated: Boolean
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.smilegate.Easel.domain.model.join

data class JoinRequest(
val email: String,
val password: String,
val username: String,
val nickname: String,
val introduce: String? = null,
val profileImagePath: String? = null,
val websitePath: String? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.smilegate.Easel.domain.model.join

data class TemporaryJoinRequest(
val email: String,
val nickname: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.smilegate.Easel.domain.model.join

data class VerifyUsernameRequest(
val username: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.smilegate.Easel.domain.model.join

data class VerifyUsernameResponse(
val isDuplicated: Boolean,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.smilegate.Easel.domain.model.login

data class LoginRequest(
val email: String,
val password: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.smilegate.Easel.domain.model.login

data class LoginResponse(
val accessToken: String,
val refreshToken: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.smilegate.Easel.domain.model.user

data class UserProfileResponse(
val backgroundImagePath: String,
val profileImagePath: String,
val nickname: String,
val username: String,
val introduce: String,
val websitePath: String,
val joinedAt: String,
val followingCount: Long,
val followerCount: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.smilegate.Easel.domain.repository

import android.util.Log
import com.smilegate.Easel.domain.api.ApiService
import com.smilegate.Easel.domain.model.join.JoinRequest

class JoinRepository(private val apiService: ApiService) {

suspend fun joinUser(joinRequest: JoinRequest) {
try {
val response = apiService.joinUser(joinRequest)

if (response.isSuccessful) {
// 성공적으로 응답을 받았을 때의 처리
// 여기에서는 특별히 할 일이 없다면 그냥 지나가도 됩니다.
} else {
// 서버로부터 오류 응답을 받았을 때의 처리
// 예를 들어, 오류 메시지를 출력하거나 특정 동작을 수행할 수 있습니다.
val errorBody = response.errorBody()?.string()
Log.e("UserRepository", "Error: $errorBody")
Log.e("UserRepository","Failed to join user. Response code: ${response.code()}")
}
} catch (e: Exception) {
// 네트워크 오류 등 예외 발생 시의 처리
Log.e("UserRepository", "Error: ${e.message}", e)
Log.e("UserRepository","Failed to join user. Error: ${e.message}")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.smilegate.Easel.domain.repository

import android.util.Log
import androidx.lifecycle.MutableLiveData
import com.smilegate.Easel.domain.api.ApiService
import com.smilegate.Easel.domain.model.auth.EmailAuth
import java.io.IOException

class SendCodeRepository(private val apiService: ApiService) {
private val _codeLiveData = MutableLiveData<String?>()
private val codeLiveData: MutableLiveData<String?> = _codeLiveData

suspend fun sendCode(email: String, payload: String) {
val request = EmailAuth(email, payload)
try {
val response = apiService.sendCode(request)
if (response.isSuccessful) {
// 성공적인 응답 처리
val responseBody = response.body()?.string()
if (responseBody != null) {
codeLiveData.postValue(responseBody)
} else {
// 서버가 빈 응답을 반환한 경우 처리
}
} else {
// 실패한 응답 처리
val errorMessage = response.errorBody()?.string()
if (!errorMessage.isNullOrEmpty()) {
Log.e("SendCodeRepository", "Error: $errorMessage")
} else {
Log.e("SendCodeRepository", "Failed to send code. Response code: ${response.code()}")
}
}
} catch (e: IOException) {
Log.e("SendCodeRepository", "Network error: ${e.message}")
} catch (e: Exception) {
Log.e("SendCodeRepository", "Unexpected error: ${e.message}")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.smilegate.Easel.domain.repository

import com.smilegate.Easel.domain.api.ApiService
import com.smilegate.Easel.domain.model.auth.EmailRequest

class UserRepository(private val apiService: ApiService) {
suspend fun verifyEmail(email: String): Boolean {
val request = EmailRequest(email)
val response = apiService.verifyEmail(request)
return response.isSuccessful && response.body()?.isDuplicated == false
}
}
Loading
Loading