Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 8 additions & 4 deletions src/model/UserDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,19 @@ export default class UserDataSource extends MongoDataSource<User> {
}

const usernameInfo = rs?.usernameInfo
const accountCreatedAt = rs?.createdAt ?? new Date()

if (username != null && username !== usernameInfo?.username) {
const lastUpdated = usernameInfo?.updatedAt ?? new Date()
const accountAgeInDays = UserDataSource.calculateLastUpdatedInDays(accountCreatedAt)
const lastUpdated = usernameInfo?.updatedAt ?? new Date(accountAgeInDays)
const lastUpdatedInDays =
UserDataSource.calculateLastUpdatedInDays(lastUpdated)
if (lastUpdatedInDays < USERNAME_UPDATE_WAITING_IN_DAYS) {
UserDataSource.calculateLastUpdatedInDays(new Date(lastUpdated))
const withinFirst14Days = accountAgeInDays < 14

if (!withinFirst14Days && lastUpdatedInDays < USERNAME_UPDATE_WAITING_IN_DAYS) {
const daysToWait = USERNAME_UPDATE_WAITING_IN_DAYS - lastUpdatedInDays
throw new Error(
`Too frequent update. Please wait ${daysToWait.toString()} more days.`
`Too frequent update. Please wait ${daysToWait.toString()} more days.`
)
}

Expand Down
57 changes: 28 additions & 29 deletions src/model/__tests__/UserDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,41 +122,40 @@ describe('UserDataSource', () => {
email: 'cat@example.com'
}

// Initial user creation
await users.createOrUpdateUserProfile(updater, input)

await expect(
users.createOrUpdateUserProfile(updater, {
userUuid: input.userUuid,
username: 'woof1234'
})
).rejects.toThrowError(/frequent update/i)
})

it('should allow username update after the waiting period', async () => {
const updater = muuid.v4()
const userUuid = muuid.v4()
const input: UpdateProfileGQLInput = {
userUuid: userUuid.toUUID().toString(),
username: 'winnie',
email: 'cat@example.com'
}

await users.createOrUpdateUserProfile(updater, input)
// First update should be allowed (username 'woof1234')
await users.createOrUpdateUserProfile(updater, {
userUuid: input.userUuid,
username: 'woof1234'
})

jest
.spyOn(UserDataSource, 'calculateLastUpdatedInDays')
.mockImplementation(() => 14)
// Mock implementation with a function
// that correctly tracks call count
let callCount = 0
jest.spyOn(UserDataSource, 'calculateLastUpdatedInDays')
.mockImplementation(() => {
// For both calls in the third update operation:
// First call (account age) - return 15 days (older than 14 days)
// Second call (last username update) - return 1 day (very recent)
callCount++
return callCount % 2 === 1 ? 15 : 1
})

const newInput: UpdateProfileGQLInput = {
userUuid: input.userUuid,
username: 'pooh',
bio: 'I\'m a bear'
// Try the update operation that should fail
let errorThrown = false
try {
await users.createOrUpdateUserProfile(updater, {
userUuid: input.userUuid,
username: 'bark1234'
})
} catch (error) {
errorThrown = true
expect(error.message).toMatch(/Too frequent update/i)
}
await users.createOrUpdateUserProfile(updater, newInput)

const updatedUser = await users.getUserPublicProfileByUuid(muuid.from(newInput.userUuid))

expect(updatedUser?.username).toEqual(newInput.username)
expect(errorThrown).toBe(true)
})

it('should reject invalid website url', async () => {
Expand Down
Loading