From b623ce4136dee67a4a14c69d4834c965e84c29d3 Mon Sep 17 00:00:00 2001 From: ally010314 Date: Fri, 6 Feb 2026 12:07:25 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat/=EB=B2=84=EB=B8=94=20=EA=B3=84?= =?UTF-8?q?=EC=A0=95=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/datasources/BubbleLocalDataSource.kt | 3 +- .../data/repository/BubbleRepositoryImpl.kt | 16 ++- .../data/repository/UserRepositoryImpl.kt | 15 ++- .../com/umc/edison/data/token/TokenManager.kt | 20 +++ .../domain/repository/BubbleRepository.kt | 1 + .../datasources/BubbleLocalDataSourceImpl.kt | 125 +++++++++++------- .../com/umc/edison/local/model/BubbleLocal.kt | 1 + .../umc/edison/local/room/dao/BubbleDao.kt | 84 ++++++++---- 8 files changed, 187 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/com/umc/edison/data/datasources/BubbleLocalDataSource.kt b/app/src/main/java/com/umc/edison/data/datasources/BubbleLocalDataSource.kt index be229578f..459780d86 100644 --- a/app/src/main/java/com/umc/edison/data/datasources/BubbleLocalDataSource.kt +++ b/app/src/main/java/com/umc/edison/data/datasources/BubbleLocalDataSource.kt @@ -5,7 +5,7 @@ import com.umc.edison.data.model.bubble.BubbleEntity interface BubbleLocalDataSource { // CREATE suspend fun addBubbles(bubbles: List) - suspend fun addBubble(bubble: BubbleEntity) : BubbleEntity + suspend fun addBubble(bubble: BubbleEntity, userId: String? = null) : BubbleEntity // READ suspend fun getAllActiveBubbles(): List @@ -24,6 +24,7 @@ interface BubbleLocalDataSource { suspend fun trashBubbles(bubbles: List) suspend fun markAsSynced(bubble: BubbleEntity) suspend fun syncBubbles(bubbles: List) + suspend fun linkGuestBubblesToUser(userId: String) // DELETE suspend fun deleteBubbles(bubbles: List) diff --git a/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt b/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt index 615de050b..c637b221e 100644 --- a/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt +++ b/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt @@ -7,6 +7,7 @@ import com.umc.edison.data.datasources.BubbleRemoteDataSource import com.umc.edison.data.model.bubble.ClusteredBubbleEntity import com.umc.edison.data.model.bubble.KeywordBubbleEntity import com.umc.edison.data.model.bubble.toData +import com.umc.edison.data.token.TokenManager import com.umc.edison.domain.DataResource import com.umc.edison.domain.model.bubble.Bubble import com.umc.edison.domain.model.bubble.ClusteredBubble @@ -19,7 +20,8 @@ import javax.inject.Inject class BubbleRepositoryImpl @Inject constructor( private val bubbleLocalDataSource: BubbleLocalDataSource, private val bubbleRemoteDataSource: BubbleRemoteDataSource, - private val resourceFactory: FlowBoundResourceFactory + private val resourceFactory: FlowBoundResourceFactory, + private val tokenManager: TokenManager ) : BubbleRepository { // CREATE override fun addBubbles(bubbles: List): Flow> = @@ -41,7 +43,10 @@ class BubbleRepositoryImpl @Inject constructor( override fun addBubble(bubble: Bubble): Flow> = resourceFactory.sync( - localAction = { bubbleLocalDataSource.addBubble(bubble.toData()) }, + localAction = { + val currentUserId = tokenManager.getUserId() + bubbleLocalDataSource.addBubble(bubble.toData()) + }, remoteSync = { val newBubble = bubbleLocalDataSource.getActiveBubble(bubble.id) bubbleRemoteDataSource.syncBubble(newBubble) @@ -193,6 +198,10 @@ class BubbleRepositoryImpl @Inject constructor( } ) + override suspend fun linkGuestBubblesToUser(userId: String) { + bubbleLocalDataSource.linkGuestBubblesToUser(userId) + } + // DELETE override fun deleteBubbles(bubbles: List): Flow> = resourceFactory.sync( @@ -212,7 +221,8 @@ class BubbleRepositoryImpl @Inject constructor( } }, onRemoteSuccess = { deletedBubbles -> - val localBubbles = deletedBubbles.map { remote -> bubbleLocalDataSource.getRawBubble(remote.id) } + val localBubbles = + deletedBubbles.map { remote -> bubbleLocalDataSource.getRawBubble(remote.id) } bubbleLocalDataSource.deleteBubbles(localBubbles) } ) diff --git a/app/src/main/java/com/umc/edison/data/repository/UserRepositoryImpl.kt b/app/src/main/java/com/umc/edison/data/repository/UserRepositoryImpl.kt index b988be850..3950b7cf5 100644 --- a/app/src/main/java/com/umc/edison/data/repository/UserRepositoryImpl.kt +++ b/app/src/main/java/com/umc/edison/data/repository/UserRepositoryImpl.kt @@ -9,6 +9,7 @@ import com.umc.edison.data.token.TokenManager import com.umc.edison.domain.DataResource import com.umc.edison.domain.model.identity.Identity import com.umc.edison.domain.model.user.User +import com.umc.edison.domain.repository.BubbleRepository import com.umc.edison.domain.repository.UserRepository import kotlinx.coroutines.flow.Flow import javax.inject.Inject @@ -17,12 +18,16 @@ class UserRepositoryImpl @Inject constructor( private val userRemoteDataSource: UserRemoteDataSource, private val resourceFactory: FlowBoundResourceFactory, private val tokenManager: TokenManager, + private val bubbleRepository: BubbleRepository ) : UserRepository { - // CREATE + override fun googleLogin(idToken: String): Flow> = resourceFactory.remote( dataAction = { val userWithToken: UserWithTokenEntity = userRemoteDataSource.googleLogin(idToken) + val userEmail = userWithToken.user.email tokenManager.setToken(userWithToken.accessToken, userWithToken.refreshToken) + tokenManager.saveUserId(userEmail) + bubbleRepository.linkGuestBubblesToUser(userEmail) userWithToken } ) @@ -39,17 +44,19 @@ class UserRepositoryImpl @Inject constructor( nickname = nickname, identity = identity.map { it.toData() } ) + val userEmail = userWithToken.user.email tokenManager.setToken(userWithToken.accessToken, userWithToken.refreshToken) + tokenManager.saveUserId(userEmail) + bubbleRepository.linkGuestBubblesToUser(userEmail) + userWithToken } ) - - // READ override fun getLogInState(): Flow> = resourceFactory.local( dataAction = { - tokenManager.loadAccessToken()?.isNotEmpty() + tokenManager.loadAccessToken()?.isNotEmpty() == true } ) diff --git a/app/src/main/java/com/umc/edison/data/token/TokenManager.kt b/app/src/main/java/com/umc/edison/data/token/TokenManager.kt index 7c8987ca6..97a4ee635 100644 --- a/app/src/main/java/com/umc/edison/data/token/TokenManager.kt +++ b/app/src/main/java/com/umc/edison/data/token/TokenManager.kt @@ -17,11 +17,13 @@ class TokenManager @Inject constructor( applicationScope.launch { loadAccessToken() loadRefreshToken() + loadUserId() } } private var cachedAccessToken: String? = null private var cachedRefreshToken: String? = null + private var cachedUserId: String? = null override fun getAccessToken(): String? { if (cachedAccessToken == null) { @@ -37,9 +39,12 @@ class TokenManager @Inject constructor( return cachedRefreshToken } + fun getUserId(): String? = cachedUserId + override fun clearCachedTokens() { cachedAccessToken = null cachedRefreshToken = null + cachedUserId = null } override fun setCachedTokens(accessToken: String, refreshToken: String?) { @@ -61,6 +66,17 @@ class TokenManager @Inject constructor( return token } + suspend fun loadUserId(): String? { + val id = prefDataSource.get(USER_ID_KEY, "") + cachedUserId = id.ifEmpty { null } + return cachedUserId + } + + suspend fun saveUserId(userId: String) { + cachedUserId = userId + prefDataSource.set(USER_ID_KEY, userId) + } + suspend fun setToken(accessToken: String, refreshToken: String? = null) { cachedAccessToken = accessToken prefDataSource.set(ACCESS_TOKEN_KEY, accessToken) @@ -73,12 +89,16 @@ class TokenManager @Inject constructor( suspend fun deleteToken() { cachedAccessToken = null cachedRefreshToken = null + cachedUserId = null + prefDataSource.remove(ACCESS_TOKEN_KEY) prefDataSource.remove(REFRESH_TOKEN_KEY) + prefDataSource.remove(USER_ID_KEY) } companion object { private const val ACCESS_TOKEN_KEY = "access_token" private const val REFRESH_TOKEN_KEY = "refresh_token" + private const val USER_ID_KEY = "user_id" } } diff --git a/app/src/main/java/com/umc/edison/domain/repository/BubbleRepository.kt b/app/src/main/java/com/umc/edison/domain/repository/BubbleRepository.kt index 0efd09170..cd058f2c6 100644 --- a/app/src/main/java/com/umc/edison/domain/repository/BubbleRepository.kt +++ b/app/src/main/java/com/umc/edison/domain/repository/BubbleRepository.kt @@ -26,6 +26,7 @@ interface BubbleRepository { fun recoverBubbles(bubbles: List): Flow> fun updateBubbles(bubbles: List): Flow> fun updateBubble(bubble: Bubble): Flow> + suspend fun linkGuestBubblesToUser(userId: String) // DELETE fun deleteBubbles(bubbles: List): Flow> diff --git a/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt b/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt index c808ac237..547d33790 100644 --- a/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt +++ b/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt @@ -3,6 +3,7 @@ package com.umc.edison.local.datasources import android.icu.util.Calendar import com.umc.edison.data.datasources.BubbleLocalDataSource import com.umc.edison.data.model.bubble.BubbleEntity +import com.umc.edison.data.token.TokenManager import com.umc.edison.local.model.BubbleLocal import com.umc.edison.local.model.toLocal import com.umc.edison.local.room.RoomConstant @@ -17,53 +18,75 @@ class BubbleLocalDataSourceImpl @Inject constructor( private val bubbleDao: BubbleDao, private val labelDao: LabelDao, private val bubbleLabelDao: BubbleLabelDao, - private val linkedBubbleDao: LinkedBubbleDao + private val linkedBubbleDao: LinkedBubbleDao, + private val tokenManager: TokenManager ) : BubbleLocalDataSource, BaseLocalDataSourceImpl(bubbleDao) { private val tableName = RoomConstant.getTableNameByClass(BubbleLocal::class.java) - // CREATE + override suspend fun linkGuestBubblesToUser(userId: String) { + bubbleDao.linkGuestBubblesToUser(userId) + } + + // --- CREATE --- override suspend fun addBubbles(bubbles: List) { bubbles.forEach { bubble -> - addBubble(bubble) + addBubble(bubble, null) } } - override suspend fun addBubble(bubble: BubbleEntity): BubbleEntity { - val id = insert(bubble.toLocal()) - val insertedBubble = bubble.copy(id = id) + override suspend fun addBubble(bubble: BubbleEntity, userId: String?): BubbleEntity { + val targetUserId = userId ?: tokenManager.getUserId() + val localBubble = BubbleLocal( + uuid = bubble.id, + userId = targetUserId, + title = bubble.title, + content = bubble.content, + mainImage = bubble.mainImage, + isSynced = bubble.isSynced, + isTrashed = bubble.isTrashed, + isDeleted = bubble.isDeleted, + createdAt = bubble.createdAt, + updatedAt = bubble.updatedAt, + deletedAt = bubble.deletedAt + ) + val id = insert(localBubble) + + val insertedBubble = bubble.copy(id = id) addBubbleLabel(insertedBubble) addLinkedBubble(insertedBubble) - return getActiveBubble(insertedBubble.id) } - // READ + // --- READ --- override suspend fun getAllActiveBubbles(): List { - val localBubbles: List = bubbleDao.getAllActiveBubbles() - + val userId = tokenManager.getUserId() + val localBubbles: List = bubbleDao.getAllActiveBubbles(userId) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getAllRecentBubbles(dayBefore: Int): List { + val userId = tokenManager.getUserId() val timestampLimit = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -dayBefore) }.time.time - val localBubbles: List = bubbleDao.getAllRecentBubbles(timestampLimit) + val localBubbles: List = bubbleDao.getAllRecentBubbles(timestampLimit, userId) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getAllTrashedBubbles(): List { - val deletedBubbles: List = bubbleDao.getAllTrashedBubbles() + val userId = tokenManager.getUserId() + val deletedBubbles: List = bubbleDao.getAllTrashedBubbles(userId) return convertLocalBubblesToBubbleEntities(deletedBubbles) } override suspend fun getActiveBubble(id: String): BubbleEntity { - val bubble = bubbleDao.getActiveBubbleById(id)?.toData() - ?: throw IllegalArgumentException("Bubble with id $id not found") + val userId = tokenManager.getUserId() + val bubble = bubbleDao.getActiveBubbleById(id, userId)?.toData() + ?: throw IllegalArgumentException("Bubble with id $id not found for current user") val result = bubble.copy( labels = labelDao.getAllActiveLabelsByBubbleId(id).map { it.toData() }, @@ -75,7 +98,8 @@ class BubbleLocalDataSourceImpl @Inject constructor( } override suspend fun getRawBubble(id: String): BubbleEntity { - val bubble = bubbleDao.getRawBubbleById(id)?.toData() + val userId = tokenManager.getUserId() + val bubble = bubbleDao.getRawBubbleById(id, userId)?.toData() ?: throw IllegalArgumentException("Bubble with id $id not found") val result = bubble.copy( @@ -88,27 +112,29 @@ class BubbleLocalDataSourceImpl @Inject constructor( } override suspend fun getBubblesByLabelId(labelId: String): List { - val localBubbles: List = bubbleDao.getBubblesByLabelId(labelId) + val userId = tokenManager.getUserId() + val localBubbles: List = bubbleDao.getBubblesByLabelId(labelId, userId) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getBubblesWithoutLabel(): List { - val localBubbles: List = bubbleDao.getBubblesWithoutLabel() + val userId = tokenManager.getUserId() + val localBubbles: List = bubbleDao.getBubblesWithoutLabel(userId) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getSearchBubbleResults(query: String): List { - val localBubbles: List = bubbleDao.getSearchBubbles(query) + val userId = tokenManager.getUserId() + val localBubbles: List = bubbleDao.getSearchBubbles(query, userId) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getUnSyncedBubbles(): List { val localBubbles: List = getAllUnSyncedRows(tableName) - return convertLocalBubblesToBubbleEntities(localBubbles) } - // UPDATE + // --- UPDATE --- override suspend fun updateBubbles(bubbles: List) { bubbles.forEach { bubble -> updateBubble(bubble) @@ -125,6 +151,10 @@ class BubbleLocalDataSourceImpl @Inject constructor( addBubbleLabel(bubble) addLinkedBubble(bubble) + if (isSynced) { + markAsSynced(bubble) + } + return getActiveBubble(bubble.id) } @@ -136,8 +166,7 @@ class BubbleLocalDataSourceImpl @Inject constructor( deletedAt = Date() ) } - - trashedBubbles.map { + trashedBubbles.forEach { update(it.toLocal(), tableName) } } @@ -148,7 +177,7 @@ class BubbleLocalDataSourceImpl @Inject constructor( override suspend fun syncBubbles(bubbles: List) { if (bubbles.isEmpty()) return - + // 배치로 처리하기 위해 모든 관련 버블 ID 수집 val allBubbleIds = mutableSetOf() bubbles.forEach { bubble -> @@ -156,20 +185,21 @@ class BubbleLocalDataSourceImpl @Inject constructor( bubble.backLinks.forEach { allBubbleIds.add(it.id) } bubble.linkedBubble?.let { allBubbleIds.add(it.id) } } - + // 기존 버블들을 배치로 조회 + val userId = tokenManager.getUserId() val existingBubbles = convertLocalBubblesToBubbleEntities( - bubbleDao.getActiveBubblesByIds(allBubbleIds.toList()) + bubbleDao.getActiveBubblesByIds(allBubbleIds.toList(), userId) ).associateBy { it.id } - + // 각 버블 동기화 bubbles.forEach { bubble -> syncBubbleWithExistingData(bubble, existingBubbles) } } - + private suspend fun syncBubbleWithExistingData( - bubble: BubbleEntity, + bubble: BubbleEntity, existingBubbles: Map ) { // backLinks 처리 @@ -179,7 +209,7 @@ class BubbleLocalDataSourceImpl @Inject constructor( if (existingBackLink.same(backLink) && existingBackLink.updatedAt > backLink.updatedAt) continue updateBubble(backLink, true) } else { - addBubble(backLink) + addBubble(backLink, null) } markAsSynced(backLink) } @@ -189,10 +219,10 @@ class BubbleLocalDataSourceImpl @Inject constructor( val existingLinkedBubble = existingBubbles[linkedBubble.id] if (existingLinkedBubble != null) { if (!existingLinkedBubble.same(linkedBubble)) { - updateBubble(linkedBubble) + updateBubble(linkedBubble, true) } } else { - addBubble(linkedBubble) + addBubble(linkedBubble, null) } markAsSynced(linkedBubble) } @@ -201,15 +231,15 @@ class BubbleLocalDataSourceImpl @Inject constructor( val existingBubble = existingBubbles[bubble.id] if (existingBubble != null) { if (!existingBubble.same(bubble)) { - updateBubble(bubble) + updateBubble(bubble, true) } } else { - addBubble(bubble) + addBubble(bubble, null) } markAsSynced(bubble) } - // DELETE + // --- DELETE --- override suspend fun deleteBubbles(bubbles: List) { bubbleDao.deleteBubbles(bubbles.map { it.id }) } @@ -217,21 +247,21 @@ class BubbleLocalDataSourceImpl @Inject constructor( // Helper function private suspend fun addBubbleLabel(bubble: BubbleEntity) { if (bubble.labels.isEmpty()) return - + val labelIds = bubble.labels.map { it.id } val existingLabels = labelDao.getLabelsByIds(labelIds) val existingLabelIds = existingLabels.map { it.uuid }.toSet() - + // 존재하지 않는 라벨들을 배치로 삽입 val newLabels = bubble.labels.filter { it.id !in existingLabelIds } newLabels.forEach { label -> labelDao.insert(label.toLocal()) } - + // 버블-라벨 관계 확인 및 삽입 val existingRelations = bubbleLabelDao.getBubbleLabelsByIds(listOf(bubble.id), labelIds) val existingRelationPairs = existingRelations.map { "${it.bubbleId}-${it.labelId}" }.toSet() - + bubble.labels.forEach { label -> val relationKey = "${bubble.id}-${label.id}" if (relationKey !in existingRelationPairs) { @@ -247,12 +277,13 @@ class BubbleLocalDataSourceImpl @Inject constructor( if (id == null) linkedBubbleDao.insert(bubble.id, linkedBubble.id, false) } - // BackLinks 배치 처리 + // 버블-라벨 관계 확인 및 삽입 if (bubble.backLinks.isNotEmpty()) { val backLinkIds = bubble.backLinks.map { it.id } - val existingBubbles = bubbleDao.getActiveBubblesByIds(backLinkIds) + val userId = tokenManager.getUserId() + val existingBubbles = bubbleDao.getActiveBubblesByIds(backLinkIds, userId) val existingBubbleIds = existingBubbles.map { it.uuid }.toSet() - + bubble.backLinks.forEach { backLink -> if (backLink.id in existingBubbleIds) { val id = linkedBubbleDao.getLinkedBubbleId(bubble.id, backLink.id, true) @@ -264,24 +295,24 @@ class BubbleLocalDataSourceImpl @Inject constructor( private suspend fun convertLocalBubblesToBubbleEntities(localBubbles: List): List { if (localBubbles.isEmpty()) return emptyList() - + val bubbleIds = localBubbles.map { it.uuid } - + // 배치로 모든 관련 데이터를 한 번에 조회 val labelsWithBubbleId = labelDao.getAllActiveLabelsByBubbleIds(bubbleIds) val linkedBubblesWithParentId = linkedBubbleDao.getActiveLinkedBubblesByBubbleIds(bubbleIds) val backLinksWithParentId = linkedBubbleDao.getActiveBackLinksByBubbleIds(bubbleIds) - + // 버블 ID별로 그룹화 val labelsByBubbleId = labelsWithBubbleId.groupBy { it.bubbleId } val linkedBubblesByBubbleId = linkedBubblesWithParentId.groupBy { it.parentBubbleId } val backLinksByBubbleId = backLinksWithParentId.groupBy { it.parentBubbleId } - + // 각 버블에 대해 관련 데이터를 조합하여 BubbleEntity 생성 return localBubbles.map { localBubble -> val bubbleId = localBubble.uuid val baseEntity = localBubble.toData() - + baseEntity.copy( labels = labelsByBubbleId[bubbleId]?.map { it.toLabelEntity() } ?: emptyList(), linkedBubble = linkedBubblesByBubbleId[bubbleId]?.firstOrNull()?.toBubbleEntity(), @@ -289,4 +320,4 @@ class BubbleLocalDataSourceImpl @Inject constructor( ) } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/umc/edison/local/model/BubbleLocal.kt b/app/src/main/java/com/umc/edison/local/model/BubbleLocal.kt index 74eba36ba..a25a45757 100644 --- a/app/src/main/java/com/umc/edison/local/model/BubbleLocal.kt +++ b/app/src/main/java/com/umc/edison/local/model/BubbleLocal.kt @@ -11,6 +11,7 @@ import java.util.UUID data class BubbleLocal( @PrimaryKey @ColumnInfo(name = "id") override val uuid: String = UUID.randomUUID().toString(), + @ColumnInfo(name = "user_id") val userId: String? = null, val title: String?, val content: String?, @ColumnInfo(name = "main_image") val mainImage: String?, diff --git a/app/src/main/java/com/umc/edison/local/room/dao/BubbleDao.kt b/app/src/main/java/com/umc/edison/local/room/dao/BubbleDao.kt index 5fcccb8c7..2b66517ac 100644 --- a/app/src/main/java/com/umc/edison/local/room/dao/BubbleDao.kt +++ b/app/src/main/java/com/umc/edison/local/room/dao/BubbleDao.kt @@ -7,27 +7,57 @@ import com.umc.edison.local.room.RoomConstant @Dao interface BubbleDao : BaseSyncDao { - // READ - @Query("SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE is_deleted = 0 AND is_trashed = 0") - suspend fun getAllActiveBubbles(): List - @Query("SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE is_deleted = 0 AND is_trashed = 0 AND created_at >= :dayBefore") - suspend fun getAllRecentBubbles(dayBefore: Long): List + // user_id가 NULL인 버블들을 현재 로그인한 user_id로 일괄 업데이트 + @Query("UPDATE ${RoomConstant.Table.BUBBLE} SET user_id = :newUserId WHERE user_id IS NULL") + suspend fun linkGuestBubblesToUser(newUserId: String) - @Query("SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE is_trashed = 1 AND is_deleted = 0") - suspend fun getAllTrashedBubbles(): List + // 현재 로그인한 사용자의 버블만 조회 + @Query(""" + SELECT * FROM ${RoomConstant.Table.BUBBLE} + WHERE is_deleted = 0 AND is_trashed = 0 + AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + """) + suspend fun getAllActiveBubbles(userId: String?): List - @Query("SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id = :bubbleId AND is_deleted = 0 AND is_trashed = 0") - suspend fun getActiveBubbleById(bubbleId: String): BubbleLocal? + @Query(""" + SELECT * FROM ${RoomConstant.Table.BUBBLE} + WHERE is_deleted = 0 AND is_trashed = 0 + AND created_at >= :dayBefore + AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + """) + suspend fun getAllRecentBubbles(dayBefore: Long, userId: String?): List - @Query("SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id = :bubbleId") - suspend fun getRawBubbleById(bubbleId: String): BubbleLocal? + @Query(""" + SELECT * FROM ${RoomConstant.Table.BUBBLE} + WHERE is_trashed = 1 AND is_deleted = 0 + AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + """) + suspend fun getAllTrashedBubbles(userId: String?): List - @Query("SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id IN (SELECT bubble_id FROM ${RoomConstant.Table.BUBBLE_LABEL} WHERE label_id = :labelId) AND is_deleted = 0 AND is_trashed = 0") - suspend fun getBubblesByLabelId(labelId: String): List + @Query(""" + SELECT * FROM ${RoomConstant.Table.BUBBLE} + WHERE id = :bubbleId AND is_deleted = 0 AND is_trashed = 0 + AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + """) + suspend fun getActiveBubbleById(bubbleId: String, userId: String?): BubbleLocal? - @Query( - """ + @Query(""" + SELECT * FROM ${RoomConstant.Table.BUBBLE} + WHERE id = :bubbleId + AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + """) + suspend fun getRawBubbleById(bubbleId: String, userId: String?): BubbleLocal? + + @Query(""" + SELECT * FROM ${RoomConstant.Table.BUBBLE} + WHERE id IN (SELECT bubble_id FROM ${RoomConstant.Table.BUBBLE_LABEL} WHERE label_id = :labelId) + AND is_deleted = 0 AND is_trashed = 0 + AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + """) + suspend fun getBubblesByLabelId(labelId: String, userId: String?): List + + @Query(""" SELECT DISTINCT b.* FROM ${RoomConstant.Table.BUBBLE} b LEFT JOIN ${RoomConstant.Table.BUBBLE_LABEL} bl ON b.id = bl.bubble_id LEFT JOIN ${RoomConstant.Table.LABEL} l ON bl.label_id = l.id @@ -37,17 +67,25 @@ interface BubbleDao : BaseSyncDao { OR l.name LIKE '%' || :query || '%') AND b.is_deleted = 0 AND b.is_trashed = 0 - """ - ) - suspend fun getSearchBubbles(query: String): List + AND ((:userId IS NULL AND b.user_id IS NULL) OR (b.user_id = :userId)) + """) + suspend fun getSearchBubbles(query: String, userId: String?): List - @Query("SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id NOT IN (SELECT bubble_id FROM ${RoomConstant.Table.BUBBLE_LABEL}) AND is_deleted = 0 AND is_trashed = 0") - suspend fun getBubblesWithoutLabel(): List + @Query(""" + SELECT * FROM ${RoomConstant.Table.BUBBLE} + WHERE id NOT IN (SELECT bubble_id FROM ${RoomConstant.Table.BUBBLE_LABEL}) + AND is_deleted = 0 AND is_trashed = 0 + AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + """) + suspend fun getBubblesWithoutLabel(userId: String?): List - @Query("SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id IN (:bubbleIds) AND is_deleted = 0 AND is_trashed = 0") - suspend fun getActiveBubblesByIds(bubbleIds: List): List + @Query(""" + SELECT * FROM ${RoomConstant.Table.BUBBLE} + WHERE id IN (:bubbleIds) AND is_deleted = 0 AND is_trashed = 0 + AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + """) + suspend fun getActiveBubblesByIds(bubbleIds: List, userId: String?): List - // DELETE @Query("DELETE FROM ${RoomConstant.Table.BUBBLE} WHERE id IN (:ids)") suspend fun deleteBubbles(ids: List) From 83939f4586cc0b65639bc50ff96b948bdaf3b174 Mon Sep 17 00:00:00 2001 From: ally010314 Date: Fri, 6 Feb 2026 12:57:14 +0900 Subject: [PATCH 2/6] =?UTF-8?q?fix/=20=EC=A0=9C=EB=AF=B8=EB=82=98=EC=9D=B4?= =?UTF-8?q?=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edison/data/repository/BubbleRepositoryImpl.kt | 1 - .../java/com/umc/edison/data/token/TokenManager.kt | 14 ++++++++++---- .../local/datasources/BaseLocalDataSourceImpl.kt | 10 ++++++++-- .../local/datasources/BubbleLocalDataSourceImpl.kt | 6 +++--- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt b/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt index c637b221e..aee32e485 100644 --- a/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt +++ b/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt @@ -44,7 +44,6 @@ class BubbleRepositoryImpl @Inject constructor( override fun addBubble(bubble: Bubble): Flow> = resourceFactory.sync( localAction = { - val currentUserId = tokenManager.getUserId() bubbleLocalDataSource.addBubble(bubble.toData()) }, remoteSync = { diff --git a/app/src/main/java/com/umc/edison/data/token/TokenManager.kt b/app/src/main/java/com/umc/edison/data/token/TokenManager.kt index 97a4ee635..40086550b 100644 --- a/app/src/main/java/com/umc/edison/data/token/TokenManager.kt +++ b/app/src/main/java/com/umc/edison/data/token/TokenManager.kt @@ -39,7 +39,12 @@ class TokenManager @Inject constructor( return cachedRefreshToken } - fun getUserId(): String? = cachedUserId + suspend fun getUserId(): String? { + if (cachedUserId != null) { + return cachedUserId + } + return loadUserId() + } override fun clearCachedTokens() { cachedAccessToken = null @@ -59,6 +64,8 @@ class TokenManager @Inject constructor( return token } + + suspend fun loadRefreshToken(): String? { val token = prefDataSource.get(REFRESH_TOKEN_KEY, "") cachedRefreshToken = token.ifEmpty { null } @@ -87,15 +94,14 @@ class TokenManager @Inject constructor( } suspend fun deleteToken() { - cachedAccessToken = null - cachedRefreshToken = null - cachedUserId = null + clearCachedTokens() prefDataSource.remove(ACCESS_TOKEN_KEY) prefDataSource.remove(REFRESH_TOKEN_KEY) prefDataSource.remove(USER_ID_KEY) } + companion object { private const val ACCESS_TOKEN_KEY = "access_token" private const val REFRESH_TOKEN_KEY = "refresh_token" diff --git a/app/src/main/java/com/umc/edison/local/datasources/BaseLocalDataSourceImpl.kt b/app/src/main/java/com/umc/edison/local/datasources/BaseLocalDataSourceImpl.kt index 1dff639a9..6d425f2d3 100644 --- a/app/src/main/java/com/umc/edison/local/datasources/BaseLocalDataSourceImpl.kt +++ b/app/src/main/java/com/umc/edison/local/datasources/BaseLocalDataSourceImpl.kt @@ -25,7 +25,10 @@ open class BaseLocalDataSourceImpl( // UPDATE suspend fun update(entity: T, tableName: String, isSynced: Boolean = false) { - val query = SimpleSQLiteQuery("SELECT * FROM $tableName WHERE id = '${entity.uuid}'") + val query = SimpleSQLiteQuery( + "SELECT * FROM $tableName WHERE id = ?", + arrayOf(entity.uuid) + ) baseDao.getById(query)?.let { entity.createdAt = it.createdAt entity.updatedAt = Date() @@ -36,7 +39,10 @@ open class BaseLocalDataSourceImpl( suspend fun markAsSynced(tableName: String, id: String) { val date = Date() - val query = SimpleSQLiteQuery("UPDATE $tableName SET is_synced = 1, updated_at = '$date' WHERE id = '$id'") + val query = SimpleSQLiteQuery( + "UPDATE $tableName SET is_synced = 1, updated_at = ? WHERE id = ?", + arrayOf(date.time, id) + ) baseDao.markAsSynced(query) } } \ No newline at end of file diff --git a/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt b/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt index 547d33790..3f1cd22a8 100644 --- a/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt +++ b/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt @@ -30,8 +30,9 @@ class BubbleLocalDataSourceImpl @Inject constructor( // --- CREATE --- override suspend fun addBubbles(bubbles: List) { + val userId = tokenManager.getUserId() bubbles.forEach { bubble -> - addBubble(bubble, null) + addBubble(bubble, userId) } } @@ -55,7 +56,6 @@ class BubbleLocalDataSourceImpl @Inject constructor( val insertedBubble = bubble.copy(id = id) addBubbleLabel(insertedBubble) - addLinkedBubble(insertedBubble) return getActiveBubble(insertedBubble.id) } @@ -277,7 +277,7 @@ class BubbleLocalDataSourceImpl @Inject constructor( if (id == null) linkedBubbleDao.insert(bubble.id, linkedBubble.id, false) } - // 버블-라벨 관계 확인 및 삽입 + // BackLinks 처리 if (bubble.backLinks.isNotEmpty()) { val backLinkIds = bubble.backLinks.map { it.id } val userId = tokenManager.getUserId() From 6e13da4d281bbace9ead99b35d6767bd3d0a08a2 Mon Sep 17 00:00:00 2001 From: ally010314 Date: Thu, 26 Feb 2026 20:10:51 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/UserRepositoryImpl.kt | 21 ++---- .../com/umc/edison/data/token/TokenManager.kt | 31 +++++---- .../domain/usecase/user/GoogleLoginUseCase.kt | 14 +++- .../usecase/user/GoogleSignUpUseCase.kt | 12 +++- .../datasources/BubbleLocalDataSourceImpl.kt | 67 ++++++++----------- .../com/umc/edison/local/model/BubbleLocal.kt | 2 +- .../umc/edison/local/room/dao/BubbleDao.kt | 42 ++++++------ 7 files changed, 91 insertions(+), 98 deletions(-) diff --git a/app/src/main/java/com/umc/edison/data/repository/UserRepositoryImpl.kt b/app/src/main/java/com/umc/edison/data/repository/UserRepositoryImpl.kt index 3950b7cf5..7153f56da 100644 --- a/app/src/main/java/com/umc/edison/data/repository/UserRepositoryImpl.kt +++ b/app/src/main/java/com/umc/edison/data/repository/UserRepositoryImpl.kt @@ -18,16 +18,13 @@ class UserRepositoryImpl @Inject constructor( private val userRemoteDataSource: UserRemoteDataSource, private val resourceFactory: FlowBoundResourceFactory, private val tokenManager: TokenManager, - private val bubbleRepository: BubbleRepository ) : UserRepository { override fun googleLogin(idToken: String): Flow> = resourceFactory.remote( dataAction = { val userWithToken: UserWithTokenEntity = userRemoteDataSource.googleLogin(idToken) - val userEmail = userWithToken.user.email tokenManager.setToken(userWithToken.accessToken, userWithToken.refreshToken) - tokenManager.saveUserId(userEmail) - bubbleRepository.linkGuestBubblesToUser(userEmail) + tokenManager.saveUserEmail(userWithToken.user.email) userWithToken } ) @@ -38,17 +35,13 @@ class UserRepositoryImpl @Inject constructor( identity: List ): Flow> = resourceFactory.remote( dataAction = { - val userWithToken: UserWithTokenEntity = - userRemoteDataSource.googleSignup( - idToken = idToken, - nickname = nickname, - identity = identity.map { it.toData() } - ) - val userEmail = userWithToken.user.email + val userWithToken: UserWithTokenEntity = userRemoteDataSource.googleSignup( + idToken = idToken, + nickname = nickname, + identity = identity.map { it.toData() } + ) tokenManager.setToken(userWithToken.accessToken, userWithToken.refreshToken) - tokenManager.saveUserId(userEmail) - bubbleRepository.linkGuestBubblesToUser(userEmail) - + tokenManager.saveUserEmail(userWithToken.user.email) userWithToken } ) diff --git a/app/src/main/java/com/umc/edison/data/token/TokenManager.kt b/app/src/main/java/com/umc/edison/data/token/TokenManager.kt index 7e298133d..4c5a1bfba 100644 --- a/app/src/main/java/com/umc/edison/data/token/TokenManager.kt +++ b/app/src/main/java/com/umc/edison/data/token/TokenManager.kt @@ -20,24 +20,22 @@ class TokenManager @Inject constructor( init { applicationScope.launch { preloadTokens() - loadUserId() + loadUserEmail() } } private var cachedAccessToken: String? = null private var cachedRefreshToken: String? = null - private var cachedUserId: String? = null + private var cachedUserEmail: String? = null override fun getAccessToken(): String? = cachedAccessToken override fun getRefreshToken(): String? = cachedRefreshToken - suspend fun getUserId(): String? { - if (cachedUserId != null) { - return cachedUserId - } - return loadUserId() + suspend fun getUserEmail(): String? { + if (cachedUserEmail != null) return cachedUserEmail + return loadUserEmail() } override suspend fun clearCachedTokens() { @@ -70,15 +68,15 @@ class TokenManager @Inject constructor( } } - suspend fun loadUserId(): String? { - val id = prefDataSource.get(USER_ID_KEY, "") - cachedUserId = id.ifEmpty { null } - return cachedUserId + suspend fun loadUserEmail(): String? { + val email = prefDataSource.get(USER_EMAIL_KEY, "") + cachedUserEmail = email.ifEmpty { null } + return cachedUserEmail } - suspend fun saveUserId(userId: String) { - cachedUserId = userId - prefDataSource.set(USER_ID_KEY, userId) + suspend fun saveUserEmail(userEmail: String) { + cachedUserEmail = userEmail + prefDataSource.set(USER_EMAIL_KEY, userEmail) } suspend fun setToken(accessToken: String, refreshToken: String? = null) { @@ -96,9 +94,10 @@ class TokenManager @Inject constructor( mutex.withLock { cachedAccessToken = null cachedRefreshToken = null + cachedUserEmail = null prefDataSource.remove(ACCESS_TOKEN_KEY) prefDataSource.remove(REFRESH_TOKEN_KEY) - prefDataSource.remove(USER_ID_KEY) + prefDataSource.remove(USER_EMAIL_KEY) } } @@ -112,6 +111,6 @@ class TokenManager @Inject constructor( companion object { private const val ACCESS_TOKEN_KEY = "access_token" private const val REFRESH_TOKEN_KEY = "refresh_token" - private const val USER_ID_KEY = "user_id" + private const val USER_EMAIL_KEY = "user_email" } } diff --git a/app/src/main/java/com/umc/edison/domain/usecase/user/GoogleLoginUseCase.kt b/app/src/main/java/com/umc/edison/domain/usecase/user/GoogleLoginUseCase.kt index c690eb655..2942098ad 100644 --- a/app/src/main/java/com/umc/edison/domain/usecase/user/GoogleLoginUseCase.kt +++ b/app/src/main/java/com/umc/edison/domain/usecase/user/GoogleLoginUseCase.kt @@ -2,13 +2,21 @@ package com.umc.edison.domain.usecase.user import com.umc.edison.domain.DataResource import com.umc.edison.domain.model.user.User +import com.umc.edison.domain.repository.BubbleRepository import com.umc.edison.domain.repository.UserRepository import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.onEach import javax.inject.Inject class GoogleLoginUseCase @Inject constructor( - private val userRepository: UserRepository + private val userRepository: UserRepository, + private val bubbleRepository: BubbleRepository ) { operator fun invoke(idToken: String): Flow> = - userRepository.googleLogin(idToken) -} + userRepository.googleLogin(idToken).onEach { resource -> + if (resource is DataResource.Success) { + val userEmail = resource.data.email + bubbleRepository.linkGuestBubblesToUser(userEmail) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/umc/edison/domain/usecase/user/GoogleSignUpUseCase.kt b/app/src/main/java/com/umc/edison/domain/usecase/user/GoogleSignUpUseCase.kt index 98ccdc4c6..2b42e0ef3 100644 --- a/app/src/main/java/com/umc/edison/domain/usecase/user/GoogleSignUpUseCase.kt +++ b/app/src/main/java/com/umc/edison/domain/usecase/user/GoogleSignUpUseCase.kt @@ -3,17 +3,25 @@ package com.umc.edison.domain.usecase.user import com.umc.edison.domain.DataResource import com.umc.edison.domain.model.identity.Identity import com.umc.edison.domain.model.user.User +import com.umc.edison.domain.repository.BubbleRepository import com.umc.edison.domain.repository.UserRepository import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.onEach import javax.inject.Inject class GoogleSignUpUseCase @Inject constructor( - private val userRepository: UserRepository + private val userRepository: UserRepository, + private val bubbleRepository: BubbleRepository ) { operator fun invoke( idToken: String, nickname: String, identities: List ): Flow> = - userRepository.googleSignUp(idToken, nickname, identities) + userRepository.googleSignUp(idToken, nickname, identities).onEach { resource -> + if (resource is DataResource.Success) { + val userEmail = resource.data.email + bubbleRepository.linkGuestBubblesToUser(userEmail) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt b/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt index 3f1cd22a8..1b631c65e 100644 --- a/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt +++ b/app/src/main/java/com/umc/edison/local/datasources/BubbleLocalDataSourceImpl.kt @@ -24,23 +24,23 @@ class BubbleLocalDataSourceImpl @Inject constructor( private val tableName = RoomConstant.getTableNameByClass(BubbleLocal::class.java) - override suspend fun linkGuestBubblesToUser(userId: String) { - bubbleDao.linkGuestBubblesToUser(userId) + override suspend fun linkGuestBubblesToUser(userEmail: String) { + bubbleDao.linkGuestBubblesToUser(userEmail) } // --- CREATE --- override suspend fun addBubbles(bubbles: List) { - val userId = tokenManager.getUserId() + val userEmail = tokenManager.getUserEmail() bubbles.forEach { bubble -> - addBubble(bubble, userId) + addBubble(bubble, userEmail) } } - override suspend fun addBubble(bubble: BubbleEntity, userId: String?): BubbleEntity { - val targetUserId = userId ?: tokenManager.getUserId() + override suspend fun addBubble(bubble: BubbleEntity, userEmail: String?): BubbleEntity { + val targetUserEmail = userEmail ?: tokenManager.getUserEmail() val localBubble = BubbleLocal( uuid = bubble.id, - userId = targetUserId, + userEmail = targetUserEmail, title = bubble.title, content = bubble.content, mainImage = bubble.mainImage, @@ -61,31 +61,31 @@ class BubbleLocalDataSourceImpl @Inject constructor( // --- READ --- override suspend fun getAllActiveBubbles(): List { - val userId = tokenManager.getUserId() - val localBubbles: List = bubbleDao.getAllActiveBubbles(userId) + val userEmail = tokenManager.getUserEmail() + val localBubbles: List = bubbleDao.getAllActiveBubbles(userEmail) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getAllRecentBubbles(dayBefore: Int): List { - val userId = tokenManager.getUserId() + val userEmail = tokenManager.getUserEmail() val timestampLimit = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -dayBefore) }.time.time - val localBubbles: List = bubbleDao.getAllRecentBubbles(timestampLimit, userId) + val localBubbles: List = bubbleDao.getAllRecentBubbles(timestampLimit, userEmail) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getAllTrashedBubbles(): List { - val userId = tokenManager.getUserId() - val deletedBubbles: List = bubbleDao.getAllTrashedBubbles(userId) + val userEmail = tokenManager.getUserEmail() + val deletedBubbles: List = bubbleDao.getAllTrashedBubbles(userEmail) return convertLocalBubblesToBubbleEntities(deletedBubbles) } override suspend fun getActiveBubble(id: String): BubbleEntity { - val userId = tokenManager.getUserId() - val bubble = bubbleDao.getActiveBubbleById(id, userId)?.toData() + val userEmail = tokenManager.getUserEmail() + val bubble = bubbleDao.getActiveBubbleById(id, userEmail)?.toData() ?: throw IllegalArgumentException("Bubble with id $id not found for current user") val result = bubble.copy( @@ -98,8 +98,8 @@ class BubbleLocalDataSourceImpl @Inject constructor( } override suspend fun getRawBubble(id: String): BubbleEntity { - val userId = tokenManager.getUserId() - val bubble = bubbleDao.getRawBubbleById(id, userId)?.toData() + val userEmail = tokenManager.getUserEmail() + val bubble = bubbleDao.getRawBubbleById(id, userEmail)?.toData() ?: throw IllegalArgumentException("Bubble with id $id not found") val result = bubble.copy( @@ -112,20 +112,20 @@ class BubbleLocalDataSourceImpl @Inject constructor( } override suspend fun getBubblesByLabelId(labelId: String): List { - val userId = tokenManager.getUserId() - val localBubbles: List = bubbleDao.getBubblesByLabelId(labelId, userId) + val userEmail = tokenManager.getUserEmail() + val localBubbles: List = bubbleDao.getBubblesByLabelId(labelId, userEmail) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getBubblesWithoutLabel(): List { - val userId = tokenManager.getUserId() - val localBubbles: List = bubbleDao.getBubblesWithoutLabel(userId) + val userEmail = tokenManager.getUserEmail() + val localBubbles: List = bubbleDao.getBubblesWithoutLabel(userEmail) return convertLocalBubblesToBubbleEntities(localBubbles) } override suspend fun getSearchBubbleResults(query: String): List { - val userId = tokenManager.getUserId() - val localBubbles: List = bubbleDao.getSearchBubbles(query, userId) + val userEmail = tokenManager.getUserEmail() + val localBubbles: List = bubbleDao.getSearchBubbles(query, userEmail) return convertLocalBubblesToBubbleEntities(localBubbles) } @@ -178,7 +178,6 @@ class BubbleLocalDataSourceImpl @Inject constructor( override suspend fun syncBubbles(bubbles: List) { if (bubbles.isEmpty()) return - // 배치로 처리하기 위해 모든 관련 버블 ID 수집 val allBubbleIds = mutableSetOf() bubbles.forEach { bubble -> allBubbleIds.add(bubble.id) @@ -186,13 +185,11 @@ class BubbleLocalDataSourceImpl @Inject constructor( bubble.linkedBubble?.let { allBubbleIds.add(it.id) } } - // 기존 버블들을 배치로 조회 - val userId = tokenManager.getUserId() + val userEmail = tokenManager.getUserEmail() val existingBubbles = convertLocalBubblesToBubbleEntities( - bubbleDao.getActiveBubblesByIds(allBubbleIds.toList(), userId) + bubbleDao.getActiveBubblesByIds(allBubbleIds.toList(), userEmail) ).associateBy { it.id } - // 각 버블 동기화 bubbles.forEach { bubble -> syncBubbleWithExistingData(bubble, existingBubbles) } @@ -202,7 +199,6 @@ class BubbleLocalDataSourceImpl @Inject constructor( bubble: BubbleEntity, existingBubbles: Map ) { - // backLinks 처리 for(backLink in bubble.backLinks) { val existingBackLink = existingBubbles[backLink.id] if (existingBackLink != null) { @@ -214,7 +210,6 @@ class BubbleLocalDataSourceImpl @Inject constructor( markAsSynced(backLink) } - // linkedBubble 처리 bubble.linkedBubble?.let { linkedBubble -> val existingLinkedBubble = existingBubbles[linkedBubble.id] if (existingLinkedBubble != null) { @@ -227,7 +222,6 @@ class BubbleLocalDataSourceImpl @Inject constructor( markAsSynced(linkedBubble) } - // 현재 버블 처리 val existingBubble = existingBubbles[bubble.id] if (existingBubble != null) { if (!existingBubble.same(bubble)) { @@ -252,13 +246,11 @@ class BubbleLocalDataSourceImpl @Inject constructor( val existingLabels = labelDao.getLabelsByIds(labelIds) val existingLabelIds = existingLabels.map { it.uuid }.toSet() - // 존재하지 않는 라벨들을 배치로 삽입 val newLabels = bubble.labels.filter { it.id !in existingLabelIds } newLabels.forEach { label -> labelDao.insert(label.toLocal()) } - // 버블-라벨 관계 확인 및 삽입 val existingRelations = bubbleLabelDao.getBubbleLabelsByIds(listOf(bubble.id), labelIds) val existingRelationPairs = existingRelations.map { "${it.bubbleId}-${it.labelId}" }.toSet() @@ -271,17 +263,15 @@ class BubbleLocalDataSourceImpl @Inject constructor( } private suspend fun addLinkedBubble(bubble: BubbleEntity) { - // LinkedBubble 처리 bubble.linkedBubble?.let { linkedBubble -> val id = linkedBubbleDao.getLinkedBubbleId(bubble.id, linkedBubble.id, false) if (id == null) linkedBubbleDao.insert(bubble.id, linkedBubble.id, false) } - // BackLinks 처리 if (bubble.backLinks.isNotEmpty()) { val backLinkIds = bubble.backLinks.map { it.id } - val userId = tokenManager.getUserId() - val existingBubbles = bubbleDao.getActiveBubblesByIds(backLinkIds, userId) + val userEmail = tokenManager.getUserEmail() + val existingBubbles = bubbleDao.getActiveBubblesByIds(backLinkIds, userEmail) val existingBubbleIds = existingBubbles.map { it.uuid }.toSet() bubble.backLinks.forEach { backLink -> @@ -298,17 +288,14 @@ class BubbleLocalDataSourceImpl @Inject constructor( val bubbleIds = localBubbles.map { it.uuid } - // 배치로 모든 관련 데이터를 한 번에 조회 val labelsWithBubbleId = labelDao.getAllActiveLabelsByBubbleIds(bubbleIds) val linkedBubblesWithParentId = linkedBubbleDao.getActiveLinkedBubblesByBubbleIds(bubbleIds) val backLinksWithParentId = linkedBubbleDao.getActiveBackLinksByBubbleIds(bubbleIds) - // 버블 ID별로 그룹화 val labelsByBubbleId = labelsWithBubbleId.groupBy { it.bubbleId } val linkedBubblesByBubbleId = linkedBubblesWithParentId.groupBy { it.parentBubbleId } val backLinksByBubbleId = backLinksWithParentId.groupBy { it.parentBubbleId } - // 각 버블에 대해 관련 데이터를 조합하여 BubbleEntity 생성 return localBubbles.map { localBubble -> val bubbleId = localBubble.uuid val baseEntity = localBubble.toData() diff --git a/app/src/main/java/com/umc/edison/local/model/BubbleLocal.kt b/app/src/main/java/com/umc/edison/local/model/BubbleLocal.kt index a25a45757..67443c1d8 100644 --- a/app/src/main/java/com/umc/edison/local/model/BubbleLocal.kt +++ b/app/src/main/java/com/umc/edison/local/model/BubbleLocal.kt @@ -11,7 +11,7 @@ import java.util.UUID data class BubbleLocal( @PrimaryKey @ColumnInfo(name = "id") override val uuid: String = UUID.randomUUID().toString(), - @ColumnInfo(name = "user_id") val userId: String? = null, + @ColumnInfo(name = "user_email") val userEmail: String? = null, // 컬럼명 변경 val title: String?, val content: String?, @ColumnInfo(name = "main_image") val mainImage: String?, diff --git a/app/src/main/java/com/umc/edison/local/room/dao/BubbleDao.kt b/app/src/main/java/com/umc/edison/local/room/dao/BubbleDao.kt index 2b66517ac..7f70fe874 100644 --- a/app/src/main/java/com/umc/edison/local/room/dao/BubbleDao.kt +++ b/app/src/main/java/com/umc/edison/local/room/dao/BubbleDao.kt @@ -8,54 +8,52 @@ import com.umc.edison.local.room.RoomConstant @Dao interface BubbleDao : BaseSyncDao { - // user_id가 NULL인 버블들을 현재 로그인한 user_id로 일괄 업데이트 - @Query("UPDATE ${RoomConstant.Table.BUBBLE} SET user_id = :newUserId WHERE user_id IS NULL") - suspend fun linkGuestBubblesToUser(newUserId: String) + @Query("UPDATE ${RoomConstant.Table.BUBBLE} SET user_email = :newUserEmail WHERE user_email IS NULL") + suspend fun linkGuestBubblesToUser(newUserEmail: String) - // 현재 로그인한 사용자의 버블만 조회 @Query(""" SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE is_deleted = 0 AND is_trashed = 0 - AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + AND ((:userEmail IS NULL AND user_email IS NULL) OR (user_email = :userEmail)) """) - suspend fun getAllActiveBubbles(userId: String?): List + suspend fun getAllActiveBubbles(userEmail: String?): List @Query(""" SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE is_deleted = 0 AND is_trashed = 0 AND created_at >= :dayBefore - AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + AND ((:userEmail IS NULL AND user_email IS NULL) OR (user_email = :userEmail)) """) - suspend fun getAllRecentBubbles(dayBefore: Long, userId: String?): List + suspend fun getAllRecentBubbles(dayBefore: Long, userEmail: String?): List @Query(""" SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE is_trashed = 1 AND is_deleted = 0 - AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + AND ((:userEmail IS NULL AND user_email IS NULL) OR (user_email = :userEmail)) """) - suspend fun getAllTrashedBubbles(userId: String?): List + suspend fun getAllTrashedBubbles(userEmail: String?): List @Query(""" SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id = :bubbleId AND is_deleted = 0 AND is_trashed = 0 - AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + AND ((:userEmail IS NULL AND user_email IS NULL) OR (user_email = :userEmail)) """) - suspend fun getActiveBubbleById(bubbleId: String, userId: String?): BubbleLocal? + suspend fun getActiveBubbleById(bubbleId: String, userEmail: String?): BubbleLocal? @Query(""" SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id = :bubbleId - AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + AND ((:userEmail IS NULL AND user_email IS NULL) OR (user_email = :userEmail)) """) - suspend fun getRawBubbleById(bubbleId: String, userId: String?): BubbleLocal? + suspend fun getRawBubbleById(bubbleId: String, userEmail: String?): BubbleLocal? @Query(""" SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id IN (SELECT bubble_id FROM ${RoomConstant.Table.BUBBLE_LABEL} WHERE label_id = :labelId) AND is_deleted = 0 AND is_trashed = 0 - AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + AND ((:userEmail IS NULL AND user_email IS NULL) OR (user_email = :userEmail)) """) - suspend fun getBubblesByLabelId(labelId: String, userId: String?): List + suspend fun getBubblesByLabelId(labelId: String, userEmail: String?): List @Query(""" SELECT DISTINCT b.* FROM ${RoomConstant.Table.BUBBLE} b @@ -67,24 +65,24 @@ interface BubbleDao : BaseSyncDao { OR l.name LIKE '%' || :query || '%') AND b.is_deleted = 0 AND b.is_trashed = 0 - AND ((:userId IS NULL AND b.user_id IS NULL) OR (b.user_id = :userId)) + AND ((:userEmail IS NULL AND b.user_email IS NULL) OR (b.user_email = :userEmail)) """) - suspend fun getSearchBubbles(query: String, userId: String?): List + suspend fun getSearchBubbles(query: String, userEmail: String?): List @Query(""" SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id NOT IN (SELECT bubble_id FROM ${RoomConstant.Table.BUBBLE_LABEL}) AND is_deleted = 0 AND is_trashed = 0 - AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + AND ((:userEmail IS NULL AND user_email IS NULL) OR (user_email = :userEmail)) """) - suspend fun getBubblesWithoutLabel(userId: String?): List + suspend fun getBubblesWithoutLabel(userEmail: String?): List @Query(""" SELECT * FROM ${RoomConstant.Table.BUBBLE} WHERE id IN (:bubbleIds) AND is_deleted = 0 AND is_trashed = 0 - AND ((:userId IS NULL AND user_id IS NULL) OR (user_id = :userId)) + AND ((:userEmail IS NULL AND user_email IS NULL) OR (user_email = :userEmail)) """) - suspend fun getActiveBubblesByIds(bubbleIds: List, userId: String?): List + suspend fun getActiveBubblesByIds(bubbleIds: List, userEmail: String?): List @Query("DELETE FROM ${RoomConstant.Table.BUBBLE} WHERE id IN (:ids)") suspend fun deleteBubbles(ids: List) From a211d1b74754e1c7a1ec8b8a8784e6dbf5ded693 Mon Sep 17 00:00:00 2001 From: ally010314 Date: Thu, 26 Feb 2026 20:20:42 +0900 Subject: [PATCH 4/6] =?UTF-8?q?schemas=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + .../1.json | 344 ------------------ 2 files changed, 1 insertion(+), 344 deletions(-) delete mode 100644 app/schemas/com.umc.edison.local.room.EdisonDatabase/1.json diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f85ddba42..ef8b4f7a8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -63,6 +63,7 @@ android { getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) + signingConfig = signingConfigs.getByName("debug") } } compileOptions { diff --git a/app/schemas/com.umc.edison.local.room.EdisonDatabase/1.json b/app/schemas/com.umc.edison.local.room.EdisonDatabase/1.json deleted file mode 100644 index 2a475f264..000000000 --- a/app/schemas/com.umc.edison.local.room.EdisonDatabase/1.json +++ /dev/null @@ -1,344 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 1, - "identityHash": "530b060ec11fc7c7b99bf7ac3dbf293a", - "entities": [ - { - "tableName": "BubbleLocal", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `user_email` TEXT, `title` TEXT, `content` TEXT, `main_image` TEXT, `is_synced` INTEGER NOT NULL, `is_trashed` INTEGER NOT NULL, `is_deleted` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL, `deleted_at` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "uuid", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "userEmail", - "columnName": "user_email", - "affinity": "TEXT" - }, - { - "fieldPath": "title", - "columnName": "title", - "affinity": "TEXT" - }, - { - "fieldPath": "content", - "columnName": "content", - "affinity": "TEXT" - }, - { - "fieldPath": "mainImage", - "columnName": "main_image", - "affinity": "TEXT" - }, - { - "fieldPath": "isSynced", - "columnName": "is_synced", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isTrashed", - "columnName": "is_trashed", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isDeleted", - "columnName": "is_deleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "created_at", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "updatedAt", - "columnName": "updated_at", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "deletedAt", - "columnName": "deleted_at", - "affinity": "INTEGER" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "LabelLocal", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `color` INTEGER NOT NULL, `is_synced` INTEGER NOT NULL, `is_deleted` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL, `deleted_at` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "uuid", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "name", - "columnName": "name", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "color", - "columnName": "color", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isSynced", - "columnName": "is_synced", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isDeleted", - "columnName": "is_deleted", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "created_at", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "updatedAt", - "columnName": "updated_at", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "deletedAt", - "columnName": "deleted_at", - "affinity": "INTEGER" - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - } - }, - { - "tableName": "BubbleLabelLocal", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `bubble_id` TEXT NOT NULL, `label_id` TEXT NOT NULL, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL, FOREIGN KEY(`bubble_id`) REFERENCES `BubbleLocal`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`label_id`) REFERENCES `LabelLocal`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "bubbleId", - "columnName": "bubble_id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "labelId", - "columnName": "label_id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "created_at", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "updatedAt", - "columnName": "updated_at", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_BubbleLabelLocal_bubble_id_label_id", - "unique": true, - "columnNames": [ - "bubble_id", - "label_id" - ], - "orders": [], - "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_BubbleLabelLocal_bubble_id_label_id` ON `${TABLE_NAME}` (`bubble_id`, `label_id`)" - }, - { - "name": "index_BubbleLabelLocal_label_id", - "unique": false, - "columnNames": [ - "label_id" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_BubbleLabelLocal_label_id` ON `${TABLE_NAME}` (`label_id`)" - }, - { - "name": "index_BubbleLabelLocal_bubble_id", - "unique": false, - "columnNames": [ - "bubble_id" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_BubbleLabelLocal_bubble_id` ON `${TABLE_NAME}` (`bubble_id`)" - } - ], - "foreignKeys": [ - { - "table": "BubbleLocal", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "bubble_id" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "LabelLocal", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "label_id" - ], - "referencedColumns": [ - "id" - ] - } - ] - }, - { - "tableName": "LinkedBubbleLocal", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `curr_bubble_id` TEXT NOT NULL, `link_bubble_id` TEXT NOT NULL, `is_back` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL, FOREIGN KEY(`curr_bubble_id`) REFERENCES `BubbleLocal`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`link_bubble_id`) REFERENCES `BubbleLocal`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "currBubbleId", - "columnName": "curr_bubble_id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "linkBubbleId", - "columnName": "link_bubble_id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "isBack", - "columnName": "is_back", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "created_at", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "updatedAt", - "columnName": "updated_at", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [ - { - "name": "index_LinkedBubbleLocal_curr_bubble_id_link_bubble_id_is_back", - "unique": true, - "columnNames": [ - "curr_bubble_id", - "link_bubble_id", - "is_back" - ], - "orders": [], - "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_LinkedBubbleLocal_curr_bubble_id_link_bubble_id_is_back` ON `${TABLE_NAME}` (`curr_bubble_id`, `link_bubble_id`, `is_back`)" - }, - { - "name": "index_LinkedBubbleLocal_curr_bubble_id", - "unique": false, - "columnNames": [ - "curr_bubble_id" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_LinkedBubbleLocal_curr_bubble_id` ON `${TABLE_NAME}` (`curr_bubble_id`)" - }, - { - "name": "index_LinkedBubbleLocal_link_bubble_id", - "unique": false, - "columnNames": [ - "link_bubble_id" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_LinkedBubbleLocal_link_bubble_id` ON `${TABLE_NAME}` (`link_bubble_id`)" - } - ], - "foreignKeys": [ - { - "table": "BubbleLocal", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "curr_bubble_id" - ], - "referencedColumns": [ - "id" - ] - }, - { - "table": "BubbleLocal", - "onDelete": "CASCADE", - "onUpdate": "NO ACTION", - "columns": [ - "link_bubble_id" - ], - "referencedColumns": [ - "id" - ] - } - ] - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '530b060ec11fc7c7b99bf7ac3dbf293a')" - ] - } -} \ No newline at end of file From 6d3d238b5cbf544c21e257a8f82e1dc57801c577 Mon Sep 17 00:00:00 2001 From: ally010314 Date: Thu, 26 Feb 2026 20:22:32 +0900 Subject: [PATCH 5/6] rollback --- app/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ef8b4f7a8..f85ddba42 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -63,7 +63,6 @@ android { getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) - signingConfig = signingConfigs.getByName("debug") } } compileOptions { From 1b4bc63b04fbe4cf3778d8f38e3f9a9059a347dc Mon Sep 17 00:00:00 2001 From: ally010314 Date: Fri, 27 Feb 2026 15:11:03 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=EC=88=98=EC=A0=95=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/umc/edison/data/datasources/BubbleLocalDataSource.kt | 4 ++-- .../com/umc/edison/data/repository/BubbleRepositoryImpl.kt | 5 ++--- .../com/umc/edison/domain/repository/BubbleRepository.kt | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/umc/edison/data/datasources/BubbleLocalDataSource.kt b/app/src/main/java/com/umc/edison/data/datasources/BubbleLocalDataSource.kt index 459780d86..91af3c011 100644 --- a/app/src/main/java/com/umc/edison/data/datasources/BubbleLocalDataSource.kt +++ b/app/src/main/java/com/umc/edison/data/datasources/BubbleLocalDataSource.kt @@ -5,7 +5,7 @@ import com.umc.edison.data.model.bubble.BubbleEntity interface BubbleLocalDataSource { // CREATE suspend fun addBubbles(bubbles: List) - suspend fun addBubble(bubble: BubbleEntity, userId: String? = null) : BubbleEntity + suspend fun addBubble(bubble: BubbleEntity, userEmail: String? = null) : BubbleEntity // READ suspend fun getAllActiveBubbles(): List @@ -24,7 +24,7 @@ interface BubbleLocalDataSource { suspend fun trashBubbles(bubbles: List) suspend fun markAsSynced(bubble: BubbleEntity) suspend fun syncBubbles(bubbles: List) - suspend fun linkGuestBubblesToUser(userId: String) + suspend fun linkGuestBubblesToUser(userEmail: String) // DELETE suspend fun deleteBubbles(bubbles: List) diff --git a/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt b/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt index b92a1c670..8909d0be5 100644 --- a/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt +++ b/app/src/main/java/com/umc/edison/data/repository/BubbleRepositoryImpl.kt @@ -22,7 +22,6 @@ class BubbleRepositoryImpl @Inject constructor( private val bubbleLocalDataSource: BubbleLocalDataSource, private val bubbleRemoteDataSource: BubbleRemoteDataSource, private val resourceFactory: FlowBoundResourceFactory, - private val tokenManager: TokenManager ) : BubbleRepository { // CREATE override fun addBubbles(bubbles: List): Flow> = @@ -198,8 +197,8 @@ class BubbleRepositoryImpl @Inject constructor( } ) - override suspend fun linkGuestBubblesToUser(userId: String) { - bubbleLocalDataSource.linkGuestBubblesToUser(userId) + override suspend fun linkGuestBubblesToUser(userEmail: String) { + bubbleLocalDataSource.linkGuestBubblesToUser(userEmail) } // DELETE diff --git a/app/src/main/java/com/umc/edison/domain/repository/BubbleRepository.kt b/app/src/main/java/com/umc/edison/domain/repository/BubbleRepository.kt index cd058f2c6..93f6ea6ec 100644 --- a/app/src/main/java/com/umc/edison/domain/repository/BubbleRepository.kt +++ b/app/src/main/java/com/umc/edison/domain/repository/BubbleRepository.kt @@ -26,7 +26,7 @@ interface BubbleRepository { fun recoverBubbles(bubbles: List): Flow> fun updateBubbles(bubbles: List): Flow> fun updateBubble(bubble: Bubble): Flow> - suspend fun linkGuestBubblesToUser(userId: String) + suspend fun linkGuestBubblesToUser(userEmail: String) // DELETE fun deleteBubbles(bubbles: List): Flow>