fix: add input sanitization across date plan forms and repository
This commit is contained in:
parent
b049024ba9
commit
0095151bd9
|
|
@ -77,18 +77,16 @@ class DatePlanRepositoryImpl @Inject constructor(
|
|||
}
|
||||
|
||||
override suspend fun savePlan(plan: DatePlan) {
|
||||
// Store in Room for local-first access
|
||||
val entity = plan.toEntity()
|
||||
|
||||
if (plan.id.isEmpty()) {
|
||||
// Create new plan - let Firestore generate the ID
|
||||
val newId = planDataSource.createPlan(plan.coupleId, plan)
|
||||
val sanitized = plan.sanitized()
|
||||
val entity = sanitized.toEntity()
|
||||
|
||||
if (sanitized.id.isEmpty()) {
|
||||
val newId = planDataSource.createPlan(sanitized.coupleId, sanitized)
|
||||
val updatedEntity = entity.copy(id = newId)
|
||||
planDao.insert(updatedEntity)
|
||||
} else {
|
||||
// Update existing plan
|
||||
planDao.insert(entity)
|
||||
planDataSource.updatePlan(plan.coupleId, plan)
|
||||
planDataSource.updatePlan(sanitized.coupleId, sanitized)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,8 +133,29 @@ class DatePlanRepositoryImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
// ─── Sanitization ────────────────────────────────────────────────────────
|
||||
|
||||
private fun DatePlan.sanitized(): DatePlan = copy(
|
||||
scheduledTime = scheduledTime.take(MAX_TIME_LENGTH),
|
||||
duration = duration.take(MAX_DURATION_LENGTH),
|
||||
activity = activity.take(MAX_TEXT_LENGTH),
|
||||
food = food.take(MAX_TEXT_LENGTH),
|
||||
conversationPrompts = conversationPrompts
|
||||
.take(MAX_PROMPTS)
|
||||
.map { it.take(MAX_PROMPT_LENGTH) },
|
||||
optionalChallenge = optionalChallenge?.take(MAX_TEXT_LENGTH)
|
||||
)
|
||||
|
||||
// ─── Mappers ─────────────────────────────────────────────────────────────
|
||||
|
||||
private companion object {
|
||||
const val MAX_TIME_LENGTH = 20
|
||||
const val MAX_DURATION_LENGTH = 50
|
||||
const val MAX_TEXT_LENGTH = 500
|
||||
const val MAX_PROMPT_LENGTH = 1_000
|
||||
const val MAX_PROMPTS = 20
|
||||
}
|
||||
|
||||
private fun DatePlanPreferenceEntity.toDomain(): DatePlanPreference = DatePlanPreference(
|
||||
id = id,
|
||||
coupleId = coupleId,
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ class BucketListViewModel @Inject constructor(
|
|||
|
||||
val newItem = BucketListItem(
|
||||
coupleId = coupleId,
|
||||
title = title,
|
||||
description = description,
|
||||
title = title.take(MAX_TITLE_LENGTH),
|
||||
description = description.take(MAX_DESCRIPTION_LENGTH),
|
||||
category = category,
|
||||
addedBy = "currentUser",
|
||||
addedAt = System.currentTimeMillis()
|
||||
|
|
@ -100,6 +100,11 @@ class BucketListViewModel @Inject constructor(
|
|||
fun clear() {
|
||||
_uiState.update { BucketListUiState() }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_TITLE_LENGTH = 100
|
||||
const val MAX_DESCRIPTION_LENGTH = 500
|
||||
}
|
||||
}
|
||||
|
||||
data class BucketListUiState(
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@ class DateBuilderViewModel @Inject constructor(
|
|||
val preference = DatePlanPreference(
|
||||
dateIdeaId = state.dateIdeaId,
|
||||
preferredDate = state.scheduledDate,
|
||||
preferredTime = state.scheduledTime,
|
||||
preferredTime = state.scheduledTime.take(MAX_TIME_LENGTH),
|
||||
budget = state.budget,
|
||||
duration = state.duration
|
||||
duration = state.duration.take(MAX_DURATION_LENGTH)
|
||||
)
|
||||
|
||||
viewModelScope.launch {
|
||||
|
|
@ -60,6 +60,11 @@ class DateBuilderViewModel @Inject constructor(
|
|||
fun clear() {
|
||||
_uiState.update { DateBuilderUiState() }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_TIME_LENGTH = 20
|
||||
const val MAX_DURATION_LENGTH = 50
|
||||
}
|
||||
}
|
||||
|
||||
data class DateBuilderUiState(
|
||||
|
|
|
|||
Loading…
Reference in New Issue