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: 도서관 남은 좌석 API 구현 #387

Merged
merged 18 commits into from
Nov 28, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.ku_stacks.ku_ring.domain

data class LibraryRoom(
val name: String,
val totalSeats: Int,
val occupiedSeats: Int,
val availableSeats: Int,
)
1 change: 1 addition & 0 deletions data/library/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
26 changes: 26 additions & 0 deletions data/library/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import com.ku_stacks.ku_ring.buildlogic.dsl.setNameSpace

plugins {
kuring("feature")
kuringPrimitive("retrofit")
kuringPrimitive("test")
}
l2hyunwoo marked this conversation as resolved.
Show resolved Hide resolved

android {
setNameSpace("library")
l2hyunwoo marked this conversation as resolved.
Show resolved Hide resolved
compileSdk = 34

testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}

dependencies {
implementation(projects.core.util)
implementation(projects.data.domain)
implementation(projects.data.remote)

testImplementation(libs.kotlinx.coroutines.test)
}
Empty file added data/library/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions data/library/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
4 changes: 4 additions & 0 deletions data/library/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.ku_stacks.ku_ring.library.di

import com.ku_stacks.ku_ring.library.repository.LibraryRepository
import com.ku_stacks.ku_ring.library.repository.LibraryRepositoryImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
@Module
abstract class RepositoryModule {
@Binds
@Singleton
abstract fun provideLibraryRepository(repositoryImpl: LibraryRepositoryImpl): LibraryRepository

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.ku_stacks.ku_ring.library.mapper

import com.ku_stacks.ku_ring.domain.LibraryRoom
import com.ku_stacks.ku_ring.remote.library.response.LibrarySeatResponse

fun LibrarySeatResponse.toLibraryAreaList(): List<LibraryRoom> {
return data.libraryRooms.map {
LibraryRoom(
name = it.roomName,
totalSeats = it.seats.total,
availableSeats = it.seats.available,
occupiedSeats = it.seats.occupied
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ku_stacks.ku_ring.library.repository

import com.ku_stacks.ku_ring.domain.LibraryRoom

interface LibraryRepository {
suspend fun getRemainingSeats(): Result<List<LibraryRoom>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.library.repository

import com.ku_stacks.ku_ring.domain.LibraryRoom
import com.ku_stacks.ku_ring.library.mapper.toLibraryAreaList
import com.ku_stacks.ku_ring.remote.library.LibraryClient
import javax.inject.Inject

class LibraryRepositoryImpl @Inject constructor(
private val libraryClient: LibraryClient
) : LibraryRepository {
override suspend fun getRemainingSeats(): Result<List<LibraryRoom>> = runCatching {
libraryClient.fetchRoomSeatStatus().toLibraryAreaList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.ku_stacks.ku_ring.library

import com.ku_stacks.ku_ring.library.repository.LibraryRepository
import com.ku_stacks.ku_ring.library.repository.LibraryRepositoryImpl
import com.ku_stacks.ku_ring.remote.library.LibraryClient
import junit.framework.TestCase.assertEquals
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito
import org.mockito.kotlin.times

class LibraryRepositoryTest {
private lateinit var libraryRepository: LibraryRepository
private val client: LibraryClient = Mockito.mock(LibraryClient::class.java)

@Before
fun setup() {
libraryRepository = LibraryRepositoryImpl(client)
}

@Test
fun `get Library Seat Status From Remote Test`() = runTest {
val mockLibraryStatus = LibraryTestUtil.mockLibrarySeatResponse()

Mockito.`when`(client.fetchRoomSeatStatus()).thenReturn(mockLibraryStatus)
l2hyunwoo marked this conversation as resolved.
Show resolved Hide resolved

libraryRepository.getRemainingSeats().onSuccess { mockResult ->
val expectedResult = LibraryTestUtil.mockLibraryRoomList()

Mockito.verify(
client,
times(1)
).fetchRoomSeatStatus()

assertEquals(mockResult, expectedResult)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.ku_stacks.ku_ring.library

import com.ku_stacks.ku_ring.domain.LibraryRoom
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomBranchResponse
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomListResponse
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomResponse
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomSeatResponse
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomTypeResponse
import com.ku_stacks.ku_ring.remote.library.response.LibrarySeatResponse

object LibraryTestUtil {
fun mockLibrarySeatResponse() = LibrarySeatResponse(
success = true,
code = "success.retrieved",
message = "조회되었습니다.",
data = LibraryRoomListResponse(
resultCount = 1,
libraryRooms = listOf(
LibraryRoomResponse(
id = 102,
roomName = "제 1 열람실 (A구역)",
roomType = LibraryRoomTypeResponse(
id = 1,
roomName = "열람실",
sortOrder = 1
),
awaitable = true,
isChargeable = true,
branch = LibraryRoomBranchResponse(
id = 1,
roomBranchName = "상허기념도서관",
alias = "상허",
libraryCode = "211004",
sortOrder = 1
),
unableMessage = null,
seats = LibraryRoomSeatResponse(
total = 219,
occupied = 82,
waiting = 0,
available = 137
)
)
)
)
)


fun mockLibraryRoomList() = listOf(
LibraryRoom(
name = "제 1 열람실 (A구역)",
totalSeats = 219,
occupiedSeats = 82,
availableSeats = 137
)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.remote.library

import com.ku_stacks.ku_ring.remote.library.request.LibrarySeatRequest
import com.ku_stacks.ku_ring.remote.library.response.LibrarySeatResponse
import javax.inject.Inject

class LibraryClient @Inject constructor(private val libraryService: LibraryService) {

suspend fun fetchRoomSeatStatus(): LibrarySeatResponse = libraryService.fetchLibrarySeatStatus(
methodCode = LibrarySeatRequest.METHOD_CODE,
roomTypeId = LibrarySeatRequest.ROOM_TYPE_ID,
branchTypeId = LibrarySeatRequest.BRANCH_TYPE_ID,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.remote.library

import com.ku_stacks.ku_ring.remote.library.response.LibrarySeatResponse
import retrofit2.http.GET
import retrofit2.http.Query

interface LibraryService {
@GET("1/seat-rooms")
suspend fun fetchLibrarySeatStatus(
@Query("smufMethodCode") methodCode: String,
@Query("roomTypeId") roomTypeId: Int,
@Query("branchTypeId") branchTypeId: Int,
): LibrarySeatResponse
mwy3055 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.ku_stacks.ku_ring.remote.library.di

import com.ku_stacks.ku_ring.remote.library.LibraryClient
import com.ku_stacks.ku_ring.remote.library.LibraryService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import javax.inject.Named
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object LibraryModule {
@Provides
@Singleton
fun provideLibraryService(@Named("Library") retrofit: Retrofit): LibraryService
= retrofit.create(LibraryService::class.java)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
= retrofit.create(LibraryService::class.java)
= retrofit.create()

이렇게 적어도 됩니다ㅋㅋㅋㅋ


@Provides
@Singleton
fun provideLibraryClient(libraryService: LibraryService): LibraryClient
= LibraryClient(libraryService)
Comment on lines +21 to +24
Copy link
Collaborator

Choose a reason for hiding this comment

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

이건 굳이 작성 안해주셔도 될거에요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

아 Client가 추상체와 구현체로 나뉘지 않아서 필요가 없겠네요


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ku_stacks.ku_ring.remote.library.request

object LibrarySeatRequest {
const val METHOD_CODE: String = "PC"
const val ROOM_TYPE_ID = 4
const val BRANCH_TYPE_ID: Int = 1
}
mwy3055 marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +3 to +7
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 오브젝트는 따로 작성하신 이유가 있나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

요청에 필요한 상수들이 한 군데에서 관리되고, 무슨 역할인지 명확히 알 수 있으면 좋을 것 같아서 object로 작성했습니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomBranchResponse (
@SerializedName("id")
val id: Int,
@SerializedName("name")
val roomBranchName: String,
@SerializedName("alias")
val alias: String,
@SerializedName("libraryCode")
val libraryCode: String,
@SerializedName("sortOrder")
val sortOrder: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomListResponse(
@SerializedName(value = "totalCount")
val resultCount: Int,
@SerializedName(value = "list")
val libraryRooms: List<LibraryRoomResponse>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomResponse(
@SerializedName("id")
val id: Int,
@SerializedName("name")
val roomName: String,
@SerializedName("roomType")
val roomType: LibraryRoomTypeResponse,
@SerializedName("awaitable")
val awaitable: Boolean,
@SerializedName("isChargeable")
val isChargeable: Boolean,
@SerializedName("branch")
val branch: LibraryRoomBranchResponse,
@SerializedName("unableMessage")
val unableMessage: String?,
@SerializedName("seats")
val seats: LibraryRoomSeatResponse,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomSeatResponse(
@SerializedName("total")
val total: Int,
@SerializedName("occupied")
val occupied: Int,
@SerializedName("waiting")
val waiting: Int,
@SerializedName("available")
val available: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomTypeResponse(
@SerializedName("id")
val id: Int,
@SerializedName("name")
val roomName: String,
@SerializedName("sortOrder")
val sortOrder: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibrarySeatResponse(
@SerializedName("success")
val success: Boolean,
@SerializedName("code")
val code: String,
@SerializedName("message")
val message: String,
@SerializedName("data")
val data: LibraryRoomListResponse,
)
Loading