Login to dashboard worked
This commit is contained in:
@@ -1,4 +1,20 @@
|
||||
// [PACKAGE] com.homebox.lens.domain.model
|
||||
// [FILE] TokenResponse.kt
|
||||
// [SEMANTICS] data_transfer_object, authentication, model
|
||||
|
||||
package com.homebox.lens.domain.model
|
||||
|
||||
class TokenResponse {
|
||||
}
|
||||
/**
|
||||
* [ENTITY: DataClass('TokenResponse')]
|
||||
* [CONTRACT]
|
||||
* Модель данных, представляющая ответ от сервера с токеном аутентификации.
|
||||
* @property token Строка, содержащая JWT или другой токен доступа.
|
||||
* @invariant `token` не должен быть пустым.
|
||||
*/
|
||||
data class TokenResponse(val token: String) {
|
||||
init {
|
||||
// [INVARIANT_CHECK]
|
||||
require(token.isNotBlank()) { "[INVARIANT_FAILED] Token cannot be blank." }
|
||||
}
|
||||
}
|
||||
// [END_FILE_TokenResponse.kt]
|
||||
@@ -1,27 +1,42 @@
|
||||
// [PACKAGE] com.homebox.lens.domain.repository
|
||||
// [FILE] AuthRepository.kt
|
||||
// [SEMANTICS] authentication, data_access, repository
|
||||
|
||||
package com.homebox.lens.domain.repository
|
||||
|
||||
// [IMPORTS]
|
||||
import com.homebox.lens.domain.model.Credentials
|
||||
import com.homebox.lens.domain.model.TokenResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Repository for managing authentication tokens.
|
||||
* Репозиторий для управления аутентификацией.
|
||||
* [COHERENCE_NOTE] Добавлен метод `login` для инкапсуляции логики входа.
|
||||
*/
|
||||
interface AuthRepository {
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Saves the authentication token.
|
||||
* @param token The token to save.
|
||||
* Выполняет вход в систему, используя предоставленные учетные данные.
|
||||
* @param credentials Учетные данные пользователя (URL сервера, логин, пароль).
|
||||
* @return [Result] с [TokenResponse] в случае успеха, или с [Exception] в случае ошибки.
|
||||
* @throws IllegalArgumentException если `credentials` невалидны (предусловие).
|
||||
*/
|
||||
suspend fun login(credentials: Credentials): Result<TokenResponse>
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Сохраняет токен аутентификации.
|
||||
* @param token Токен для сохранения.
|
||||
* @throws IllegalArgumentException если `token` пустой (предусловие).
|
||||
*/
|
||||
suspend fun saveToken(token: String)
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Retrieves the authentication token.
|
||||
* @return A Flow emitting the token, or null if not found.
|
||||
* Получает токен аутентификации.
|
||||
* @return [Flow], который эммитит токен в виде строки, или `null`, если токен отсутствует.
|
||||
*/
|
||||
fun getToken(): Flow<String?>
|
||||
}
|
||||
// [END_FILE_AuthRepository.kt]
|
||||
// [END_FILE_AuthRepository.kt]
|
||||
@@ -8,13 +8,14 @@ import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Repository for managing user credentials.
|
||||
* Repository for managing user credentials and session tokens.
|
||||
*/
|
||||
interface CredentialsRepository {
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Saves the user credentials securely.
|
||||
* Saves the user's base credentials (URL, username, password) securely.
|
||||
* @param credentials The credentials to save.
|
||||
* @sideeffect Overwrites any existing saved credentials.
|
||||
*/
|
||||
suspend fun saveCredentials(credentials: Credentials)
|
||||
|
||||
@@ -24,5 +25,20 @@ interface CredentialsRepository {
|
||||
* @return A Flow emitting the saved [Credentials], or null if none are saved.
|
||||
*/
|
||||
fun getCredentials(): Flow<Credentials?>
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* [ACTION] Saves the authorization token received after a successful login.
|
||||
* @param token The authorization token (including "Bearer " prefix if provided by the server).
|
||||
* @sideeffect Overwrites any existing saved token.
|
||||
*/
|
||||
suspend fun saveToken(token: String)
|
||||
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* [ACTION] Retrieves the saved authorization token.
|
||||
* @return The saved token as a String, or null if no token is saved.
|
||||
*/
|
||||
suspend fun getToken(): String?
|
||||
}
|
||||
// [END_FILE_CredentialsRepository.kt]
|
||||
// [END_FILE_CredentialsRepository.kt]
|
||||
@@ -1,7 +1,9 @@
|
||||
// [PACKAGE] com.homebox.lens.domain.repository
|
||||
// [FILE] ItemRepository.kt
|
||||
// [SEMANTICS] data_access, abstraction, repository
|
||||
|
||||
package com.homebox.lens.domain.repository
|
||||
|
||||
// [IMPORTS]
|
||||
import com.homebox.lens.domain.model.*
|
||||
|
||||
@@ -10,9 +12,10 @@ import com.homebox.lens.domain.model.*
|
||||
* [CONTRACT]
|
||||
* Абстракция репозитория для работы с "Вещами".
|
||||
* Определяет контракт, которому должен следовать слой данных.
|
||||
* [COHERENCE_NOTE] Метод `login` был удален, так как он относится к аутентификации и перенесен в `AuthRepository`.
|
||||
*/
|
||||
interface ItemRepository {
|
||||
suspend fun login(credentials: Credentials): Result<Unit>
|
||||
// [DELETED] suspend fun login(credentials: Credentials): Result<Unit>
|
||||
suspend fun createItem(newItemData: ItemCreate): ItemSummary
|
||||
suspend fun getItemDetails(itemId: String): ItemOut
|
||||
suspend fun updateItem(itemId: String, item: ItemUpdate): ItemOut
|
||||
@@ -23,4 +26,4 @@ interface ItemRepository {
|
||||
suspend fun getAllLabels(): List<LabelOut>
|
||||
suspend fun searchItems(query: String): PaginationResult<ItemSummary>
|
||||
}
|
||||
// [END_FILE_ItemRepository.kt]
|
||||
// [END_FILE_ItemRepository.kt]
|
||||
@@ -1,25 +1,21 @@
|
||||
// [PACKAGE] com.homebox.lens.domain.usecase
|
||||
// [FILE] domain/src/main/java/com/homebox/lens/domain/usecase/GetAllLabelsUseCase.kt
|
||||
// [SEMANTICS] domain, usecase, label, list
|
||||
// [FILE] GetAllLabelsUseCase.kt
|
||||
|
||||
// [IMPORTS]
|
||||
package com.homebox.lens.domain.usecase
|
||||
|
||||
import com.homebox.lens.domain.model.LabelOut
|
||||
import com.homebox.lens.domain.repository.ItemRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
// [CORE-LOGIC]
|
||||
class GetAllLabelsUseCase @Inject constructor(
|
||||
private val itemRepository: ItemRepository
|
||||
) {
|
||||
suspend operator fun invoke(): List<LabelOut>? {
|
||||
return try {
|
||||
itemRepository.getAllLabels()
|
||||
} catch (e: Exception) {
|
||||
// [ERROR_HANDLER] Просто возвращаем null.
|
||||
null
|
||||
}
|
||||
class GetAllLabelsUseCase @Inject constructor(private val repository: ItemRepository) {
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Получает список всех меток.
|
||||
* @return Список [LabelOut].
|
||||
* @throws Exception в случае ошибки сети или API.
|
||||
*/
|
||||
suspend operator fun invoke(): List<LabelOut> {
|
||||
// [FIX] Упрощено.
|
||||
return repository.getAllLabels()
|
||||
}
|
||||
}
|
||||
// [END_FILE_GetAllLabelsUseCase.kt]
|
||||
}
|
||||
@@ -1,25 +1,21 @@
|
||||
// [PACKAGE] com.homebox.lens.domain.usecase
|
||||
// [FILE] domain/src/main/java/com/homebox/lens/domain/usecase/GetAllLocationsUseCase.kt
|
||||
// [SEMANTICS] domain, usecase, location, list
|
||||
// [FILE] GetAllLocationsUseCase.kt
|
||||
|
||||
// [IMPORTS]
|
||||
package com.homebox.lens.domain.usecase
|
||||
|
||||
import com.homebox.lens.domain.model.LocationOutCount
|
||||
import com.homebox.lens.domain.repository.ItemRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
// [CORE-LOGIC]
|
||||
class GetAllLocationsUseCase @Inject constructor(
|
||||
private val itemRepository: ItemRepository
|
||||
) {
|
||||
suspend operator fun invoke(): List<LocationOutCount>? {
|
||||
return try {
|
||||
itemRepository.getAllLocations()
|
||||
} catch (e: Exception) {
|
||||
// [ERROR_HANDLER] Просто возвращаем null.
|
||||
null
|
||||
}
|
||||
class GetAllLocationsUseCase @Inject constructor(private val repository: ItemRepository) {
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Получает список всех локаций.
|
||||
* @return Список [LocationOutCount].
|
||||
* @throws Exception в случае ошибки сети или API.
|
||||
*/
|
||||
suspend operator fun invoke(): List<LocationOutCount> {
|
||||
// [FIX] Упрощено.
|
||||
return repository.getAllLocations()
|
||||
}
|
||||
}
|
||||
// [END_FILE_GetAllLocationsUseCase.kt]
|
||||
}
|
||||
@@ -1,25 +1,22 @@
|
||||
// [PACKAGE] com.homebox.lens.domain.usecase
|
||||
// [FILE] domain/src/main/java/com/homebox/lens/domain/usecase/GetStatisticsUseCase.kt
|
||||
// [SEMANTICS] domain, usecase, statistics
|
||||
// [FILE] GetStatisticsUseCase.kt
|
||||
|
||||
// [IMPORTS]
|
||||
package com.homebox.lens.domain.usecase
|
||||
|
||||
import com.homebox.lens.domain.model.GroupStatistics
|
||||
import com.homebox.lens.domain.repository.ItemRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
// [CORE-LOGIC]
|
||||
class GetStatisticsUseCase @Inject constructor(
|
||||
private val itemRepository: ItemRepository
|
||||
) {
|
||||
suspend operator fun invoke(): GroupStatistics? {
|
||||
return try {
|
||||
itemRepository.getStatistics()
|
||||
} catch (e: Exception) {
|
||||
// [ERROR_HANDLER] Просто возвращаем null, вызывающий слой обработает это.
|
||||
null
|
||||
}
|
||||
class GetStatisticsUseCase @Inject constructor(private val repository: ItemRepository) {
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Получает статистику инвентаря.
|
||||
* @return [GroupStatistics] объект.
|
||||
* @throws Exception в случае ошибки сети или API.
|
||||
*/
|
||||
suspend operator fun invoke(): GroupStatistics {
|
||||
// [FIX] Упрощено. Просто вызываем репозиторий и возвращаем его результат.
|
||||
// Обработка ошибок делегирована вызывающей стороне (ViewModel).
|
||||
return repository.getStatistics()
|
||||
}
|
||||
}
|
||||
// [END_FILE_GetStatisticsUseCase.kt]
|
||||
}
|
||||
@@ -1,29 +1,52 @@
|
||||
// [PACKAGE] com.homebox.lens.domain.usecase
|
||||
// [FILE] LoginUseCase.kt
|
||||
|
||||
// [PURPOSE] Инкапсулирует бизнес-логику процесса входа пользователя в систему.
|
||||
package com.homebox.lens.domain.usecase
|
||||
|
||||
// [IMPORTS]
|
||||
import com.homebox.lens.domain.model.Credentials
|
||||
import com.homebox.lens.domain.repository.ItemRepository
|
||||
import com.homebox.lens.domain.model.TokenResponse
|
||||
import com.homebox.lens.domain.repository.AuthRepository
|
||||
import javax.inject.Inject
|
||||
import com.homebox.lens.domain.model.Result
|
||||
|
||||
/**
|
||||
* [ENTITY: Class('LoginUseCase')]
|
||||
* [CONTRACT]
|
||||
* Use case for user login.
|
||||
* @param itemRepository The repository to handle item and auth operations.
|
||||
* Use case для выполнения входа пользователя.
|
||||
* @param authRepository Репозиторий для выполнения сетевого запроса на вход и сохранения токена.
|
||||
* [COHERENCE_NOTE] Удалена зависимость от CredentialsRepository для сохранения токена.
|
||||
* Эту ответственность теперь несет AuthRepository.
|
||||
*/
|
||||
class LoginUseCase @Inject constructor(
|
||||
private val itemRepository: ItemRepository
|
||||
private val authRepository: AuthRepository
|
||||
) {
|
||||
/**
|
||||
* [CONTRACT]
|
||||
* Executes the login process.
|
||||
* @param credentials The user's credentials.
|
||||
* @return A [Result] object indicating success or failure.
|
||||
* Выполняет процесс входа в систему.
|
||||
* @param credentials Учетные данные пользователя.
|
||||
* @return [Result] с [Unit] в случае успеха или с [Exception] в случае ошибки.
|
||||
* @sideeffect В случае успеха, сохраняет токен авторизации через `authRepository`.
|
||||
*/
|
||||
suspend operator fun invoke(credentials: Credentials): Result<Unit> {
|
||||
return itemRepository.login(credentials)
|
||||
// [PRECONDITION]
|
||||
require(credentials.serverUrl.isNotBlank() && credentials.username.isNotBlank()) {
|
||||
"[PRECONDITION_FAILED] Server URL and username must not be blank."
|
||||
}
|
||||
|
||||
// [ACTION] Выполняем вход через authRepository.
|
||||
val loginResult: Result<TokenResponse> = authRepository.login(credentials)
|
||||
|
||||
// [CORE-LOGIC] Обрабатываем результат с помощью `fold`.
|
||||
return loginResult.fold(
|
||||
onSuccess = { tokenResponse ->
|
||||
// [ACTION] В случае успеха, сохраняем токен через тот же репозиторий.
|
||||
authRepository.saveToken(tokenResponse.token)
|
||||
Result.success(Unit)
|
||||
},
|
||||
onFailure = { exception ->
|
||||
// [ACTION] В случае ошибки, просто пробрасываем ее дальше.
|
||||
Result.failure(exception)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
// [END_FILE_LoginUseCase.kt]
|
||||
// [END_FILE_LoginUseCase.kt]
|
||||
Reference in New Issue
Block a user