diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/auth/di/authDiModule.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/auth/di/authDiModule.kt index d072cbeeae2a77a3dba05db440e61a16a18f96cb..47b0e2ecf857f6c1f990725ef103b7d879117157 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/auth/di/authDiModule.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/auth/di/authDiModule.kt @@ -9,7 +9,7 @@ val authDiModule = module(createdAtStart = true) { single { AuthorizationPipeline() .addAuthorizer(PermitAuthorizer(listOf("/swagger/", "/notifications" ))) - .addAuthorizer(TokenAuthorizer(get())) + .addAuthorizer(TokenAuthorizer(get(), get())) .addAuthorizer(RequestAuthorizer(get())) .addAuthorizer(ApiKeyAuthorizer()) } diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/auth/service/TokenAuthorizer.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/auth/service/TokenAuthorizer.kt index c7501e467133ec0e1b5ae3e7f917d3e868979a06..c1d08a4303aa1dc75694765c9b2ae047d317b3e4 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/auth/service/TokenAuthorizer.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/auth/service/TokenAuthorizer.kt @@ -5,14 +5,19 @@ import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier import com.google.api.client.http.javanet.NetHttpTransport import com.google.api.client.json.gson.GsonFactory import io.ktor.server.application.* +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import office.effective.config +import office.effective.features.user.facade.UserFacade +import office.effective.features.user.repository.UserRepository +import office.effective.model.UserModel import org.slf4j.Logger import org.slf4j.LoggerFactory /** * Implementation of [Authorizer]. Checks GoogleIdTokens * */ -class TokenAuthorizer(private val extractor: TokenExtractor = TokenExtractor()) : Authorizer { +class TokenAuthorizer(private val extractor: TokenExtractor = TokenExtractor(), private val userFacade: UserFacade) : Authorizer { private val verifier: GoogleIdTokenVerifier = GoogleIdTokenVerifier.Builder(NetHttpTransport(), GsonFactory()).build() @@ -48,6 +53,7 @@ class TokenAuthorizer(private val extractor: TokenExtractor = TokenExtractor()) val emailVerified: Boolean = payload.emailVerified val hostedDomain = payload.hostedDomain ?: extractDomain(payload.email) + val currentAvatarUrl: String? = payload["picture"] as String?; if ((acceptableMailDomain == hostedDomain) && emailVerified) { userMail = payload.email } @@ -57,6 +63,7 @@ class TokenAuthorizer(private val extractor: TokenExtractor = TokenExtractor()) logger.trace("Token auth with token: {}", tokenString) return false } else { + checkUserAndUpdateAvatar(email = userMail, newAvatar = currentAvatarUrl, ) logger.info("Token auth succeed") return true } @@ -80,4 +87,16 @@ class TokenAuthorizer(private val extractor: TokenExtractor = TokenExtractor()) logger.trace("Token auth failed with token: {}", tokenString) return false } + + private fun checkUserAndUpdateAvatar(email: String, newAvatar: String?): Boolean { + val result = userFacade.existsByEmail(email) + runBlocking { + if(result) { + launch { + userFacade.updateAvatar(email, newAvatar) + } + } + } + return result; + } } diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/di/userDIModule.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/di/userDIModule.kt index 30874450bf4c3463339e7d51359a9d68efbae6cd..a5b04934c3f9eaf18df759701a8f54c6b6339676 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/di/userDIModule.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/features/user/di/userDIModule.kt @@ -15,7 +15,7 @@ val userDIModule = module(createdAtStart = true) { single { IntegrationModelEntityConverter() } single { UserModelEntityConverter() } single { UserDTOModelConverter(get(), get(), get()) } - single { UserRepository(get(), get(), get()) } + single { UserRepository(get(), get(), get(), get()) } single { UserFacade(get(), get(), get()) } single { IntegrationDTOModelConverter(get()) } } \ No newline at end of file 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 ceb3f023a34b44d17d9a7a282d6d740c43e101f4..50df848205f8abbad2f52bbf31dc1328aa6a6735 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 @@ -1,5 +1,6 @@ package office.effective.features.user.facade +import com.sun.source.tree.NewArrayTree import office.effective.common.exception.InstanceNotFoundException import office.effective.common.utils.DatabaseTransactionManager import office.effective.features.user.converters.UserDTOModelConverter @@ -101,4 +102,32 @@ class UserFacade( ) }) } + + /** + * Checks if a user with the specified email exists in the database. + * + * @param email The email of the user to check. + * @return true if a user with the specified email exists, false otherwise. + * @author Kiselev Danil + * */ + fun existsByEmail(email: String): Boolean { + return transactionManager.useTransaction({ + service.existsByEmail(email) + }) + } + + /** + *Updates the avatar URL for a user with the specified email. + * + * @param email The email of the user to update. + * @param newAvatar The new avatar URL to set. + * @throws InstanceNotFoundException if user with the specified email is not found. + * @author Kiselev Danil + * */ + fun updateAvatar(email: String, newAvatar: String?) { + transactionManager.useTransaction({ + service.updateAvatar(email, newAvatar) + }) + } + } 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 b458df7e4031f9d930f9fa7930b7c58e7414fc18..d9de3055efd713efd91471a61a054b3b57b262a3 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 @@ -1,6 +1,7 @@ package office.effective.features.user.repository import office.effective.common.exception.* +import office.effective.common.utils.DatabaseTransactionManager import office.effective.features.user.converters.IntegrationModelEntityConverter import office.effective.features.user.converters.UserModelEntityConverter import office.effective.model.IntegrationModel @@ -18,7 +19,8 @@ import java.util.* class UserRepository( private val db: Database, private val converter: UserModelEntityConverter, - private val integrationConverter: IntegrationModelEntityConverter + private val integrationConverter: IntegrationModelEntityConverter, + private val transactionManager: DatabaseTransactionManager ) { private val logger = LoggerFactory.getLogger(this::class.java) @@ -154,7 +156,7 @@ class UserRepository( ) ) } - return modelsSet; + return modelsSet } /** @@ -276,4 +278,39 @@ class UserRepository( val ent = findById(userId) return ent?.tag } + + /** + * Checks if a user with the specified email exists in the database. + * + * @param email The email of the user to check. + * @return true if a user with the specified email exists, false otherwise. + * @author Kiselev Danil + * */ + fun existsByEmail(email: String): Boolean { + + val entity: UserEntity? = db.users.find { it.email eq email } + return (entity != null) + } + + /** + * Updates the avatar URL for a user with the specified email. + * + * @param email The email of the user to update. + * @param newAvatar The new avatar URL to set. + * @throws InstanceNotFoundException if user with the specified email is not found. + * @author Kiselev Danil + * */ + fun updateAvatar(email: String, newAvatar: String?) { + transactionManager.useTransaction({ + logger.debug("[updateAvatar] retrieving a user with email {}", email) + val entity: UserEntity? = db.users.find { it.email eq email } + entity ?: throw InstanceNotFoundException(UserEntity::class, "User with email $email not wound") + + if (entity.avatarURL == newAvatar){ + logger.debug("[updateAvatar] updating user avatar with id {}", entity.id) + entity.avatarURL = newAvatar + entity.flushChanges() + } + }) + } } 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 957f290954cc767766a591611a5a94d20e134cdc..f8d3db3fbad6f2b85adf0cf727341c87e93bb4fe 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 @@ -49,4 +49,12 @@ class UserService(private val repository: UserRepository) : IUserService { override fun getUserByEmail(emailStr: String): UserModel? { return repository.findByEmail(emailStr) } + + override fun existsByEmail(email: String): Boolean { + return repository.existsByEmail(email) + } + + override fun updateAvatar(email: String, newAvatar: String?) { + repository.updateAvatar(email, newAvatar) + } } \ No newline at end of file diff --git a/effectiveOfficeBackend/src/main/kotlin/office/effective/serviceapi/IUserService.kt b/effectiveOfficeBackend/src/main/kotlin/office/effective/serviceapi/IUserService.kt index 1547f5e26699bee066118a69ae56732043258cfb..5f798efa12edd9b540460e6d2a6a1d4bac7edfbc 100644 --- a/effectiveOfficeBackend/src/main/kotlin/office/effective/serviceapi/IUserService.kt +++ b/effectiveOfficeBackend/src/main/kotlin/office/effective/serviceapi/IUserService.kt @@ -1,6 +1,11 @@ package office.effective.serviceapi +import office.effective.common.exception.InstanceNotFoundException +import office.effective.features.user.repository.UserEntity +import office.effective.features.user.repository.users import office.effective.model.UserModel +import org.ktorm.dsl.eq +import org.ktorm.entity.find /** * Interface that provides methods to manipulate [UserModel] objects @@ -50,4 +55,23 @@ interface IUserService { * @author Kiselev Danil * */ fun getUserByEmail(emailStr: String): UserModel?; + + /** + * Checks if a user with the specified email exists in the database. + * + * @param email The email of the user to check. + * @return true if a user with the specified email exists, false otherwise. + * @author Kiselev Danil + * */ + fun existsByEmail(email: String): Boolean + + /** + *Updates the avatar URL for a user with the specified email. + * + * @param email The email of the user to update. + * @param newAvatar The new avatar URL to set. + * @throws InstanceNotFoundException if user with the specified email is not found. + * @author Kiselev Danil + * */ + fun updateAvatar(email: String, newAvatar: String?) } \ No newline at end of file