Fixes in edit/create travel
This commit is contained in:
@@ -1,22 +1,24 @@
|
||||
package eu.fosil.okupamicoche.dto
|
||||
|
||||
import eu.fosil.okupamicoche.entities.User
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
|
||||
class CreateUserDto(
|
||||
private val id: String,
|
||||
private val username: String,
|
||||
private val name: String,
|
||||
private val email: String?
|
||||
) {
|
||||
constructor(user: User) : this(
|
||||
user.id,
|
||||
user.username,
|
||||
user.name,
|
||||
user.email
|
||||
)
|
||||
|
||||
fun toUser(userRepository: UserRepository): User {
|
||||
fun toUser(): User {
|
||||
return User(
|
||||
id = id,
|
||||
username = username,
|
||||
name = name,
|
||||
email = email
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
class UserDto(
|
||||
// Los campos deben ser públicos para que aparezcan en el JSON
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val matrixId: String?,
|
||||
val name: String,
|
||||
val email: String?,
|
||||
@@ -15,6 +16,7 @@ class UserDto(
|
||||
) {
|
||||
constructor(user: User) : this(
|
||||
user.id,
|
||||
user.username,
|
||||
user.matrixId,
|
||||
user.name,
|
||||
user.email,
|
||||
@@ -25,6 +27,7 @@ class UserDto(
|
||||
fun toUser(userRepository: UserRepository): User {
|
||||
return User(
|
||||
id,
|
||||
username,
|
||||
matrixId,
|
||||
name,
|
||||
email,
|
||||
|
||||
@@ -2,16 +2,17 @@ package eu.fosil.okupamicoche.dto
|
||||
|
||||
import eu.fosil.okupamicoche.entities.User
|
||||
import eu.fosil.okupamicoche.entities.UserId
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
|
||||
class UserInfoDto(
|
||||
// Los campos deben ser públicos para que aparezcan en el JSON
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val matrixId: String?,
|
||||
val name: String
|
||||
) {
|
||||
constructor(user: User) : this(
|
||||
user.id,
|
||||
user.username,
|
||||
user.matrixId,
|
||||
user.name
|
||||
)
|
||||
@@ -19,6 +20,7 @@ class UserInfoDto(
|
||||
fun toUser(): User {
|
||||
return User(
|
||||
id,
|
||||
username,
|
||||
matrixId,
|
||||
name
|
||||
)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package eu.fosil.okupamicoche.entities
|
||||
|
||||
class UserIdNotFoundException : Exception()
|
||||
class UserIdNotFoundException(msg: String = "") : Exception(msg)
|
||||
|
||||
class UserNotSpecifiedException : Exception()
|
||||
class InsufficientPermissions(msg: String = "") : Exception(msg)
|
||||
|
||||
class UserNotSpecifiedException(msg: String = "") : Exception(msg)
|
||||
|
||||
class CannotDuplicateIdException(msg: String = "") : Exception(msg)
|
||||
@@ -7,6 +7,7 @@ typealias UserId = String
|
||||
@Entity
|
||||
class User(
|
||||
@Id var id: UserId,
|
||||
var username: String,
|
||||
var matrixId: String? = null,
|
||||
var name: String,
|
||||
var email: String? = null,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package eu.fosil.okupamicoche.entities
|
||||
|
||||
class UserKeycloak(
|
||||
val id: UserId,
|
||||
val username: String,
|
||||
val admin: Boolean,
|
||||
val name: String,
|
||||
val email: String
|
||||
) {
|
||||
constructor(claims: Map<String, Any>) : this(
|
||||
claims["sub"].toString(),
|
||||
claims["preferred_username"].toString(),
|
||||
try {
|
||||
claims["admin"] as Boolean
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
},
|
||||
claims["name"].toString(),
|
||||
claims["email"].toString()
|
||||
)
|
||||
|
||||
fun toUser(): User {
|
||||
return User(
|
||||
id,
|
||||
username,
|
||||
"@$username:fosil.eu",
|
||||
name,
|
||||
email
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,6 @@ package eu.fosil.okupamicoche.spring.controller
|
||||
|
||||
import eu.fosil.okupamicoche.entities.ApiErrorResponse
|
||||
import eu.fosil.okupamicoche.entities.ApiResponse
|
||||
import eu.fosil.okupamicoche.entities.UserIdNotFoundException
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
|
||||
interface ApiRestController {
|
||||
fun <T> response(function: () -> T): ApiResponse<T> {
|
||||
@@ -16,28 +13,4 @@ interface ApiRestController {
|
||||
ApiErrorResponse(e.javaClass.canonicalName, e.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelve el id del usuario actual.
|
||||
*/
|
||||
fun getCurrentUserId(): String {
|
||||
val authentication = SecurityContextHolder.getContext().authentication
|
||||
if (authentication.principal is Jwt) {
|
||||
val jwt = authentication.principal as Jwt
|
||||
return jwt.claims["sub"].toString()
|
||||
}
|
||||
throw UserIdNotFoundException()
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelve el id del usuario actual.
|
||||
*/
|
||||
fun getCurrentUserClaims(): Map<String, Any> {
|
||||
val authentication = SecurityContextHolder.getContext().authentication
|
||||
if (authentication.principal is Jwt) {
|
||||
val jwt = authentication.principal as Jwt
|
||||
return jwt.claims
|
||||
}
|
||||
throw UserIdNotFoundException()
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,10 @@ package eu.fosil.okupamicoche.spring.controller
|
||||
import eu.fosil.okupamicoche.dto.ListDto
|
||||
import eu.fosil.okupamicoche.dto.TravelDto
|
||||
import eu.fosil.okupamicoche.dto.UserInfoDto
|
||||
import eu.fosil.okupamicoche.entities.ApiResponse
|
||||
import eu.fosil.okupamicoche.entities.TravelId
|
||||
import eu.fosil.okupamicoche.entities.UserId
|
||||
import eu.fosil.okupamicoche.entities.UserIdNotFoundException
|
||||
import eu.fosil.okupamicoche.entities.*
|
||||
import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import eu.fosil.okupamicoche.spring.services.AuthService
|
||||
import eu.fosil.okupamicoche.usecases.travel.*
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.validation.annotation.Validated
|
||||
@@ -17,6 +15,7 @@ import org.springframework.web.bind.annotation.*
|
||||
@RestController
|
||||
@RequestMapping("/api/travel")
|
||||
class PrivateTravelRestController(
|
||||
private val authService: AuthService,
|
||||
private val userRepository: UserRepository,
|
||||
private val travelRepository: TravelRepository
|
||||
) : ApiRestController {
|
||||
@@ -24,7 +23,10 @@ class PrivateTravelRestController(
|
||||
@RequestMapping("/create")
|
||||
fun createTravel(@RequestBody @Validated travel: TravelDto): ApiResponse<Unit> {
|
||||
return response {
|
||||
val driver = userRepository.findByIdOrNull(getCurrentUserId()) ?: throw UserIdNotFoundException()
|
||||
val driver = userRepository.findByIdOrNull(authService.currentUser().id)
|
||||
?: throw UserIdNotFoundException("Current user not found.")
|
||||
if (travelRepository.findByIdOrNull(travel.id) != null)
|
||||
throw CannotDuplicateIdException("Travel id already exists.")
|
||||
println("travel des=${travel.description}")
|
||||
travel.driverInfo = UserInfoDto(driver)
|
||||
CreateTravel(travelRepository).createTravel(travel.toTravel(userRepository))
|
||||
@@ -41,13 +43,17 @@ class PrivateTravelRestController(
|
||||
@RequestMapping("/delete")
|
||||
fun deleteTravel(@RequestParam @Validated travelId: TravelId): ApiResponse<Unit> {
|
||||
return response {
|
||||
if (!authService.canEditTravel(travelId))
|
||||
throw InsufficientPermissions("Only admins and travel driver can delete this travel.")
|
||||
DeleteTravel(travelRepository).deleteTravel(travelId)
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/edit")
|
||||
fun editTravel(@RequestParam @Validated travel: TravelDto): ApiResponse<Unit> {
|
||||
fun editTravel(@RequestBody @Validated travel: TravelDto): ApiResponse<Unit> {
|
||||
return response {
|
||||
if (!authService.canEditTravel(travel.id))
|
||||
throw InsufficientPermissions("Only admins and travel driver can edit this travel.")
|
||||
EditTravel(travelRepository).editTravel(travel.toTravel(userRepository))
|
||||
}
|
||||
}
|
||||
@@ -55,7 +61,7 @@ class PrivateTravelRestController(
|
||||
@RequestMapping("/listusertravels")
|
||||
fun listUserTravels(): ApiResponse<ListDto<TravelDto>> {
|
||||
return response {
|
||||
val userId = getCurrentUserId()
|
||||
val userId = authService.currentUser().id
|
||||
val useCase = ListUserTravels(travelRepository)
|
||||
val travels = useCase.listUserTravels(userId).map { t -> TravelDto(t) }
|
||||
println("travels=$travels")
|
||||
@@ -66,7 +72,7 @@ class PrivateTravelRestController(
|
||||
@RequestMapping("/join")
|
||||
fun join(@RequestParam @Validated travelId: TravelId): ApiResponse<Unit> {
|
||||
return response {
|
||||
val userId = getCurrentUserId()
|
||||
val userId = authService.currentUser().id
|
||||
AddTraveler(userRepository, travelRepository).addTraveler(travelId, userId)
|
||||
}
|
||||
}
|
||||
@@ -74,7 +80,7 @@ class PrivateTravelRestController(
|
||||
@RequestMapping("/leave")
|
||||
fun leave(@RequestParam @Validated travelId: TravelId): ApiResponse<Unit> {
|
||||
return response {
|
||||
val userId = getCurrentUserId()
|
||||
val userId = authService.currentUser().id
|
||||
RemoveTraveler(userRepository, travelRepository).removeTraveler(travelId, userId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,34 +3,32 @@ package eu.fosil.okupamicoche.spring.controller
|
||||
import eu.fosil.okupamicoche.dto.CreateUserDto
|
||||
import eu.fosil.okupamicoche.dto.UserDto
|
||||
import eu.fosil.okupamicoche.entities.ApiResponse
|
||||
import eu.fosil.okupamicoche.entities.User
|
||||
import eu.fosil.okupamicoche.entities.InsufficientPermissions
|
||||
import eu.fosil.okupamicoche.entities.UserId
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import eu.fosil.okupamicoche.spring.services.AuthService
|
||||
import eu.fosil.okupamicoche.usecases.user.*
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.validation.annotation.Validated
|
||||
import org.springframework.web.bind.annotation.CrossOrigin
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/user")
|
||||
class PrivateUserRestController(private val userRepository: UserRepository) : ApiRestController {
|
||||
class PrivateUserRestController(
|
||||
private val authService: AuthService,
|
||||
private val userRepository: UserRepository
|
||||
) : ApiRestController {
|
||||
|
||||
@RequestMapping("/user")
|
||||
fun getCurrentUserCreateIfNeeded(): ApiResponse<UserDto> {
|
||||
return response {
|
||||
var user = userRepository.findByIdOrNull(getCurrentUserId())
|
||||
|
||||
val userKeycloak = authService.currentUser()
|
||||
var user = userRepository.findByIdOrNull(userKeycloak.id)
|
||||
|
||||
if (user == null) {
|
||||
val claims = getCurrentUserClaims()
|
||||
user = User(
|
||||
claims["sub"].toString(),
|
||||
"@${claims["preferred_username"].toString()}:fosil.eu",
|
||||
claims["given_name"].toString(),
|
||||
claims["email"].toString()
|
||||
)
|
||||
user = userKeycloak.toUser()
|
||||
CreateUser(userRepository).createUser(user)
|
||||
}
|
||||
|
||||
@@ -41,7 +39,9 @@ class PrivateUserRestController(private val userRepository: UserRepository) : Ap
|
||||
@RequestMapping("/create")
|
||||
fun createUser(@RequestBody @Validated createUserDto: CreateUserDto): ApiResponse<Unit> {
|
||||
return response {
|
||||
CreateUser(userRepository).createUser(createUserDto.toUser(userRepository))
|
||||
if (!authService.currentUser().admin)
|
||||
throw InsufficientPermissions("Only admins can create users.")
|
||||
CreateUser(userRepository).createUser(createUserDto.toUser())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package eu.fosil.okupamicoche.spring.services
|
||||
|
||||
import eu.fosil.okupamicoche.entities.*
|
||||
import eu.fosil.okupamicoche.repositories.TravelRepository
|
||||
import eu.fosil.okupamicoche.repositories.UserRepository
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class AuthService(
|
||||
private val userRepository: UserRepository,
|
||||
private val travelRepository: TravelRepository
|
||||
) {
|
||||
/**
|
||||
* Devuelve el id del usuario actual.
|
||||
*/
|
||||
fun currentUser(): UserKeycloak {
|
||||
val authentication = SecurityContextHolder.getContext().authentication
|
||||
if (authentication.principal is Jwt) {
|
||||
val jwt = authentication.principal as Jwt
|
||||
return UserKeycloak(jwt.claims)
|
||||
}
|
||||
throw UserIdNotFoundException()
|
||||
}
|
||||
|
||||
fun canEditTravel(travelId: TravelId?): Boolean {
|
||||
val travel = travelRepository.findByIdOrNull(travelId) ?: return false
|
||||
return currentUser().admin || currentUser().id == travel.driver.id
|
||||
}
|
||||
|
||||
fun canEditUser(user: User): Boolean {
|
||||
return currentUser().admin || currentUser().id == user.id
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user