diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/dto/UserDTO.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/dto/UserDTO.kt index 3c602f43bd2d6d55f4353195b67281bbd25c6621..10cf6da0c4b3060abdef46e23dfc49b274ed2312 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/dto/UserDTO.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/dto/UserDTO.kt @@ -9,5 +9,7 @@ data class UserDTO( val active: Boolean, val role: String, val avatarUrl: String, - val integrations: List? + val integrations: List?, + val email: String, + val tag: String, ) diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/dto/WorkspaceDTO.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/dto/WorkspaceDTO.kt index 72c1a58ebf664e9267f58ddf796e109de2546f2c..1b718668ee3cdf5e14e3c62b9b268f194d0ef3d9 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/dto/WorkspaceDTO.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/dto/WorkspaceDTO.kt @@ -7,5 +7,6 @@ data class WorkspaceDTO( val id: String, val name: String, val utilities: List, - val zone: WorkspaceZoneDTO? = null + val zone: WorkspaceZoneDTO? = null, + val tag: String ) diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/booking/routes/swagger/BookingSwagger.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/booking/routes/swagger/BookingSwagger.kt index fac4b7190b61332cf94cb75fe3a9980ba1902091..abd6b4db1683dabdc7af81d6ed50cd1b24ac3b71 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/booking/routes/swagger/BookingSwagger.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/booking/routes/swagger/BookingSwagger.kt @@ -84,24 +84,37 @@ fun SwaggerDocument.postBooking(): OpenApiRoute.() -> Unit = { "Bookings", BookingDTO( owner = UserDTO( id = "2c77feee-2bc1-11ee-be56-0242ac120002", - fullName = "Ivan Ivanov", + fullName = "Max", active = true, - role = "employee", + role = "Fullstack developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", - integrations = listOf(IntegrationDTO("c717cf6e-28b3-4148-a469-032991e5d9e9", "email", "123@effective.band")) + integrations = listOf(IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89087659880") + ), + email = "cool.fullstack.developer@effective.band", + tag = "employee" ), participants = listOf( UserDTO( id = "2c77feee-2bc1-11ee-be56-0242ac120002", fullName = "Ivan Ivanov", active = true, - role = "employee", + role = "Android developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", - integrations = listOf(IntegrationDTO("c717cf6e-28b3-4148-a469-032991e5d9e9", "email", "123@effective.band")) + integrations = listOf(IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89236379887") + ), + email = "cool.backend.developer@effective.band", + tag = "employee" ) ), workspace = WorkspaceDTO( - id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", utilities = listOf( + id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", tag = "meeting", + utilities = listOf( UtilityDTO( id = "50d89406-2bc6-11ee-be56-0242ac120002", name = "Sockets", @@ -194,30 +207,49 @@ private val bookingExample1 = BookingDTO( id = "2c77feee-2bc1-11ee-be56-0242ac120002", fullName = "Ivan Ivanov", active = true, - role = "employee", + role = "Backend developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", - integrations = listOf(IntegrationDTO("c717cf6e-28b3-4148-a469-032991e5d9e9", "email", "123@effective.band")) + integrations = listOf(IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89236379887") + ), + email = "cool.backend.developer@effective.band", + tag = "employee" ), participants = listOf( UserDTO( id = "2c77feee-2bc1-11ee-be56-0242ac120002", fullName = "Ivan Ivanov", active = true, - role = "employee", + role = "Backend developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", - integrations = listOf(IntegrationDTO("c717cf6e-28b3-4148-a469-032991e5d9e9", "email", "123@effective.band")) + integrations = listOf(IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89236379887") + ), + email = "cool.backend.developer@effective.band", + tag = "employee" ), UserDTO( id = "207b9634-2bc4-11ee-be56-0242ac120002", fullName = "Grzegorz Brzęczyszczykiewicz", active = true, - role = "guest", + role = "Guest", avatarUrl = "https://img.freepik.com/free-photo/capybara-in-the-nature-habitat-of-northern-pantanal_475641-1029.jpg", - integrations = listOf(IntegrationDTO("c717cf6e-28b3-4148-a469-032991e5d9e9", "email", "somemail@gmail.com")) + integrations = listOf(IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89086379880") + ), + email = "email@yahoo.com", + tag = "employee" ) ), workspace = WorkspaceDTO( - id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", utilities = listOf( + id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", tag = "meeting", + utilities = listOf( UtilityDTO( id = "50d89406-2bc6-11ee-be56-0242ac120002", name = "Sockets", @@ -241,22 +273,35 @@ private val bookingExample2 = BookingDTO( id = "2c77feee-2bc1-11ee-be56-0242ac120002", fullName = "Ivan Ivanov", active = true, - role = "employee", + role = "Backend developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", - integrations = listOf(IntegrationDTO("c717cf6e-28b3-4148-a469-032991e5d9e9", "email", "123@effective.band")) + integrations = listOf(IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89236379887") + ), + email = "cool.backend.developer@effective.band", + tag = "employee" ), participants = listOf( UserDTO( id = "2c77feee-2bc1-11ee-be56-0242ac120002", fullName = "Ivan Ivanov", active = true, - role = "employee", + role = "Backend developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", - integrations = listOf(IntegrationDTO("c717cf6e-28b3-4148-a469-032991e5d9e9", "email", "123@effective.band")) + integrations = listOf(IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89236379887") + ), + email = "cool.backend.developer@effective.band", + tag = "employee" ) ), workspace = WorkspaceDTO( - id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", utilities = listOf( + id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", tag = "meeting", + utilities = listOf( UtilityDTO( id = "50d89406-2bc6-11ee-be56-0242ac120002", name = "Sockets", diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/converters/UserDTOModelConverter.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/converters/UserDTOModelConverter.kt index d1879337ff8ec557a013e0e0fc47c2dfd3ac330d..05b07d8f5562e4c1ed30d850ca5ce4cd763a275d 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/converters/UserDTOModelConverter.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/converters/UserDTOModelConverter.kt @@ -11,27 +11,37 @@ import office.effective.model.UserModel class UserDTOModelConverter( private val repository: UserRepository, private val converter: IntegrationDTOModelConverter, - private val uuidConverter : UuidValidator + private val uuidConverter: UuidValidator ) { + /** + * Converts user dto to model + * + * @author Danil Kiselev, Daniil Zavyalov + */ fun dTOToModel(userDTO: UserDTO): UserModel { val userId = uuidConverter.uuidFromString(userDTO.id) val tag: UsersTagEntity? = repository.findTagByUserOrNull(userId); val integrations: MutableSet = mutableSetOf() userDTO.integrations?.forEach { integrations.add(converter.dTOToModel(it)) } return UserModel( - userDTO.fullName, - userId, - tag ?: UsersTagEntity(), - userDTO.active, - userDTO.role, - userDTO.avatarUrl, - integrations + fullName = userDTO.fullName, + id = userId, + tag = tag ?: UsersTagEntity(), + active = userDTO.active, + role = userDTO.role, + avatarURL = userDTO.avatarUrl, + integrations = integrations, + email = userDTO.email ) } + /** + * Converts user model to dto + * + * @author Danil Kiselev, Daniil Zavyalov + */ fun modelToDTO(userModel: UserModel): UserDTO { - val integrations: MutableList = mutableListOf() userModel.integrations?.forEach { integrations.add(converter.modelToDTO(it)) } return UserDTO( @@ -40,7 +50,9 @@ class UserDTOModelConverter( active = userModel.active, role = userModel.role ?: "", avatarUrl = userModel.avatarURL ?: "", - integrations = integrations + integrations = integrations, + email = userModel.email, + tag = userModel.tag.name ) } diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/converters/UserModelEntityConverter.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/converters/UserModelEntityConverter.kt index a64f69195215b22f091187b2c36ff999ac0aee8b..0a0073de10f0acb5467d11e7c9dc2ed0765148e3 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/converters/UserModelEntityConverter.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/converters/UserModelEntityConverter.kt @@ -1,30 +1,47 @@ package office.effective.features.user.converters +import office.effective.common.exception.MissingIdException import office.effective.features.user.repository.UserEntity import office.effective.model.IntegrationModel import office.effective.model.UserModel class UserModelEntityConverter { + + /** + * Converts user model to entity + * + * @throws MissingIdException if the user id is null + * + * @author Danil Kiselev, Daniil Zavyalov + */ fun modelToEntity(userModel: UserModel): UserEntity { - var res = UserEntity() - res.id = userModel.id!! - res.tag = userModel.tag - res.active = userModel.active - res.role = userModel.role - res.avatarURL = userModel.avatarURL - return res + return UserEntity { + id = userModel.id ?: throw MissingIdException("User with name ${userModel.fullName} doesn't have an id") + fullName = userModel.fullName + tag = userModel.tag + active = userModel.active + role = userModel.role + avatarURL = userModel.avatarURL + email = userModel.email + } } + /** + * Converts user entity to model + * + * @author Danil Kiselev, Daniil Zavyalov + */ fun entityToModel(userEntity: UserEntity, integrations: Set?): UserModel { return UserModel( - userEntity.fullName, + fullName = userEntity.fullName, id = userEntity.id, tag = userEntity.tag, active = userEntity.active, role = userEntity.role, avatarURL = userEntity.avatarURL, - integrations = integrations + integrations = integrations, + email = userEntity.email ) } diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/facade/UserFacade.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/facade/UserFacade.kt index 967d520426f2bb043e79291a8bdf293a15db7436..903791058ad89417095a95ec5714d8b5f74857c6 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/facade/UserFacade.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/facade/UserFacade.kt @@ -13,7 +13,7 @@ class UserFacade( private val verifier: ITokenVerifier, private val transactionManager: DatabaseTransactionManager ) { - fun getUsersByTag(tagStr: String, token: String): Set { + fun getUsersByTag(tagStr: String): Set { val models: Set = transactionManager.useTransaction>({ service.getUsersByTag(tagStr) }) val dtos: MutableSet = mutableSetOf() @@ -21,11 +21,37 @@ class UserFacade( return dtos.toSet() } - fun getUserById(userIdStr: String, token: String): UserDTO { + /** + * Retrieves all users + * @return Set + * + * @author Daniil Zavyalov + * */ + fun getUsers(): Set { + return transactionManager.useTransaction({ + val dtos: MutableSet = mutableSetOf() + for (model in service.getAll()) { + dtos.add(converterDTO.modelToDTO(model)) + } + dtos.toSet() + }) + } + + fun getUserById(userIdStr: String): UserDTO { return transactionManager.useTransaction({ converterDTO.modelToDTO(service.getUserById(userIdStr)) }) + } + /** + * Retrieves a user model by email + * + * @author Daniil Zavyalov + */ + fun getUserByEmail(email: String): UserDTO { + return transactionManager.useTransaction({ + converterDTO.modelToDTO(service.getUserByEmail(email)) + }) } /** diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/repository/UserEntity.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/repository/UserEntity.kt index 878fe6b4d0665d9caf0d261b76cea1f60ab33f23..b8d19adf3cf6f737881cb85057f10b2e9f389fbe 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/repository/UserEntity.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/repository/UserEntity.kt @@ -18,6 +18,7 @@ interface UserEntity : Entity { var active: Boolean var role: String? var avatarURL: String? + var email: String } object Users : Table("users") { @@ -27,6 +28,7 @@ object Users : Table("users") { val active = boolean("active").bindTo { it.active } val role = varchar("role").bindTo { it.role } val avatarURL = varchar("avatar_url").bindTo { it.avatarURL } + val email = varchar("email").bindTo { it.email } } val Database.users get() = this.sequenceOf(Users) \ No newline at end of file diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/repository/UserRepository.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/repository/UserRepository.kt index af3310930c5cd1c245da380914200474df3000ee..7fce03f0d83eb01921143b4298c81abbbcdb40ed 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/repository/UserRepository.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/repository/UserRepository.kt @@ -34,17 +34,36 @@ class UserRepository(private val db: Database, * */ fun findById(userId: UUID): UserModel { val userEnt: UserEntity = - db.users.find { it.id eq userId } ?: throw InstanceNotFoundException(UserEntity::class, "User ${userId}") + db.users.find { it.id eq userId } + ?: throw InstanceNotFoundException(UserEntity::class, "User with id $userId not found", userId) + val integrations = findSetOfIntegrationsByUser(userId) - val tagEntity = db.users_tags.find { it.id eq userEnt.tag.id } ?: throw InstanceNotFoundException( - UsersTagEntity::class, "Cannot find tag by id ${userEnt.tag.id}" - ) - val userModel = converter.entityToModel(userEnt, null) - userModel.integrations = integrations - userModel.tag = tagEntity + return converter.entityToModel(userEnt, integrations) + } + + /** + * Retrieves all users + * @return Set + * + * @author Daniil Zavyalov + * */ + fun findAll(): Set { + val entities = db.users.toSet() + if (entities.isEmpty()) return emptySet() + + val ids = mutableSetOf() - return userModel + for (entity in entities) { + ids.add(entity.id) + } + val integrations = findAllIntegrationsByUserIds(ids) + + val models = mutableSetOf() + for (entity in entities) { + models.add(converter.entityToModel(entity, integrations[entity.id])) + } + return models } /** @@ -56,7 +75,7 @@ class UserRepository(private val db: Database, fun findByTag(tagId: UUID): Set { val ents = db.users.filter { Users.tagId eq tagId }.toSet() - var models: MutableSet = mutableSetOf() + val models: MutableSet = mutableSetOf() ents.forEach { val user = converter.entityToModel(it, null) user.integrations = findSetOfIntegrationsByUser(user.id!!) @@ -67,18 +86,20 @@ class UserRepository(private val db: Database, } /** - * Searching user with input integration value. - * @return UserModel - user with integration value eq input line - * @throws InstanceNotFoundException if there are no users with such integration value + * Retrieves a user model by email * - * @author Danil Kiselev - * */ + * @return UserModel + * @throws InstanceNotFoundException if user with the given email doesn't exist in database + * @author Daniil Zavyalov + */ fun findByEmail(email: String): UserModel { - val integrationUserEntity: UserIntegrationEntity = - db.usersinegrations.find { it.valueStr eq email } ?: throw InstanceNotFoundException( - UserIntegrationEntity::class, "Integration with value ${email} not found" - ); - return findById(integrationUserEntity.userId.id) + val entity: UserEntity = + db.users.find { it.email eq email } + ?: throw InstanceNotFoundException(UserEntity::class, "User with email $email not found") + + val integrations = findSetOfIntegrationsByUser(entity.id) + + return converter.entityToModel(entity, integrations) } /** @@ -187,6 +208,7 @@ class UserRepository(private val db: Database, ent?.active = model.active ent?.avatarURL = model.avatarURL ent?.role = model.role + ent?.email = model.email ent?.flushChanges() val integrations: Set? = model.integrations diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/UserRouting.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/UserRouting.kt new file mode 100644 index 0000000000000000000000000000000000000000..1cb5ab726eda125cd8067cb673f25c3f3c7fe7d5 --- /dev/null +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/UserRouting.kt @@ -0,0 +1,47 @@ +package office.effective.features.user.routes + +import io.github.smiley4.ktorswaggerui.dsl.get +import io.github.smiley4.ktorswaggerui.dsl.put +import io.github.smiley4.ktorswaggerui.dsl.route +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import office.effective.common.swagger.SwaggerDocument +import office.effective.dto.UserDTO +import office.effective.features.user.facade.UserFacade +import office.effective.features.user.routes.swagger.updateUser +import office.effective.features.user.routes.swagger.returnUserById +import office.effective.features.user.routes.swagger.returnUsers +import org.koin.core.context.GlobalContext + +fun Route.userRouting() { + val facade: UserFacade = GlobalContext.get().get() + + route("users", {}) { + get(SwaggerDocument.returnUsers()) { + val tag: String? = call.request.queryParameters["user_tag"] + val email: String? = call.request.queryParameters["email"] + + when { + (email != null && tag != null) -> { + call.response.status(HttpStatusCode.BadRequest) + call.respondText("email and tag are mutually exclusive parameters") + } + (email != null) -> call.respond(facade.getUserByEmail(email)) + (tag != null) -> call.respond(facade.getUsersByTag(tag)) + else -> call.respond(facade.getUsers()) + } + } + get("/{user_id}", SwaggerDocument.returnUserById()) { + val userId: String = call.parameters["user_id"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val user = facade.getUserById(userId) + call.respond(user) + } + put("/{user_id}", SwaggerDocument.updateUser()) { + val user: UserDTO = call.receive() + call.respond(facade.updateUser(user)) + } + } +} \ No newline at end of file diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/swagger/AuthSwagger.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/swagger/AuthSwagger.kt deleted file mode 100644 index 1bffb7b880a5a315c5b0ce66df7b7a6609f0331c..0000000000000000000000000000000000000000 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/swagger/AuthSwagger.kt +++ /dev/null @@ -1,27 +0,0 @@ -package office.effective.features.user.routes.swagger - -import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute -import io.ktor.http.* -import office.effective.common.swagger.SwaggerDocument - -fun SwaggerDocument.login(): OpenApiRoute.() -> Unit = { - description = "Empty route. Need to redirect to google authentication page" - tags = listOf("users") -} - -fun SwaggerDocument.callback(): OpenApiRoute.() -> Unit = { - description = "Change user in db" - tags = listOf("users") - response { - HttpStatusCode.OK to { - description = "Return users emai;" - body { - example( - "User email", - "123@effective.band" - ) { - } - } - } - } -} \ No newline at end of file diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/swagger/UserSwagger.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/swagger/UserSwagger.kt index d4eb7206f51c8edc41d6d22ae8b360d28d7230b2..c54daad531539549ae656cd097778300fa26ae3d 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/swagger/UserSwagger.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/swagger/UserSwagger.kt @@ -6,65 +6,26 @@ import office.effective.common.swagger.SwaggerDocument import office.effective.dto.IntegrationDTO import office.effective.dto.UserDTO -fun SwaggerDocument.returnUserByEmail(): OpenApiRoute.() -> Unit = { - description = "Return user by email" - tags = listOf("userTests") - request { - pathParameter("email") { - description = "User`s email" - example = "user@effective.band" - required = true - allowEmptyValue = false - } - } - response { - HttpStatusCode.OK to { - description = "Return user found by email" - body { - example( - "User", - UserDTO( - id = "2c77feee-2bc1-11ee-be56-0242ac120002", - fullName = "Ivan Ivanov", - active = true, - role = "ADMIN", - avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", - integrations = listOf( - IntegrationDTO( - "13c80c3d-4278-45cf-8d2a-e281004d3ff9", - "email", - "123@effective.band" - ) - ) - ) - ) { - } - } - } - HttpStatusCode.BadRequest to { - description = "Bad request" - } - HttpStatusCode.NotFound to { - description = "User with this email was not found" - } - } -} - fun SwaggerDocument.returnUsers(): OpenApiRoute.() -> Unit = { - description = "Return all users by Tag name" + description = "Return all users, all users by tag or one user by email" tags = listOf("users") request{ - queryParameter("tag"){ - description = "Name of the tag" - example = "emploee" - required = true + queryParameter("user_tag"){ + description = "Name of the tag. Mutually exclusive with email" + example = "employee" + required = false + allowEmptyValue = false + } + queryParameter("email") { + description = "User's email. Mutually exclusive with tag" + example = "cool.backend.developer@effective.band" + required = false allowEmptyValue = false } - } response { HttpStatusCode.OK to { - description = "Return users list" + description = "Return users list or single user" body> { example( "Users", @@ -73,35 +34,77 @@ fun SwaggerDocument.returnUsers(): OpenApiRoute.() -> Unit = { id = "2c77feee-2bc1-11ee-be56-0242ac120002", fullName = "Ivan Ivanov", active = true, - role = "ADMIN", + role = "Backend developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", integrations = listOf( IntegrationDTO( - "13c80c3d-4278-45cf-8d2a-e281004d3ff9", - "email", - "123@effective.band" + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89236379887" + ), IntegrationDTO( + "8c02c6dc-1c4f-459e-ac27-f1db53923b2f", + "telegram", + "@cooldeveloper" ) - ) + ), + email = "cool.backend.developer@effective.band", + tag = "employee" ), UserDTO( id = "207b9634-2bc4-11ee-be56-0242ac120002", - fullName = "Lol Kekov", + fullName = "Danil Egorov", active = true, - role = "USER", + role = "Android developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", - integrations = listOf( - IntegrationDTO( - "13c80c3d-4278-45cf-8d2a-e281004d3ff9", - "email", - "321@effective.band" - ) - ) + integrations = listOf(IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89038760982") + ), + email = "cool.android.developer@effective.band", + tag = "employee" ) ) ) { + summary = "Return users list by tag" + } + example( + "User", + UserDTO( + id = "2c77feee-2bc1-11ee-be56-0242ac120002", + fullName = "Ivan Ivanov", + active = true, + role = "Backend developer", + avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", + integrations = listOf( + IntegrationDTO( + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89236379887" + ), IntegrationDTO( + "8c02c6dc-1c4f-459e-ac27-f1db53923b2f", + "telegram", + "@cooldeveloper" + ), IntegrationDTO( + "e321f85c-3f85-4c23-8e59-05005a82ffa8", + "Foobr", + "CoolDev@foobr.ru" + ) + ), + email = "cool.backend.developer@effective.band", + tag = "employee" + ) + ) { + summary = "Return user by email" } } } + HttpStatusCode.BadRequest to { + description = "Email and tag are mutually exclusive parameters" + } + HttpStatusCode.NotFound to { + description = "Provided tag doesn't exist or the user was not found when searching by email" + } } } @@ -126,15 +129,21 @@ fun SwaggerDocument.returnUserById(): OpenApiRoute.() -> Unit = { id = "2c77feee-2bc1-11ee-be56-0242ac120002", fullName = "Ivan Ivanov", active = true, - role = "ADMIN", + role = "Backend developer", avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", integrations = listOf( IntegrationDTO( - "13c80c3d-4278-45cf-8d2a-e281004d3ff9", - "email", - "123@effective.band" + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "89236379887" + ), IntegrationDTO( + "8c02c6dc-1c4f-459e-ac27-f1db53923b2f", + "telegram", + "@cooldeveloper" ) - ) + ), + email = "cool.android.developer@effective.band", + tag = "employee" ) ) { } @@ -171,15 +180,17 @@ fun SwaggerDocument.updateUser(): OpenApiRoute.() -> Unit = { avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", integrations = listOf( IntegrationDTO( - "13c80c3d-4278-45cf-8d2a-e281004d3ff9", - "email", - "0987654321@gmail.com" + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "88009000000" ), IntegrationDTO( - "52a3a1e0-21e1-4e76-b8c3-4b5ae7022aab", - "telegraph", - "@0987654321" + "8c02c6dc-1c4f-459e-ac27-f1db53923b2f", + "telegram", + "@mimocrocodile" ) - ) + ), + email = "mimocrocodile@mimo.crocodile", + tag = "guest" ) ) } @@ -198,15 +209,17 @@ fun SwaggerDocument.updateUser(): OpenApiRoute.() -> Unit = { avatarUrl = "https://img.freepik.com/free-photo/beautiful-shot-of-a-white-british-shorthair-kitten_181624-57681.jpg", integrations = listOf( IntegrationDTO( - "13c80c3d-4278-45cf-8d2a-e281004d3ff9", - "email", - "0987654321@gmail.com" + "c717cf6e-28b3-4148-a469-032991e5d9e9", + "phoneNumber", + "88009000000" ), IntegrationDTO( - "52a3a1e0-21e1-4e76-b8c3-4b5ae7022aab", - "telegraph", - "@0987654321" + "8c02c6dc-1c4f-459e-ac27-f1db53923b2f", + "telegram", + "@mimocrocodile" ) - ) + ), + email = "mimocrocodile@mimo.crocodile", + tag = "guest" ) ) { } @@ -216,7 +229,7 @@ fun SwaggerDocument.updateUser(): OpenApiRoute.() -> Unit = { description = "Bad request" } HttpStatusCode.NotFound to { - description = "User with this id was not found" + description = "User with this id not found" } } } diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/userRouting.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/userRouting.kt deleted file mode 100644 index cf8045c014f6035c976c3fb8238abde90418dbfe..0000000000000000000000000000000000000000 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/routes/userRouting.kt +++ /dev/null @@ -1,56 +0,0 @@ -package office.effective.features.user.routes - -import io.github.smiley4.ktorswaggerui.dsl.get -import io.github.smiley4.ktorswaggerui.dsl.put -import io.github.smiley4.ktorswaggerui.dsl.route -import io.ktor.http.* -import io.ktor.server.application.* -import io.ktor.server.request.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import office.effective.common.swagger.SwaggerDocument -import office.effective.features.user.ITokenVerifier -import office.effective.features.user.converters.UserDTOModelConverter -import office.effective.dto.UserDTO -import office.effective.features.user.facade.UserFacade -import office.effective.features.user.repository.UserRepository -import office.effective.features.user.routes.swagger.updateUser -import office.effective.features.user.routes.swagger.returnUserByEmail -import office.effective.features.user.routes.swagger.returnUserById -import office.effective.features.user.routes.swagger.returnUsers -import org.koin.core.context.GlobalContext - -fun Route.userRouting() { - val facade: UserFacade = GlobalContext.get().get() - val verifier: ITokenVerifier = GlobalContext.get().get() - - route("userTests", { - }) { - get("/{email}", SwaggerDocument.returnUserByEmail()) { - val repo: UserRepository = GlobalContext.get().get() - val model = - repo.findByEmail( - call.parameters["email"] ?: return@get call.respond(HttpStatusCode.BadRequest) - ) - val converterDTO: UserDTOModelConverter = GlobalContext.get().get() - call.respond(converterDTO.modelToDTO(model)) - } - } - route("users", {}) { - get("", SwaggerDocument.returnUsers()) { - var tagStr = call.request.queryParameters["tag"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val users: Set? = facade.getUsersByTag(tagStr as String, "tokenStr as String") - call.respond(users ?: "no such users") - } - get("/{user_id}", SwaggerDocument.returnUserById()) { - val userId : String = call.parameters["user_id"] ?: return@get call.respond(HttpStatusCode.BadRequest) - val user = facade.getUserById(userId, "zsd") - call.respond(user) - } - - put("/{user_id}", SwaggerDocument.updateUser()) { - val user: UserDTO = call.receive() - call.respond(facade.updateUser(user)) - } - } -} \ No newline at end of file diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/service/IUserService.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/service/IUserService.kt index 32257ade1d5c15ce05c8a0391e31901682bbec90..9f9d5c9d10106874ab13cb6444ce4255ff8d6144 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/service/IUserService.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/service/IUserService.kt @@ -4,6 +4,7 @@ import office.effective.model.UserModel interface IUserService { fun getUsersByTag(tagStr: String): Set; + fun getAll(): Set fun getUserById(userIdStr: String): UserModel; fun updateUser(user: UserModel): UserModel; fun getUserByEmail(emailStr: String): UserModel; diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/service/UserService.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/service/UserService.kt index 2838c8caec67170d672c8c0ff334a4a3d48cffb0..5df8eafb0c514af4b7b9ac6305bccc4a6f45587f 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/service/UserService.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/service/UserService.kt @@ -10,6 +10,16 @@ class UserService(private val repository: UserRepository) : IUserService { return repository.findByTag(repository.findTagByName(tagStr).id) } + /** + * Retrieves all users + * @return Set + * + * @author Daniil Zavyalov + * */ + override fun getAll(): Set { + return repository.findAll() + } + override fun getUserById(userIdStr: String): UserModel { return repository.findById(UUID.fromString(userIdStr)) } @@ -23,6 +33,11 @@ class UserService(private val repository: UserRepository) : IUserService { return repository.updateUser(user) } + /** + * Retrieves a user model by email + * + * @author Danil Kiselev + */ override fun getUserByEmail(emailStr: String): UserModel { return repository.findByEmail(emailStr) } diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/converters/WorkspaceFacadeConverter.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/converters/WorkspaceFacadeConverter.kt index e95b7e1c4816cc4c4517a3715095563b5a4e64ec..6393bda452bf61d573fad54c557e31db2b484a3c 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/converters/WorkspaceFacadeConverter.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/converters/WorkspaceFacadeConverter.kt @@ -21,7 +21,8 @@ class WorkspaceFacadeConverter(private val uuidValidator: UuidValidator) { model.id.toString(), model.name, utilities, - model.zone?.let { zoneModelToDto(it) } + model.zone?.let { zoneModelToDto(it) }, + model.tag ) } @@ -53,7 +54,7 @@ class WorkspaceFacadeConverter(private val uuidValidator: UuidValidator) { return Workspace( id = uuidValidator.uuidFromString(dto.id), name = dto.name, - tag = "", //This is probably wrong + tag = dto.tag, utilities = utilities, zone = dto.zone?.let { zoneDtoToModel(it) } ) diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/facade/WorkspaceFacade.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/facade/WorkspaceFacade.kt index 265754582877f62f1985031a0e5f9e3a164ce3d8..ab44e29b61999f72462ea12bf043ae667efe1736 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/facade/WorkspaceFacade.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/facade/WorkspaceFacade.kt @@ -19,7 +19,7 @@ class WorkspaceFacade(private val service: WorkspaceService, /** * Retrieves a workspace model by its id * - * Throws InstanceNotFoundException if workspace with the given id doesn't exist in database + * @throws InstanceNotFoundException if workspace with the given id doesn't exist in database * * @author Daniil Zavyalov */ diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/repository/WorkspaceRepository.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/repository/WorkspaceRepository.kt index dfe4beb148f2c1eae1886c81762e423ea23a3ab0..e7e4de4deb5ffc784091c3ebb300de4753f53fa0 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/repository/WorkspaceRepository.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/repository/WorkspaceRepository.kt @@ -136,7 +136,7 @@ class WorkspaceRepository(private val database: Database, private val converter: return database.from(Workspaces) .innerJoin(right = WorkspaceTags, on = WorkspaceTags.id eq Workspaces.tagId) - .innerJoin(right = WorkspaceZones, on = WorkspaceZones.id eq Workspaces.zoneId) + .leftJoin(right = WorkspaceZones, on = WorkspaceZones.id eq Workspaces.zoneId) .leftJoin( right = WorkspaceBooking, on = (Workspaces.id eq WorkspaceBooking.workspaceId) diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/routes/swagger/WorkspaceSwagger.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/routes/swagger/WorkspaceSwagger.kt index 4f0a9f0a59ee4e7c224acae21f1811c751d08a8e..fb8da5cafb5c443a5984c2b5a8ef8af3b8a3990f 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/routes/swagger/WorkspaceSwagger.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/workspace/routes/swagger/WorkspaceSwagger.kt @@ -24,7 +24,8 @@ fun SwaggerDocument.returnWorkspaceById(): OpenApiRoute.() -> Unit = { body { example( "Workspaces", WorkspaceDTO( - id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", utilities = listOf( + id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", tag = "meeting", + utilities = listOf( UtilityDTO( id = "50d89406-2bc6-11ee-be56-0242ac120002", name = "Sockets", @@ -80,7 +81,8 @@ fun SwaggerDocument.returnWorkspaceByTag(): OpenApiRoute.() -> Unit = { example( "Workspace", listOf( WorkspaceDTO( - id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", utilities = listOf( + id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Sun", tag = "meeting", + utilities = listOf( UtilityDTO( id = "50d89406-2bc6-11ee-be56-0242ac120002", name = "Sockets", @@ -94,7 +96,8 @@ fun SwaggerDocument.returnWorkspaceByTag(): OpenApiRoute.() -> Unit = { ) ) ), WorkspaceDTO( - id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Moon", utilities = listOf( + id = "2561471e-2bc6-11ee-be56-0242ac120002", name = "Moon", tag = "meeting", + utilities = listOf( UtilityDTO( id = "50d89406-2bc6-11ee-be56-0242ac120002", name = "Sockets", diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/model/UserModel.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/model/UserModel.kt index 2c52a905758f03311f90cdc52b3c8f539fa70ca4..cbdcf720da5e3b9831927e6cba02d8aad4ea1186 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/model/UserModel.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/model/UserModel.kt @@ -10,5 +10,6 @@ data class UserModel( var active: Boolean, var role: String?, var avatarURL: String?, - var integrations: Set? + var integrations: Set?, + var email: String ) \ No newline at end of file diff --git a/effectiveOfficeBackend/src/main/resources/changelog/changelog-1.7.yaml b/effectiveOfficeBackend/src/main/resources/changelog/changelog-1.7.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3c7dd8910a06b9e58991163a796909bcd3d7e954 --- /dev/null +++ b/effectiveOfficeBackend/src/main/resources/changelog/changelog-1.7.yaml @@ -0,0 +1,22 @@ +databaseChangeLog: + - changeSet: + id: create-email-domain + author: zavyalov-daniil + changes: + - sql: > + CREATE DOMAIN email_domain AS VARCHAR(255) + CHECK (VALUE ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'); + + - changeSet: + id: create-user-email-column + author: zavyalov-daniil + changes: + - addColumn: + tableName: users + columns: + - column: + name: email + type: email_domain + constraints: + nullable: false + unique: true diff --git a/effectiveOfficeBackend/src/main/resources/changelog/changelog-master.yaml b/effectiveOfficeBackend/src/main/resources/changelog/changelog-master.yaml index 0c0accbc0233d2e187c215ec2dfcf27b48559881..e327dfd94439cd80a519494e4a49d3fa1c1b7f22 100644 --- a/effectiveOfficeBackend/src/main/resources/changelog/changelog-master.yaml +++ b/effectiveOfficeBackend/src/main/resources/changelog/changelog-master.yaml @@ -12,4 +12,6 @@ databaseChangeLog: - include: file: changelog/changelog-1.5.yaml - include: - file: changelog/changelog-1.6.yaml \ No newline at end of file + file: changelog/changelog-1.6.yaml + - include: + file: changelog/changelog-1.7.yaml \ No newline at end of file