Коммит 7b73455f создал по автору Radch-enko's avatar Radch-enko
Просмотр файлов

Feature: implement core booking and workspace APIs for tablet clients

- Added `BookingApi`, `WorkspaceApi`, and `UserApi` interfaces for defining API operations.
- Implemented `BookingApiImpl`, `WorkspaceApiImpl`, and `UserApiImpl` with server communication logic.
- Introduced error handling with `ErrorResponse` and result encapsulation using `Either`.
- Added reusable HTTP utilities for requests and client creation.
- Enhanced `WorkspaceDTO`, `UserDTO`, and `BookingResponseDTO` with serialization capabilities.
владелец 21094dd6
package band.effective.office.tablet.core.data.network
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
/**
* Android-specific implementation of HttpClientFactory
*/
actual object HttpClientFactory {
/**
* Creates an Android-specific HTTP client using OkHttp engine
* @return HttpClient instance
*/
actual fun createHttpClient(): HttpClient = HttpClient(OkHttp)
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.api
import band.effective.office.tablet.core.data.model.Either
import band.effective.office.tablet.core.data.model.ErrorResponse
import band.effective.office.tablet.core.data.dto.SuccessResponse
import band.effective.office.tablet.core.data.dto.booking.BookingRequestDTO
import band.effective.office.tablet.core.data.dto.booking.BookingResponseDTO
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
/**
* Interface for booking-related operations
*/
interface BookingApi {
/**
* Get booking by id
* @param id booking's id
* @return Information about booking
*/
suspend fun getBooking(id: String): Either<ErrorResponse, BookingResponseDTO>
/**
* Get user's bookings
* @param userId user id whose booking need get
* @param beginDate start date for bookings search
* @param endDate end date for bookings search
* @return list bookings current user
*/
suspend fun getBookingsByUser(
userId: String,
beginDate: Long,
endDate: Long
): Either<ErrorResponse, List<BookingResponseDTO>>
/**
* Get bookings in workspace
* @param workspaceId workspace id to be reserved
* @param from optional start date for bookings search
* @param to optional end date for bookings search
* @return list bookings in current workspace
*/
suspend fun getBookingsByWorkspaces(
workspaceId: String,
from: Long? = null,
to: Long? = null
): Either<ErrorResponse, List<BookingResponseDTO>>
/**
* Booking workspace
* @param bookingInfo information for booking workspace
* @return Created entry from database
*/
suspend fun createBooking(
bookingInfo: BookingRequestDTO
): Either<ErrorResponse, BookingResponseDTO>
/**
* Update booking info
* @param bookingInfo new information about booking
* @param bookingId id of booking to be updated
* @return new entry from database
*/
suspend fun updateBooking(
bookingInfo: BookingRequestDTO,
bookingId: String,
): Either<ErrorResponse, BookingResponseDTO>
/**
* Delete booking
* @param bookingId id of booking to be deleted
* @return If complete return SuccessResponse, else return ErrorResponse
*/
suspend fun deleteBooking(
bookingId: String
): Either<ErrorResponse, SuccessResponse>
/**
* Subscribe on bookings list updates
* @param workspaceId workspace name
* @param scope CoroutineScope for collect updates
* @return Flow with updates
*/
fun subscribeOnBookingsList(
workspaceId: String,
scope: CoroutineScope
): Flow<Either<ErrorResponse, List<BookingResponseDTO>>>
/**
* Get all bookings in a date range
* @param rangeFrom optional start date for bookings search
* @param rangeTo optional end date for bookings search
* @return list of all bookings in the date range
*/
suspend fun getBookings(
rangeFrom: Long? = null,
rangeTo: Long? = null
): Either<ErrorResponse, List<BookingResponseDTO>>
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.api
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.update
/**
* Utility class for collecting and sharing data updates.
* @param T Type of data to collect
* @param defaultValue Default value for the data
*/
class Collector<T>(defaultValue: T) {
private data class CollectableElement<T>(val value: T, val number: Long)
private val collection = MutableStateFlow(CollectableElement(defaultValue, 0))
/**
* Creates a flow that emits the collected values.
* @param scope CoroutineScope for sharing the flow
* @return Flow of collected values
*/
fun flow(scope: CoroutineScope) =
collection.map { it.value }.shareIn(
scope = scope,
started = SharingStarted.Lazily,
replay = 1
)
/**
* Emits a new value to the collection.
* @param value New value to emit
*/
fun emit(value: T) {
collection.update { CollectableElement(value = value, number = it.number + 1) }
}
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.api
import band.effective.office.tablet.core.data.model.Either
import band.effective.office.tablet.core.data.model.ErrorResponse
import band.effective.office.tablet.core.data.dto.user.UserDTO
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
/**
* Interface for user-related operations
*/
interface UserApi {
/**
* Get user by id
* @param id user id
* @return User info
*/
suspend fun getUser(id: String): Either<ErrorResponse, UserDTO>
/**
* Get all users
* @param tag user type (employee or guest)
* @return Users list
*/
suspend fun getUsers(tag: String): Either<ErrorResponse, List<UserDTO>>
/**
* Update information about user
* @param user new user model
* @return New model from database
*/
suspend fun updateUser(user: UserDTO): Either<ErrorResponse, UserDTO>
/**
* Get user by email
* @param email user email
* @return User info
*/
suspend fun getUserByEmail(email: String): Either<ErrorResponse, UserDTO>
/**
* Subscribe on organizers list updates
* @param scope CoroutineScope for collect updates
* @return Flow with updates
*/
fun subscribeOnOrganizersList(scope: CoroutineScope): Flow<Either<ErrorResponse, List<UserDTO>>>
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.api
import band.effective.office.tablet.core.data.model.Either
import band.effective.office.tablet.core.data.model.ErrorResponse
import band.effective.office.tablet.core.data.dto.workspace.WorkspaceDTO
import band.effective.office.tablet.core.data.dto.workspace.WorkspaceZoneDTO
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
/**
* Interface for workspace-related operations
*/
interface WorkspaceApi {
/**
* Get workspace by name
* @param id workspace name
* @return Workspace info
*/
suspend fun getWorkspace(id: String): Either<ErrorResponse, WorkspaceDTO>
/**
* Get all workspace current type
* @param tag workspace type (meeting or regular)
* @param freeFrom optional start time to check availability
* @param freeUntil optional end time to check availability
* @return List of workspaces
*/
suspend fun getWorkspaces(
tag: String,
freeFrom: Long? = null,
freeUntil: Long? = null
): Either<ErrorResponse, List<WorkspaceDTO>>
/**
* Get all workspace with bookings current type
* @param tag workspace type (meeting or regular)
* @param withBookings whether to include bookings
* @param freeFrom optional start time to check availability
* @param freeUntil optional end time to check availability
* @return List of workspaces with bookings
*/
suspend fun getWorkspacesWithBookings(
tag: String,
withBookings: Boolean = true,
freeFrom: Long? = null,
freeUntil: Long? = null
): Either<ErrorResponse, List<WorkspaceDTO>>
/**
* Get all workspace zones
* @return List of workspace zones
*/
suspend fun getZones(): Either<ErrorResponse, List<WorkspaceZoneDTO>>
/**
* Subscribe on workspace info updates
* @param id workspace name
* @param scope CoroutineScope for collect updates
* @return Flow with updates
*/
fun subscribeOnWorkspaceUpdates(
id: String,
scope: CoroutineScope
): Flow<Either<ErrorResponse, WorkspaceDTO>>
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.api.impl
import band.effective.office.tablet.core.data.api.BookingApi
import band.effective.office.tablet.core.data.api.Collector
import band.effective.office.tablet.core.data.dto.SuccessResponse
import band.effective.office.tablet.core.data.dto.booking.BookingRequestDTO
import band.effective.office.tablet.core.data.dto.booking.BookingResponseDTO
import band.effective.office.tablet.core.data.model.Either
import band.effective.office.tablet.core.data.model.ErrorResponse
import band.effective.office.tablet.core.data.network.HttpClientProvider
import band.effective.office.tablet.core.data.network.HttpRequestUtil
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.appendPathSegments
import io.ktor.http.contentType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
/**
* Implementation of the BookingApi interface
*/
class BookingApiImpl(
private val baseUrl: String,
private val collector: Collector<String> = Collector("")
) : BookingApi {
private val client = HttpClientProvider.create()
override suspend fun getBooking(id: String): Either<ErrorResponse, BookingResponseDTO> {
return when (val result = HttpRequestUtil.request<BookingResponseDTO>(
client = client,
url = "$baseUrl/api/v1/bookings",
method = HttpRequestUtil.Method.GET
) {
url {
appendPathSegments(id)
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun getBookingsByUser(
userId: String,
beginDate: Long,
endDate: Long
): Either<ErrorResponse, List<BookingResponseDTO>> {
return when (val result = HttpRequestUtil.request<List<BookingResponseDTO>>(
client = client,
url = "$baseUrl/api/v1/bookings",
method = HttpRequestUtil.Method.GET
) {
url {
parameters.append("user_id", userId)
parameters.append("range_from", beginDate.toString())
parameters.append("range_to", endDate.toString())
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun getBookingsByWorkspaces(
workspaceId: String,
from: Long?,
to: Long?
): Either<ErrorResponse, List<BookingResponseDTO>> {
return when (val result = HttpRequestUtil.request<List<BookingResponseDTO>>(
client = client,
url = "$baseUrl/api/v1/bookings",
method = HttpRequestUtil.Method.GET
) {
url {
parameters.append("workspace_id", workspaceId)
if (from != null) {
parameters.append("range_from", from.toString())
}
if (to != null) {
parameters.append("range_to", to.toString())
}
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun createBooking(bookingInfo: BookingRequestDTO): Either<ErrorResponse, BookingResponseDTO> {
return when (val result = HttpRequestUtil.request<BookingResponseDTO>(
client = client,
url = "$baseUrl/api/v1/bookings",
method = HttpRequestUtil.Method.POST
) {
contentType(ContentType.Application.Json)
setBody(bookingInfo)
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun updateBooking(
bookingInfo: BookingRequestDTO,
bookingId: String
): Either<ErrorResponse, BookingResponseDTO> {
return when (val result = HttpRequestUtil.request<BookingResponseDTO>(
client = client,
url = "$baseUrl/api/v1/bookings",
method = HttpRequestUtil.Method.PUT
) {
url {
appendPathSegments(bookingId)
}
contentType(ContentType.Application.Json)
val body = Json.encodeToString(bookingInfo)
setBody(bookingInfo)
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun deleteBooking(bookingId: String): Either<ErrorResponse, SuccessResponse> {
return when (val result = HttpRequestUtil.request<SuccessResponse>(
client = client,
url = "$baseUrl/api/v1/bookings",
method = HttpRequestUtil.Method.DELETE
) {
url {
appendPathSegments(bookingId)
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override fun subscribeOnBookingsList(
workspaceId: String,
scope: CoroutineScope
): Flow<Either<ErrorResponse, List<BookingResponseDTO>>> {
return collector.flow(scope)
.filter { it == "booking" }
.map { Either.Success(listOf()) }
}
override suspend fun getBookings(
rangeFrom: Long?,
rangeTo: Long?
): Either<ErrorResponse, List<BookingResponseDTO>> {
return when (val result = HttpRequestUtil.request<List<BookingResponseDTO>>(
client = client,
url = "$baseUrl/api/v1/bookings",
method = HttpRequestUtil.Method.GET
) {
url {
if (rangeFrom != null) {
parameters.append("range_from", rangeFrom.toString())
}
if (rangeTo != null) {
parameters.append("range_to", rangeTo.toString())
}
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.api.impl
import band.effective.office.tablet.core.data.api.Collector
import band.effective.office.tablet.core.data.api.UserApi
import band.effective.office.tablet.core.data.dto.user.UserDTO
import band.effective.office.tablet.core.data.model.Either
import band.effective.office.tablet.core.data.model.ErrorResponse
import band.effective.office.tablet.core.data.network.HttpClientProvider
import band.effective.office.tablet.core.data.network.HttpRequestUtil
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.appendPathSegments
import io.ktor.http.contentType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
/**
* Implementation of the UserApi interface
*/
class UserApiImpl(
private val baseUrl: String,
private val collector: Collector<String> = Collector("")
) : UserApi {
private val client = HttpClientProvider.create()
override suspend fun getUser(id: String): Either<ErrorResponse, UserDTO> {
return when (val result = HttpRequestUtil.request<UserDTO>(
client = client,
url = "$baseUrl/api/v1/users",
method = HttpRequestUtil.Method.GET
) {
url {
appendPathSegments(id)
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun getUsers(tag: String): Either<ErrorResponse, List<UserDTO>> {
return when (val result = HttpRequestUtil.request<List<UserDTO>>(
client = client,
url = "$baseUrl/api/v1/users",
method = HttpRequestUtil.Method.GET
) {
url {
parameters.append("user_tag", tag)
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun updateUser(user: UserDTO): Either<ErrorResponse, UserDTO> {
return when (val result = HttpRequestUtil.request<UserDTO>(
client = client,
url = "$baseUrl/api/v1/users",
method = HttpRequestUtil.Method.PUT
) {
contentType(ContentType.Application.Json)
setBody(user)
url {
appendPathSegments(user.id)
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun getUserByEmail(email: String): Either<ErrorResponse, UserDTO> {
return when (val result = HttpRequestUtil.request<UserDTO>(
client = client,
url = "$baseUrl/api/v1/users",
method = HttpRequestUtil.Method.GET
) {
url {
parameters.append(name = "email", value = email)
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override fun subscribeOnOrganizersList(scope: CoroutineScope): Flow<Either<ErrorResponse, List<UserDTO>>> {
return collector.flow(scope)
.filter { it == "organizer" }
.map { Either.Success(listOf()) }
}
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.api.impl
import band.effective.office.tablet.core.data.api.Collector
import band.effective.office.tablet.core.data.api.WorkspaceApi
import band.effective.office.tablet.core.data.dto.workspace.WorkspaceDTO
import band.effective.office.tablet.core.data.dto.workspace.WorkspaceZoneDTO
import band.effective.office.tablet.core.data.model.Either
import band.effective.office.tablet.core.data.model.ErrorResponse
import band.effective.office.tablet.core.data.network.HttpClientProvider
import band.effective.office.tablet.core.data.network.HttpRequestUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
/**
* Implementation of the WorkspaceApi interface
*/
class WorkspaceApiImpl(
private val baseUrl: String,
private val collector: Collector<String> = Collector("")
) : WorkspaceApi {
private val client = HttpClientProvider.create()
override suspend fun getWorkspace(id: String): Either<ErrorResponse, WorkspaceDTO> {
return when (val workspaces = getWorkspaces("meeting")) {
is Either.Error -> workspaces
is Either.Success -> workspaces.data.firstOrNull { it.name == id }.let {
if (it == null) {
Either.Error(ErrorResponse.getResponse(404))
} else {
Either.Success(it)
}
}
}
}
override suspend fun getWorkspaces(
tag: String,
freeFrom: Long?,
freeUntil: Long?
): Either<ErrorResponse, List<WorkspaceDTO>> {
return when (val result = HttpRequestUtil.request<List<WorkspaceDTO>>(
client = client,
url = "$baseUrl/api/v1/workspaces",
method = HttpRequestUtil.Method.GET
) {
url {
parameters.append("workspace_tag", tag)
if (freeFrom != null) {
parameters.append("free_from", freeFrom.toString())
}
if (freeUntil != null) {
parameters.append("free_until", freeUntil.toString())
}
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun getWorkspacesWithBookings(
tag: String,
withBookings: Boolean,
freeFrom: Long?,
freeUntil: Long?
): Either<ErrorResponse, List<WorkspaceDTO>> {
return when (val result = HttpRequestUtil.request<List<WorkspaceDTO>>(
client = client,
url = "$baseUrl/api/v1/workspaces",
method = HttpRequestUtil.Method.GET
) {
url {
parameters.append("workspace_tag", tag)
parameters.append("with_bookings", withBookings.toString())
if (freeFrom != null) {
parameters.append("with_bookings_from", freeFrom.toString())
}
if (freeUntil != null) {
parameters.append("with_bookings_until", freeUntil.toString())
}
}
}) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override suspend fun getZones(): Either<ErrorResponse, List<WorkspaceZoneDTO>> {
return when (val result = HttpRequestUtil.request<List<WorkspaceZoneDTO>>(
client = client,
url = "$baseUrl/api/v1/workspaces/zones",
method = HttpRequestUtil.Method.GET
)) {
is HttpRequestUtil.Result.Success -> Either.Success(result.data)
is HttpRequestUtil.Result.Error -> Either.Error(ErrorResponse(result.code, result.message))
}
}
override fun subscribeOnWorkspaceUpdates(
id: String,
scope: CoroutineScope
): Flow<Either<ErrorResponse, WorkspaceDTO>> {
return collector.flow(scope)
.filter { it == "workspace" }
.map {
Either.Success(
WorkspaceDTO(
id = "",
name = "",
utilities = listOf(),
zone = null,
tag = ""
)
)
}
}
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto
import kotlinx.serialization.Serializable
/**
* Represents a successful response from the server.
* @property success Indicates whether the operation was successful
*/
@Serializable
data class SuccessResponse(val success: Boolean = true)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto.booking
import kotlinx.serialization.Serializable
/**
* Represents a request to book a workspace.
* @property ownerEmail Email of the booking owner
* @property participantEmails List of participant emails
* @property workspaceId ID of the workspace to book
* @property beginBooking Start time of the booking (Unix timestamp)
* @property endBooking End time of the booking (Unix timestamp)
* @property recurrence Recurrence pattern for recurring bookings
*/
@Serializable
data class BookingRequestDTO(
val ownerEmail: String?,
val participantEmails: List<String>,
val workspaceId: String,
val beginBooking: Long,
val endBooking: Long,
val recurrence: RecurrenceDTO? = null
)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto.booking
import band.effective.office.tablet.core.data.dto.user.UserDTO
import band.effective.office.tablet.core.data.dto.workspace.WorkspaceDTO
import kotlinx.serialization.Serializable
/**
* Represents a response for a booking.
* @property owner Owner of the booking
* @property participants List of participants in the booking
* @property workspace Workspace that is booked
* @property id Unique identifier of the booking
* @property beginBooking Start time of the booking (Unix timestamp)
* @property endBooking End time of the booking (Unix timestamp)
* @property recurrence Recurrence pattern for recurring bookings
* @property recurringBookingId ID of the recurring booking series this booking belongs to
*/
@Serializable
data class BookingResponseDTO(
val owner: UserDTO?,
val participants: List<UserDTO>,
val workspace: WorkspaceDTO,
val id: String,
val beginBooking: Long,
val endBooking: Long,
val recurrence: RecurrenceDTO? = null,
val recurringBookingId: String? = null
)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto.booking
import kotlinx.serialization.Serializable
/**
* Represents a recurrence pattern for bookings.
* @property interval Period of bookings (e.g., every 2 days)
* @property freq Frequency type (DAILY, WEEKLY, MONTHLY, YEARLY)
* @property count Number of occurrences
* @property until End date of recurrence
* @property byDay Days of the week for recurrence
* @property byMonth Months for recurrence
* @property byYearDay Days of the year for recurrence
* @property byHour Hours for recurrence
*/
@Serializable
data class RecurrenceDTO(
val interval: Int? = null,
val freq: String,
val count: Int? = null,
val until: Long? = null,
val byDay: List<Int> = listOf(),
val byMonth: List<Int> = listOf(),
val byYearDay: List<Int> = listOf(),
val byHour: List<Int> = listOf()
)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto.user
import kotlinx.serialization.Serializable
/**
* Represents an integration with an external service.
* @property id Unique identifier
* @property name Name of the integration
* @property value Value of the integration
*/
@Serializable
data class IntegrationDTO(
val id: String,
val name: String,
val value: String
)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto.user
import kotlinx.serialization.Serializable
/**
* Represents a user in the system.
* @property id Unique identifier (UUIDv4)
* @property fullName Full name of the user
* @property active Whether the user is active
* @property role Role of the user
* @property avatarUrl URL to the user's avatar
* @property integrations List of integrations associated with the user
* @property email Email address of the user
* @property tag User type (employee or guest)
*/
@Serializable
data class UserDTO(
val id: String,
val fullName: String,
val active: Boolean,
val role: String,
val avatarUrl: String,
val integrations: List<IntegrationDTO>? = null,
val email: String = "",
val tag: String = ""
)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto.workspace
import kotlinx.serialization.Serializable
/**
* Represents a utility available in a workspace.
* @property id Unique identifier
* @property name Name of the utility
* @property iconUrl URL to the utility's icon
* @property count Number of this utility available
*/
@Serializable
data class UtilityDTO(
val id: String,
val name: String,
val iconUrl: String,
val count: Int
)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto.workspace
import kotlinx.serialization.Serializable
/**
* Represents a workspace.
* @property id Unique identifier
* @property name Name of the workspace
* @property utilities List of utilities available in the workspace
* @property zone Zone where the workspace is located
* @property tag Type of workspace (e.g., meeting, regular)
* @property bookings List of bookings for this workspace (optional)
*/
@Serializable
data class WorkspaceDTO(
val id: String,
val name: String,
val utilities: List<UtilityDTO>,
val zone: WorkspaceZoneDTO? = null,
val tag: String,
val bookings: List<BookingInfo>? = null
)
/**
* Simplified booking information to avoid circular dependency with BookingResponseDTO.
* @property id Booking identifier
* @property beginBooking Start time of the booking
* @property endBooking End time of the booking
*/
@Serializable
data class BookingInfo(
val id: String,
val beginBooking: Long,
val endBooking: Long
)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.dto.workspace
import kotlinx.serialization.Serializable
/**
* Represents a zone in the workspace.
* @property id Unique identifier
* @property name Name of the zone
*/
@Serializable
data class WorkspaceZoneDTO(
val id: String,
val name: String
)
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.model
/**
* Represents a value of one of two possible types (a disjoint union).
* Instances of [Either] are either an instance of [Error] or [Success].
*/
sealed interface Either<out ErrorType, out DataType> {
/**
* Represents the error case of the disjoint union.
*/
data class Error<out ErrorType>(val error: ErrorType) : Either<ErrorType, Nothing>
/**
* Represents the success case of the disjoint union.
*/
data class Success<out DataType>(val data: DataType) : Either<Nothing, DataType>
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.model
/**
* Represents an error response from the server.
* @property code HTTP status code
* @property description Error description
*/
data class ErrorResponse(val code: Int, val description: String) {
companion object {
/**
* Creates an error response based on the HTTP status code.
* @param code HTTP status code
* @return ErrorResponse with a description based on the code
*/
fun getResponse(code: Int): ErrorResponse {
val description = when (code) {
404 -> "Not found"
in 400..499 -> "Client error"
in 500..599 -> "Server error"
else -> "Unknown error"
}
return ErrorResponse(code, description)
}
}
}
\ Нет новой строки в конце файла
package band.effective.office.tablet.core.data.network
import io.ktor.client.HttpClient
/**
* Factory for creating platform-specific HTTP clients
*/
expect object HttpClientFactory {
/**
* Creates a platform-specific HTTP client
* @return HttpClient instance
*/
fun createHttpClient(): HttpClient
}
\ Нет новой строки в конце файла
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать