projects request and test
This commit is contained in:
parent
7e8fbd3063
commit
c0de6f6606
@ -13,15 +13,20 @@ object ApiFactory {
|
||||
|
||||
fun provideRepository(dataStoreRepository: DataStoreRepository): ApiRepository {
|
||||
val json = Json { ignoreUnknownKeys = true }
|
||||
val client = OkHttpClient.Builder()
|
||||
.addInterceptor(HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
})
|
||||
.addInterceptor(AuthInterceptor(dataStoreRepository))
|
||||
.build()
|
||||
|
||||
val retrofit = Retrofit.Builder()
|
||||
.baseUrl("https://api.matule.ru/api/")
|
||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||
.client(OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
}).build())
|
||||
.client(client)
|
||||
.build()
|
||||
|
||||
|
||||
return BaseApiRepository(retrofit.create<ApiService>(), dataStoreRepository)
|
||||
return BaseApiRepository(retrofit.create<ApiService>(), dataStoreRepository, Handle.Base())
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package com.example.api.core.data.core
|
||||
|
||||
import com.example.api.core.data.dto.AuthUserResponseDto
|
||||
import com.example.api.core.data.dto.RegisterUserDto
|
||||
import com.example.api.core.data.dto.SalesAndActionsDto
|
||||
import com.example.api.core.data.dto.ProjectsDto
|
||||
import com.example.api.core.data.dto.SignInUserDto
|
||||
import com.example.api.core.data.dto.UserResponseDto
|
||||
import retrofit2.http.Body
|
||||
@ -23,7 +23,7 @@ internal interface ApiService {
|
||||
suspend fun auth(@Body signInUserDto: SignInUserDto): AuthUserResponseDto
|
||||
|
||||
@GET("collections/project/records")
|
||||
suspend fun salesAndProjects(): SalesAndActionsDto
|
||||
suspend fun projects(): ProjectsDto
|
||||
|
||||
// @GET("collections/products/records")
|
||||
// suspend fun products():
|
||||
|
@ -0,0 +1,22 @@
|
||||
package com.example.api.core.data.core
|
||||
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
/**
|
||||
* Автор: Манякин Дмитрий (user5)
|
||||
* Дата создания: 27.05.2025
|
||||
* */
|
||||
|
||||
class AuthInterceptor(private val dataStoreRepository: DataStoreRepository) : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val token = runBlocking { dataStoreRepository.token().first() }
|
||||
val request = chain.request().newBuilder().apply {
|
||||
token?.let { addHeader("Authorization", "Bearer $token") }
|
||||
}
|
||||
|
||||
return chain.proceed(request.build())
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import com.example.api.core.domain.ApiRepository
|
||||
import com.example.api.core.domain.AuthUserResponse
|
||||
import com.example.api.core.domain.FetchResult
|
||||
import com.example.api.core.domain.RegisterUser
|
||||
import com.example.api.core.domain.Projects
|
||||
import retrofit2.HttpException
|
||||
import java.net.UnknownHostException
|
||||
|
||||
@ -12,24 +13,42 @@ import java.net.UnknownHostException
|
||||
* Дата создания: 27.05.2025
|
||||
* */
|
||||
|
||||
internal interface Handle {
|
||||
suspend fun <T> handle(action: suspend () -> T): FetchResult<T>
|
||||
|
||||
class Base : Handle {
|
||||
override suspend fun <T> handle(action: suspend () -> T): FetchResult<T> {
|
||||
return try {
|
||||
val result = action.invoke()
|
||||
|
||||
FetchResult.Success(result)
|
||||
} catch (e: UnknownHostException) {
|
||||
FetchResult.Error(null, "no internet connection")
|
||||
} catch (e: HttpException) {
|
||||
FetchResult.Error(null, e.message())
|
||||
} catch (e: Exception) {
|
||||
FetchResult.Error(null, e.message!!)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal class BaseApiRepository(
|
||||
private val service: ApiService,
|
||||
private val dataStoreRepository: DataStoreRepository
|
||||
private val dataStoreRepository: DataStoreRepository,
|
||||
private val handle: Handle,
|
||||
) : RemoteMapper(), ApiRepository {
|
||||
|
||||
override suspend fun auth(registerUser: RegisterUser): FetchResult<AuthUserResponse> {
|
||||
return try {
|
||||
service.register(registerUser.toRegisterUserDto())
|
||||
val response = service.auth(registerUser.toSignInUserDto())
|
||||
dataStoreRepository.saveToken(response.token)
|
||||
override suspend fun auth(registerUser: RegisterUser): FetchResult<AuthUserResponse> = handle.handle {
|
||||
service.register(registerUser.toRegisterUserDto())
|
||||
val response = service.auth(registerUser.toSignInUserDto())
|
||||
dataStoreRepository.saveToken(response.token)
|
||||
response.toUserResponse()
|
||||
}
|
||||
|
||||
FetchResult.Success(response.toUserResponse())
|
||||
} catch (e: UnknownHostException) {
|
||||
FetchResult.Error(null, "no internet connection")
|
||||
} catch (e: HttpException) {
|
||||
FetchResult.Error(null, e.message())
|
||||
} catch (e: Exception) {
|
||||
FetchResult.Error(null, e.message!!)
|
||||
}
|
||||
|
||||
override suspend fun projects(): FetchResult<Projects> = handle.handle {
|
||||
service.projects().toDomain()
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ interface DataStoreRepository {
|
||||
|
||||
suspend fun saveToken(token: String)
|
||||
|
||||
fun token(): Flow<String>
|
||||
fun token(): Flow<String?>
|
||||
|
||||
class Base(private val preferences: DataStore<Preferences>) : DataStoreRepository {
|
||||
override suspend fun saveToken(token: String) {
|
||||
@ -25,9 +25,9 @@ interface DataStoreRepository {
|
||||
}
|
||||
}
|
||||
|
||||
override fun token(): Flow<String> {
|
||||
override fun token(): Flow<String?> {
|
||||
return preferences.data.map { preferences ->
|
||||
preferences[TOKEN_KEY] ?: ""
|
||||
preferences[TOKEN_KEY]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,15 @@ package com.example.api.core.data.core
|
||||
|
||||
import com.example.api.core.data.dto.AuthUserResponseDto
|
||||
import com.example.api.core.data.dto.RegisterUserDto
|
||||
import com.example.api.core.data.dto.SaleItemDto
|
||||
import com.example.api.core.data.dto.ProjectsDto
|
||||
import com.example.api.core.data.dto.SignInUserDto
|
||||
import com.example.api.core.data.dto.SignInUserResponseDto
|
||||
import com.example.api.core.data.dto.UserResponseDto
|
||||
import com.example.api.core.domain.AuthUserResponse
|
||||
import com.example.api.core.domain.RegisterUser
|
||||
import com.example.api.core.domain.SaleItem
|
||||
import com.example.api.core.domain.Projects
|
||||
import com.example.api.core.domain.SignInUserResponse
|
||||
import com.example.api.core.domain.UserResponse
|
||||
|
||||
/**
|
||||
* Автор: Манякин Дмитрий (user5)
|
||||
@ -55,4 +57,32 @@ internal abstract class RemoteMapper {
|
||||
verified = verified
|
||||
)
|
||||
}
|
||||
|
||||
protected fun ProjectsDto.toDomain(): Projects {
|
||||
return Projects(
|
||||
page = page,
|
||||
perPage = perPage,
|
||||
totalPage = totalPages,
|
||||
totalItems = totalItems,
|
||||
items = items.map { it.toSaleItem() }
|
||||
)
|
||||
}
|
||||
|
||||
protected fun SaleItemDto.toSaleItem(): SaleItem {
|
||||
return SaleItem(
|
||||
id = id,
|
||||
collectionId = collectionId,
|
||||
collectionName = collectionName,
|
||||
created = created,
|
||||
updated = updated,
|
||||
title = title,
|
||||
dateStart = dateStart,
|
||||
dateEnd = dateEnd,
|
||||
gender = gender,
|
||||
descriptionSource = descriptionSource,
|
||||
category = category,
|
||||
image = image,
|
||||
userId = userId
|
||||
)
|
||||
}
|
||||
}
|
@ -3,10 +3,10 @@ package com.example.api.core.data.dto
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal data class SalesAndActionsDto(
|
||||
internal data class ProjectsDto(
|
||||
val page: Int,
|
||||
val perPage: Int,
|
||||
val totalPage: Int,
|
||||
val totalPages: Int,
|
||||
val totalItems: Int,
|
||||
val items: List<SaleItemDto>
|
||||
)
|
@ -8,4 +8,6 @@ package com.example.api.core.domain
|
||||
interface ApiRepository {
|
||||
|
||||
suspend fun auth(registerUser: RegisterUser): FetchResult<AuthUserResponse>
|
||||
|
||||
suspend fun projects(): FetchResult<Projects>
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package com.example.api.core.domain
|
||||
|
||||
internal data class SalesAndActions(
|
||||
data class Projects(
|
||||
val page: Int,
|
||||
val perPage: Int,
|
||||
val totalPage: Int,
|
@ -126,6 +126,49 @@ class ServiceTest {
|
||||
assertEquals("/collections/users/auth-with-password", request.path)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_project_list() = runBlocking {
|
||||
val response = """
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"category": "е",
|
||||
"collectionId": "pbc_3202395908",
|
||||
"collectionName": "project",
|
||||
"created": "2025-05-26 14:47:25.523Z",
|
||||
"dateEnd": "2025-05-24 12:00:00.000Z",
|
||||
"dateStart": "2025-05-15 12:00:00.000Z",
|
||||
"description_source": "е",
|
||||
"gender": "е",
|
||||
"id": "7m35pcmbjr86kh4",
|
||||
"image": "",
|
||||
"title": "е",
|
||||
"typeProject": "е",
|
||||
"updated": "2025-05-26 14:47:25.523Z",
|
||||
"user_id": ""
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"perPage": 30,
|
||||
"totalItems": 1,
|
||||
"totalPages": 1
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(response))
|
||||
|
||||
val responseResult = service.projects()
|
||||
|
||||
val request = mockWebServer.takeRequest()
|
||||
|
||||
assertEquals(1, responseResult.page)
|
||||
assertEquals(1, responseResult.totalItems)
|
||||
assertEquals(1, responseResult.items.size)
|
||||
|
||||
assertEquals("GET", request.method)
|
||||
assertEquals("/collections/project/records", request.path)
|
||||
}
|
||||
|
||||
@After
|
||||
fun teardown() {
|
||||
mockWebServer.shutdown()
|
||||
|
@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.example.api.core.domain.ApiRepository
|
||||
import com.example.api.core.domain.AuthUserResponse
|
||||
import com.example.api.core.domain.RegisterUser
|
||||
import com.example.api.core.domain.Projects
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@ -24,10 +25,15 @@ class MainViewModel @Inject constructor(
|
||||
private val apiRepository: ApiRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val _loadResultUiState =
|
||||
private val _authUiState =
|
||||
MutableStateFlow<FetchResultUiState<AuthUserResponse>>(FetchResultUiState.Initial())
|
||||
val loadResultUiState: StateFlow<FetchResultUiState<AuthUserResponse>>
|
||||
get() = _loadResultUiState.asStateFlow()
|
||||
val authUiState: StateFlow<FetchResultUiState<AuthUserResponse>>
|
||||
get() = _authUiState.asStateFlow()
|
||||
|
||||
private val _ProjectsUiState =
|
||||
MutableStateFlow<FetchResultUiState<Projects>>(FetchResultUiState.Initial())
|
||||
val projectsUiState: StateFlow<FetchResultUiState<Projects>>
|
||||
get() = _ProjectsUiState.asStateFlow()
|
||||
|
||||
fun auth(email: String, password: String) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
@ -40,7 +46,17 @@ class MainViewModel @Inject constructor(
|
||||
)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
_loadResultUiState.value = result.map(FetchResultMapper())
|
||||
_authUiState.value = result.map(FetchResultMapper())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun salesAndProjects() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val result = apiRepository.projects()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
_ProjectsUiState.value = result.map(FetchResultMapper())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,12 @@ fun TestScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: MainViewModel = hiltViewModel()
|
||||
) {
|
||||
val state by viewModel.loadResultUiState.collectAsState()
|
||||
val state by viewModel.authUiState.collectAsState()
|
||||
val state2 by viewModel.projectsUiState.collectAsState()
|
||||
|
||||
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Column {
|
||||
Button(onClick = { viewModel.auth("someemael@te3st1.com", "12345678") }) {
|
||||
Button(onClick = { viewModel.auth("someemael@te3s11t1.com", "12345678") }) {
|
||||
Text("register")
|
||||
}
|
||||
|
||||
@ -36,6 +37,16 @@ fun TestScreen(
|
||||
onError = { _, message -> Text(text = message) },
|
||||
onLoading = { CircularProgressIndicator() }
|
||||
)
|
||||
|
||||
Button(onClick = { viewModel.salesAndProjects() }) {
|
||||
Text("sales and projects")
|
||||
}
|
||||
|
||||
state2.Show(
|
||||
onSuccess = { Text(text = it.items.size.toString()) },
|
||||
onError = { _, message -> Text(text = message) },
|
||||
onLoading = { CircularProgressIndicator() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user