diff --git a/src/main/kotlin/org/octopus/lorca_core/common/enums/EUserRoles.kt b/src/main/kotlin/org/octopus/lorca_core/common/enums/EUserRoles.kt index 7edd0e4..5e94dd3 100644 --- a/src/main/kotlin/org/octopus/lorca_core/common/enums/EUserRoles.kt +++ b/src/main/kotlin/org/octopus/lorca_core/common/enums/EUserRoles.kt @@ -5,5 +5,6 @@ enum class EUserRoles(val role: String) { PSICO("PSICO"), ALL("ALL"), ADMIN("ADMIN"), - BASE("BASE") + BASE("BASE"), + EMPTY("") } \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/common/models/Worker.kt b/src/main/kotlin/org/octopus/lorca_core/common/models/Worker.kt index 03306e5..8bbf16d 100644 --- a/src/main/kotlin/org/octopus/lorca_core/common/models/Worker.kt +++ b/src/main/kotlin/org/octopus/lorca_core/common/models/Worker.kt @@ -1,10 +1,14 @@ package org.octopus.lorca_core.common.models import org.octopus.lorca_core.common.enums.EWorkerCategory +import java.util.* data class Worker( var id: Long, var name: String, var surname: String, - val category: EWorkerCategory + var birthDate: Date, + var dni: String, + var email: String, + var category: EWorkerCategory, ) \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/config/security/JwtAuthenticationFilter.kt b/src/main/kotlin/org/octopus/lorca_core/config/security/JwtAuthenticationFilter.kt index 95d679b..9c2ff52 100644 --- a/src/main/kotlin/org/octopus/lorca_core/config/security/JwtAuthenticationFilter.kt +++ b/src/main/kotlin/org/octopus/lorca_core/config/security/JwtAuthenticationFilter.kt @@ -4,7 +4,6 @@ import jakarta.servlet.FilterChain import jakarta.servlet.ServletException import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse -import org.octopus.lorca_core.common.enums.EUserRoles import org.octopus.lorca_core.services.JwtService import org.springframework.lang.NonNull import org.springframework.security.authentication.UsernamePasswordAuthenticationToken @@ -48,7 +47,7 @@ class JwtAuthenticationFilter( val roles = jwtService.getRoles(jwt) - if (jwtService.isTokenValid(jwt, userDetails) && roles.contains(EUserRoles.BASE)) { + if (jwtService.isTokenValid(jwt, userDetails) && roles.isNotEmpty()) { val authToken = UsernamePasswordAuthenticationToken( userDetails, null, diff --git a/src/main/kotlin/org/octopus/lorca_core/config/security/SecurityConfig.kt b/src/main/kotlin/org/octopus/lorca_core/config/security/SecurityConfig.kt index 80349f8..e168db4 100644 --- a/src/main/kotlin/org/octopus/lorca_core/config/security/SecurityConfig.kt +++ b/src/main/kotlin/org/octopus/lorca_core/config/security/SecurityConfig.kt @@ -14,6 +14,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic @Configuration @EnableWebSecurity @EnableMethodSecurity(securedEnabled = true) + class SecurityConfig( val authenticationProvider: AuthenticationProvider, val jwtAuthenticationFilter: JwtAuthenticationFilter @@ -25,6 +26,7 @@ class SecurityConfig( .authorizeHttpRequests { auth -> auth .requestMatchers("/auth/**").permitAll() + .requestMatchers("/workers/register/**").hasRole("EMPTY") .anyRequest().authenticated() } .sessionManagement { session -> diff --git a/src/main/kotlin/org/octopus/lorca_core/db/entities/ClientEntity.kt b/src/main/kotlin/org/octopus/lorca_core/db/entities/ClientEntity.kt index 04f2271..de58d37 100644 --- a/src/main/kotlin/org/octopus/lorca_core/db/entities/ClientEntity.kt +++ b/src/main/kotlin/org/octopus/lorca_core/db/entities/ClientEntity.kt @@ -1,9 +1,7 @@ package org.octopus.lorca_core.db.entities -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id +import jakarta.persistence.* +import java.util.* @Entity(name = "clients") data class ClientEntity( @@ -11,5 +9,12 @@ data class ClientEntity( var id: Long = 0L, var name: String, var surname: String, + var dni: String, + val phoneNumber: String, + @Column(unique = true) + val expNumber: String, + @Column(unique = true) + val userNumber: String, + val birthDate: Date, val deactivated: Boolean ) \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/db/entities/WorkerEntity.kt b/src/main/kotlin/org/octopus/lorca_core/db/entities/WorkerEntity.kt index b883fcf..c01c451 100644 --- a/src/main/kotlin/org/octopus/lorca_core/db/entities/WorkerEntity.kt +++ b/src/main/kotlin/org/octopus/lorca_core/db/entities/WorkerEntity.kt @@ -2,6 +2,7 @@ package org.octopus.lorca_core.db.entities import jakarta.persistence.* import org.octopus.lorca_core.common.enums.EWorkerCategory +import java.util.* @Entity(name = "workers") data class WorkerEntity( @@ -9,6 +10,9 @@ data class WorkerEntity( var id: Long = 0L, var name: String, var surname: String, + var birthDate: Date, + var dni: String, + var email: String, var category: EWorkerCategory, @OneToOne var authUser: UserAuthEntity diff --git a/src/main/kotlin/org/octopus/lorca_core/repositories/impl/WorkerRepositoryImpl.kt b/src/main/kotlin/org/octopus/lorca_core/repositories/impl/WorkerRepositoryImpl.kt index e135a7c..33ce5ca 100644 --- a/src/main/kotlin/org/octopus/lorca_core/repositories/impl/WorkerRepositoryImpl.kt +++ b/src/main/kotlin/org/octopus/lorca_core/repositories/impl/WorkerRepositoryImpl.kt @@ -6,6 +6,7 @@ import org.octopus.lorca_core.common.mappers.WorkerMapper import org.octopus.lorca_core.common.models.Worker import org.octopus.lorca_core.db.WorkerJpa import org.octopus.lorca_core.db.entities.UserAuthEntity +import org.octopus.lorca_core.db.entities.WorkerEntity import org.octopus.lorca_core.repositories.WorkerRepository import org.springframework.stereotype.Component import kotlin.jvm.optionals.getOrNull @@ -21,9 +22,17 @@ class WorkerRepositoryImpl( } override fun createForUser(worker: Worker, userAuth: UserAuthEntity): Worker { - val w = mapper.toEntity(worker) - w.authUser = userAuth userAuth.setClaimsList(listOf(EUserRoles.FISIO, EUserRoles.ADMIN)) + val w = WorkerEntity( + id = 0L, + name = worker.name, + surname = worker.surname, + email = worker.email, + dni = worker.dni, + birthDate = worker.birthDate, + category = worker.category, + authUser = userAuth + ) val ent = jpa.save(w) return mapper.toModel(ent) } diff --git a/src/main/kotlin/org/octopus/lorca_core/services/WorkerService.kt b/src/main/kotlin/org/octopus/lorca_core/services/WorkerService.kt index d0e2c42..7538cd9 100644 --- a/src/main/kotlin/org/octopus/lorca_core/services/WorkerService.kt +++ b/src/main/kotlin/org/octopus/lorca_core/services/WorkerService.kt @@ -2,9 +2,10 @@ package org.octopus.lorca_core.services import org.octopus.lorca_core.common.enums.EWorkerCategory import org.octopus.lorca_core.common.models.Worker +import org.octopus.lorca_core.web.utils.dtos.WorkerDto interface WorkerService { - fun createTestData() fun getAllWorkers(): List fun getAllWorkersForCategory(workCategory: EWorkerCategory): List + fun createWorker(workerDto: WorkerDto, username: String): Worker } \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/services/impl/JwtServiceImpl.kt b/src/main/kotlin/org/octopus/lorca_core/services/impl/JwtServiceImpl.kt index 1c65471..476f708 100644 --- a/src/main/kotlin/org/octopus/lorca_core/services/impl/JwtServiceImpl.kt +++ b/src/main/kotlin/org/octopus/lorca_core/services/impl/JwtServiceImpl.kt @@ -75,7 +75,10 @@ class JwtServiceImpl( } override fun getRoles(token: String): List { - return (extractAllClaims(token).get("roles") as List).map { EUserRoles.valueOf(it) } + extractAllClaims(token)["roles"]?.let { roles -> + return (roles as List).map { EUserRoles.valueOf(it) } + } + return listOf(EUserRoles.EMPTY) } private fun isTokenExpired(token: String): Boolean { diff --git a/src/main/kotlin/org/octopus/lorca_core/services/impl/WorkerServiceImpl.kt b/src/main/kotlin/org/octopus/lorca_core/services/impl/WorkerServiceImpl.kt index 7315522..1fb1cc1 100644 --- a/src/main/kotlin/org/octopus/lorca_core/services/impl/WorkerServiceImpl.kt +++ b/src/main/kotlin/org/octopus/lorca_core/services/impl/WorkerServiceImpl.kt @@ -5,19 +5,11 @@ import org.octopus.lorca_core.common.models.Worker import org.octopus.lorca_core.repositories.UserAuthRepository import org.octopus.lorca_core.repositories.WorkerRepository import org.octopus.lorca_core.services.WorkerService +import org.octopus.lorca_core.web.utils.dtos.WorkerDto import org.springframework.stereotype.Service @Service class WorkerServiceImpl(val repo: WorkerRepository, val authRepository: UserAuthRepository) : WorkerService { - override fun createTestData() { - val worker = Worker( - id = 0, - name = "TestName", - surname = "TestSurname", - category = EWorkerCategory.FISIO - ) - repo.createForUser(worker, authRepository.getByUsername("test")) - } override fun getAllWorkers(): List { return repo.getAll().toList() @@ -26,4 +18,17 @@ class WorkerServiceImpl(val repo: WorkerRepository, val authRepository: UserAuth override fun getAllWorkersForCategory(workCategory: EWorkerCategory): List { return repo.getAllByCategory(workCategory) } + + override fun createWorker(workerDto: WorkerDto, username: String): Worker { + val worker = Worker( + id = 0L, + name = workerDto.name, + surname = workerDto.surname, + birthDate = workerDto.dateOfBirth, + email = workerDto.email, + category = workerDto.category, + dni = workerDto.dni + ) + return repo.createForUser(worker, authRepository.getByUsername(username)) + } } \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/web/controllers/WorkerController.kt b/src/main/kotlin/org/octopus/lorca_core/web/controllers/WorkerController.kt index d3b3b4b..400b4a3 100644 --- a/src/main/kotlin/org/octopus/lorca_core/web/controllers/WorkerController.kt +++ b/src/main/kotlin/org/octopus/lorca_core/web/controllers/WorkerController.kt @@ -1,10 +1,13 @@ package org.octopus.lorca_core.web.controllers +import jakarta.validation.Valid import lombok.AllArgsConstructor import org.octopus.lorca_core.common.enums.EWorkerCategory import org.octopus.lorca_core.common.models.Worker import org.octopus.lorca_core.services.WorkerService +import org.octopus.lorca_core.web.utils.dtos.WorkerDto import org.octopus.lorca_core.web.utils.responses.WebResponse +import org.springframework.security.core.context.SecurityContextHolder import org.springframework.web.bind.annotation.* @RestController @@ -30,6 +33,12 @@ class WorkerController( ) } + @PostMapping("/register") + fun registerAsWorker(@Valid @RequestBody workerDto: WorkerDto): WebResponse { + val username = SecurityContextHolder.getContext().authentication.name + return WebResponse.ok(workerService.createWorker(workerDto, username)) + } + @PostMapping("/test") fun createTestData(): WebResponse { // workerService.createTestData() diff --git a/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/ClientDto.kt b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/ClientDto.kt index 159c3e1..2b5b999 100644 --- a/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/ClientDto.kt +++ b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/ClientDto.kt @@ -1,11 +1,23 @@ package org.octopus.lorca_core.web.utils.dtos +import org.octopus.lorca_core.web.utils.dtos.validators.DniValidator +import org.octopus.lorca_core.web.utils.dtos.validators.ExpValidator import org.octopus.lorca_core.web.utils.dtos.validators.NameValidator +import org.octopus.lorca_core.web.utils.dtos.validators.PhoneValidator +import java.util.* data class ClientDto( @field:NameValidator.Validate val name: String, @field:NameValidator.Validate val surname: String, + @field:DniValidator.Validate + val dni: String, + @field:PhoneValidator.Validate + val phone: String, + @field:ExpValidator.Validate + val numExp: String, + val numUser: String, + val dateOfBirth: Date, val deactivated: Boolean ) \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/WorkerDto.kt b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/WorkerDto.kt new file mode 100644 index 0000000..08f7e82 --- /dev/null +++ b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/WorkerDto.kt @@ -0,0 +1,20 @@ +package org.octopus.lorca_core.web.utils.dtos + +import org.octopus.lorca_core.common.enums.EWorkerCategory +import org.octopus.lorca_core.web.utils.dtos.validators.DniValidator +import org.octopus.lorca_core.web.utils.dtos.validators.EmailValidator +import org.octopus.lorca_core.web.utils.dtos.validators.NameValidator +import java.util.* + +data class WorkerDto( + @field:NameValidator.Validate + val name: String, + @field:NameValidator.Validate + val surname: String, + @field:DniValidator.Validate + val dni: String, + val dateOfBirth: Date, + @field:EmailValidator.Validate + val email: String, + val category: EWorkerCategory +) \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/DniValidator.kt b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/DniValidator.kt new file mode 100644 index 0000000..661e727 --- /dev/null +++ b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/DniValidator.kt @@ -0,0 +1,34 @@ +package org.octopus.lorca_core.web.utils.dtos.validators + +import jakarta.validation.Constraint +import jakarta.validation.ConstraintValidator +import jakarta.validation.ConstraintValidatorContext +import jakarta.validation.Payload +import kotlin.reflect.KClass + + +class DniValidator : ConstraintValidator { + override fun isValid(value: String?, context: ConstraintValidatorContext): Boolean { + val pattern = Regex("^\\d{8}[A-Z]$") + + if (value == null || value.matches(pattern)) { + return true + } + + context.disableDefaultConstraintViolation() + context.buildConstraintViolationWithTemplate("Invalid value '$value' : 8 numbers and a letter are expected.") + .addConstraintViolation() + + return false + } + + @Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) + @Retention(AnnotationRetention.RUNTIME) + @MustBeDocumented + @Constraint(validatedBy = [DniValidator::class]) + annotation class Validate( + val message: String = "", + val groups: Array> = [], + val payload: Array> = [] + ) +} \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/EmailValidator.kt b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/EmailValidator.kt new file mode 100644 index 0000000..2ea237f --- /dev/null +++ b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/EmailValidator.kt @@ -0,0 +1,33 @@ +package org.octopus.lorca_core.web.utils.dtos.validators + +import jakarta.validation.Constraint +import jakarta.validation.ConstraintValidator +import jakarta.validation.ConstraintValidatorContext +import jakarta.validation.Payload +import kotlin.reflect.KClass + + +class EmailValidator : ConstraintValidator { + override fun isValid(value: String?, context: ConstraintValidatorContext): Boolean { + val pattern = Regex("^(?=.{1,64}@.{1,255}$)([a-zA-Z0-9._%+-]{1,64})@([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})$") + if (value == null || value.matches(pattern)) { + return true + } + + context.disableDefaultConstraintViolation() + context.buildConstraintViolationWithTemplate("Invalid value '$value' : Email pattern is wrong.") + .addConstraintViolation() + + return false + } + + @Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) + @Retention(AnnotationRetention.RUNTIME) + @MustBeDocumented + @Constraint(validatedBy = [EmailValidator::class]) + annotation class Validate( + val message: String = "", + val groups: Array> = [], + val payload: Array> = [] + ) +} \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/ExpValidator.kt b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/ExpValidator.kt new file mode 100644 index 0000000..1493087 --- /dev/null +++ b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/ExpValidator.kt @@ -0,0 +1,34 @@ +package org.octopus.lorca_core.web.utils.dtos.validators + +import jakarta.validation.Constraint +import jakarta.validation.ConstraintValidator +import jakarta.validation.ConstraintValidatorContext +import jakarta.validation.Payload +import kotlin.reflect.KClass + + +class ExpValidator : ConstraintValidator { + override fun isValid(value: String?, context: ConstraintValidatorContext): Boolean { + val pattern = Regex("") + + if (value == null || value.matches(pattern)) { + return true + } + + context.disableDefaultConstraintViolation() + context.buildConstraintViolationWithTemplate("Invalid value '$value' : 8 numbers and a letter are expected.") + .addConstraintViolation() + + return false + } + + @Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) + @Retention(AnnotationRetention.RUNTIME) + @MustBeDocumented + @Constraint(validatedBy = [ExpValidator::class]) + annotation class Validate( + val message: String = "", + val groups: Array> = [], + val payload: Array> = [] + ) +} \ No newline at end of file diff --git a/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/PhoneValidator.kt b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/PhoneValidator.kt new file mode 100644 index 0000000..9e4b55e --- /dev/null +++ b/src/main/kotlin/org/octopus/lorca_core/web/utils/dtos/validators/PhoneValidator.kt @@ -0,0 +1,34 @@ +package org.octopus.lorca_core.web.utils.dtos.validators + +import jakarta.validation.Constraint +import jakarta.validation.ConstraintValidator +import jakarta.validation.ConstraintValidatorContext +import jakarta.validation.Payload +import kotlin.reflect.KClass + + +class PhoneValidator : ConstraintValidator { + override fun isValid(value: String?, context: ConstraintValidatorContext): Boolean { + val pattern = Regex("^[6789]\\d{8}$") + + if (value == null || value.matches(pattern)) { + return true + } + + context.disableDefaultConstraintViolation() + context.buildConstraintViolationWithTemplate("Invalid value '$value' : Phone must start with [6,7,8,9] and 8 more numbers are expected.") + .addConstraintViolation() + + return false + } + + @Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) + @Retention(AnnotationRetention.RUNTIME) + @MustBeDocumented + @Constraint(validatedBy = [PhoneValidator::class]) + annotation class Validate( + val message: String = "", + val groups: Array> = [], + val payload: Array> = [] + ) +} \ No newline at end of file diff --git a/testSuite/fullRegisterCinematic/0_register_user.sh b/testSuite/fullRegisterCinematic/0_register_user.sh new file mode 100644 index 0000000..f0aaf06 --- /dev/null +++ b/testSuite/fullRegisterCinematic/0_register_user.sh @@ -0,0 +1,3 @@ +curl -X POST http://localhost:8080/api/auth/register \ + -H "Content-Type: application/json" \ + -d '{"username":"test","password":"cGFzc3dvcmQ="}' diff --git a/testSuite/fullRegisterCinematic/1_register_worker_on_user.sh b/testSuite/fullRegisterCinematic/1_register_worker_on_user.sh new file mode 100644 index 0000000..a6196d6 --- /dev/null +++ b/testSuite/fullRegisterCinematic/1_register_worker_on_user.sh @@ -0,0 +1,8 @@ +TOKEN=$(curl -s -X POST http://localhost:8080/api/auth/login \ + -H "Content-Type: application/json" \ + -d '{"username":"test","password":"cGFzc3dvcmQ="}' | sed -n 's/.*"token":"\([^"]*\)".*/\1/p') + +curl -X POST http://localhost:8080/api/workers/register \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"name": "Test","surname": "Test","dni": "12345678A","dateOfBirth": "1990-05-15","email": "jari.sciampi@mailbox.org","category":"FISIO"}' diff --git a/testSuite/login_and_clients.sh b/testSuite/login_and_clients.sh index 073bb52..af8bc65 100644 --- a/testSuite/login_and_clients.sh +++ b/testSuite/login_and_clients.sh @@ -2,9 +2,4 @@ TOKEN=$(curl -s -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"test","password":"cGFzc3dvcmQ="}' | sed -n 's/.*"token":"\([^"]*\)".*/\1/p') -#curl -H "Authorization: Bearer $TOKEN" -X POST http://localhost:8080/api/workers/test -#curl -H "Authorization: Bearer $TOKEN" -XGET http://localhost:8080/api/workers curl -G -H "Authorization: Bearer $TOKEN" --data-urlencode "category=FISIO" "http://localhost:8080/api/workers" - - -#echo "$TOKEN" diff --git a/testSuite/registerAsWorkerTest.sh b/testSuite/registerAsWorkerTest.sh new file mode 100644 index 0000000..c1a259d --- /dev/null +++ b/testSuite/registerAsWorkerTest.sh @@ -0,0 +1,18 @@ +TOKEN=$(curl -s -X POST http://localhost:8080/api/auth/login \ + -H "Content-Type: application/json" \ + -d '{"username":"test","password":"cGFzc3dvcmQ="}' | sed -n 's/.*"token":"\([^"]*\)".*/\1/p') + +#curl -H "Authorization: Bearer $TOKEN" -X POST http://localhost:8080/api/workers/test +#curl -H "Authorization: Bearer $TOKEN" -XGET http://localhost:8080/api/workers +curl -X POST http://localhost:8080/api/workers \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Carlos", + "surname": "Fernandez", + "dni": "12345678A", + "dateOfBirth": "1990-05-15", + "email": "carlos.fernandez@example.com"}' + + +#echo "$TOKEN"