Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import jakarta.persistence.Id
import jakarta.persistence.OneToMany
import jakarta.persistence.SequenceGenerator
import jakarta.persistence.Table
import jakarta.persistence.UniqueConstraint
import org.hibernate.annotations.BatchSize
import org.hibernate.annotations.Cache
import org.hibernate.annotations.CacheConcurrencyStrategy
Expand All @@ -36,7 +37,7 @@ import java.util.Objects
import java.util.UUID

@Entity
@Table(name = "rest_source_user")
@Table(name = "rest_source_user", uniqueConstraints = [UniqueConstraint(columnNames = ["external_user_id", "source_type"])])
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
class RestSourceUser(
@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ class RestSourceUserService(

suspend fun create(userDto: RestSourceUserDTO): RestSourceUserDTO {
userDto.ensure()

// Check if the service user ID is already in use for the same source type.
userDto.serviceUserId?.let { serviceUserId ->
val existingExternalUser = userRepository.findByExternalId(
externalId = serviceUserId,
sourceType = userDto.sourceType,
)
if (existingExternalUser != null) {
val response = Response.status(Response.Status.CONFLICT)
.entity(mapOf("status" to 409, "message" to "Account with this service user ID $serviceUserId already exists for source type ${userDto.sourceType}.", "user" to userMapper.fromEntity(existingExternalUser)))
.build()

throw WebApplicationException(response)
}
}

val existingUser = userRepository.findByUserIdProjectIdSourceType(
userId = userDto.userId!!,
projectId = userDto.projectId!!,
Expand All @@ -52,6 +68,7 @@ class RestSourceUserService(

throw WebApplicationException(response)
}

val user = userRepository.create(userDto)
return userMapper.fromEntity(user)
}
Expand All @@ -69,6 +86,22 @@ class RestSourceUserService(

suspend fun update(userId: Long, user: RestSourceUserDTO): RestSourceUserDTO {
user.ensure()

// Check if the service user ID is already in use for the same source type but different user.
user.serviceUserId?.let { serviceUserId ->
val existingExternalUser = userRepository.findByExternalId(
externalId = serviceUserId,
sourceType = user.sourceType,
)
if (existingExternalUser != null && existingExternalUser.id != userId) {
val response = Response.status(Response.Status.CONFLICT)
.entity(mapOf("status" to 409, "message" to "Account with this service user ID $serviceUserId already exists for source type ${user.sourceType}.", "user" to userMapper.fromEntity(existingExternalUser)))
.build()

throw WebApplicationException(response)
}
}

return userMapper.fromEntity(
runLocked(userId) {
userRepository.update(userId, user)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.10.xsd">

<changeSet author="yatharth" id="20240607120000-add-unique-constraint-external-user-id">
<!-- Update duplicates to a fixed value for investigation, appending the external_user_id, except the row with the lowest id -->
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">
SELECT COUNT(*) FROM (
SELECT external_user_id FROM rest_source_user
WHERE external_user_id IS NOT NULL
GROUP BY external_user_id
HAVING COUNT(*) > 1
) t;
</sqlCheck>
</preConditions>
<sql dbms="postgresql">
UPDATE rest_source_user a
SET external_user_id = 'DUPLICATE_INVESTIGATE_' || a.external_user_id
FROM rest_source_user b
WHERE a.external_user_id = b.external_user_id
AND a.id > b.id
AND a.external_user_id IS NOT NULL
AND b.id = (
SELECT MIN(id) FROM rest_source_user c
WHERE c.external_user_id = a.external_user_id
);
</sql>
<addUniqueConstraint
tableName="rest_source_user"
columnNames="external_user_id"
constraintName="uk_rest_source_user_external_user_id"/>
</changeSet>
</databaseChangeLog>
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
<include file="db/changelog/changes/00000000000003_add_created_at_column.xml"/>
<include file="db/changelog/changes/20210721100000_add_registration_table.xml"/>
<include file="db/changelog/changes/20211008113000_add_registration_created_at.xml"/>
<include file="db/changelog/changes/20240607120000_add_unique_constraint_external_user_id.xml"/>
</databaseChangeLog>
Loading