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
4 changes: 4 additions & 0 deletions __test__/auth/CachingRepositoryAccessReaderConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ test("It fetches repository names for user if they are not cached", async () =>
return null
},
async set() {},
async setExpiring() {},
async delete() {}
},
repositoryAccessReader: {
Expand All @@ -32,6 +33,7 @@ test("It does not fetch repository names if they are cached", async () => {
return "[\"foo\"]"
},
async set() {},
async setExpiring() {},
async delete() {}
},
repositoryAccessReader: {
Expand All @@ -57,6 +59,7 @@ test("It caches fetched repository names for user", async () => {
cachedUserId = userId
cachedRepositoryNames = value
},
async setExpiring() {},
async delete() {}
},
repositoryAccessReader: {
Expand All @@ -77,6 +80,7 @@ test("It decodes cached repository names", async () => {
return "[\"foo\",\"bar\"]"
},
async set() {},
async setExpiring() {},
async delete() {}
},
repositoryAccessReader: {
Expand Down
5 changes: 4 additions & 1 deletion __test__/auth/CachingUserIdentityProviderReader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ test("It fetches user identity provider if it is not cached", async () => {
return null
},
async set() {},
async setExpiring() {},
async delete() {}
}, {
async getUserIdentityProvider() {
Expand All @@ -26,6 +27,7 @@ test("It does not fetch user identity provider if it is cached", async () => {
return UserIdentityProvider.GITHUB
},
async set() {},
async setExpiring() {},
async delete() {}
}, {
async getUserIdentityProvider() {
Expand All @@ -44,7 +46,8 @@ test("It caches fetched user identity provider for user", async () => {
async get() {
return null
},
async set(userId, userIdentityProvider) {
async set() {},
async setExpiring(userId, userIdentityProvider) {
cachedUserId = userId
cachedUserIdentityProvider = userIdentityProvider
},
Expand Down
4 changes: 2 additions & 2 deletions __test__/auth/GuestAccessTokenService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ test("It gets the access token for the user", async () => {
readUserId = userId
return "foo"
},
async set() {}
async setExpiring() {}
},
dataSource: {
async getAccessToken() {
Expand All @@ -38,7 +38,7 @@ test("It refreshes access token on demand when there is no cached access token",
async get() {
return null
},
async set() {}
async setExpiring() {}
},
dataSource: {
async getAccessToken() {
Expand Down
5 changes: 4 additions & 1 deletion __test__/auth/OAuthTokenRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ test("It reads the auth token for the specified user", async () => {
})
},
async set() {},
async setExpiring() {},
async delete() {}
})
await sut.get("1234")
Expand All @@ -24,7 +25,8 @@ test("It stores the auth token for the specified user", async () => {
async get() {
return ""
},
async set(userId, data) {
async set() {},
async setExpiring(userId, data) {
storedUserId = userId
storedJSON = data
},
Expand All @@ -48,6 +50,7 @@ test("It deletes the auth token for the specified user", async () => {
return ""
},
async set() {},
async setExpiring() {},
async delete(userId) {
deletedUserId = userId
}
Expand Down
21 changes: 21 additions & 0 deletions __test__/common/userData/KeyValueUserDataRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ test("It reads the expected key", async () => {
return ""
},
async set() {},
async setExpiring() {},
async delete() {}
}, "foo")
await sut.get("123")
Expand All @@ -23,12 +24,31 @@ test("It stores values under the expected key", async () => {
async set(key) {
storedKey = key
},
async setExpiring() {},
async delete() {}
}, "foo")
await sut.set("123", "bar")
expect(storedKey).toBe("foo[123]")
})

test("It stores values under the expected key with expected time to live", async () => {
let storedKey: string | undefined
let storedTimeToLive: number | undefined
const sut = new KeyValueUserDataRepository({
async get() {
return ""
},
async set() {},
async setExpiring(key, _value, timeToLive) {
storedKey = key
storedTimeToLive = timeToLive
},
async delete() {}
}, "foo")
await sut.setExpiring("123", "bar", 24 * 3600)
expect(storedKey).toBe("foo[123]")
expect(storedTimeToLive).toBe(24 * 3600)
})

test("It deletes the expected key", async () => {
let deletedKey: string | undefined
Expand All @@ -37,6 +57,7 @@ test("It deletes the expected key", async () => {
return ""
},
async set() {},
async setExpiring() {},
async delete(key) {
deletedKey = key
}
Expand Down
5 changes: 5 additions & 0 deletions src/common/keyValueStore/IKeyValueStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export default interface IKeyValueStore {
get(key: string): Promise<string | null>
set(key: string, data: string | number | Buffer): Promise<void>
setExpiring(
key: string,
data: string | number | Buffer,
timeToLive: number
): Promise<void>
delete(key: string): Promise<void>
}
8 changes: 8 additions & 0 deletions src/common/keyValueStore/RedisKeyValueStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ export default class RedisKeyValueStore implements IKeyValueStore {
await this.redis.set(key, data)
}

async setExpiring(
key: string,
data: string | number | Buffer,
timeToLive: number
): Promise<void> {
await this.redis.setex(key, timeToLive, data)
}

async delete(key: string): Promise<void> {
await this.redis.del(key)
}
Expand Down
1 change: 1 addition & 0 deletions src/common/userData/IUserDataRepository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export default interface IUserDataRepository<T> {
get(userId: string): Promise<T | null>
set(userId: string, value: T): Promise<void>
setExpiring(userId: string, value: T, timeToLive: number): Promise<void>
delete(userId: string): Promise<void>
}
4 changes: 4 additions & 0 deletions src/common/userData/KeyValueUserDataRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export default class KeyValueUserDataRepository implements IUserDataRepository<s
await this.store.set(this.getKey(userId), value)
}

async setExpiring(userId: string, value: string, timeToLive: number): Promise<void> {
await this.store.setExpiring(this.getKey(userId), value, timeToLive)
}

async delete(userId: string): Promise<void> {
await this.store.delete(this.getKey(userId))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export interface IUserIDReader {

export interface Repository {
get(userId: string): Promise<string | null>
set(userId: string, token: string): Promise<void>
setExpiring(userId: string, token: string, timeToLive: number): Promise<void>
}

export interface DataSource {
Expand Down Expand Up @@ -47,7 +47,7 @@ export default class GuestAccessTokenService implements IAccessTokenService {
private async getNewAccessToken(): Promise<string> {
const userId = await this.userIdReader.getUserId()
const newAccessToken = await this.dataSource.getAccessToken(userId)
await this.repository.set(userId, newAccessToken)
await this.repository.setExpiring(userId, newAccessToken, 7 * 24 * 3600)
return newAccessToken
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class OAuthTokenRepository implements IOAuthTokenRepository {

async set(userId: string, token: OAuthToken): Promise<void> {
const string = ZodJSONCoder.encode(OAuthTokenSchema, token)
await this.repository.set(userId, string)
await this.repository.setExpiring(userId, string, 6 * 30 * 24 * 3600)
}

async delete(userId: string): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default class CachingRepositoryAccessReader {
const repositoryNames = await this.repositoryAccessReader.getRepositoryNames(userId)
try {
const str = ZodJSONCoder.encode(RepositoryNamesContainerSchema, repositoryNames)
await this.repository.set(userId, str)
await this.repository.setExpiring(userId, str, 7 * 24 * 3600)
} catch (error: unknown) {
console.error(error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class CachingUserIdentityProviderReader implements IUserIdentityP
return cachedValue as UserIdentityProvider
} else {
const userIdentity = await this.reader.getUserIdentityProvider(userId)
await this.repository.set(userId, userIdentity.toString())
await this.repository.setExpiring(userId, userIdentity.toString(), 7 * 24 * 3600)
return userIdentity
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/features/projects/domain/ProjectRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default class ProjectRepository implements IProjectRepository {
async set(projects: Project[]): Promise<void> {
const userId = await this.userIDReader.getUserId()
const string = ZodJSONCoder.encode(ProjectSchema.array(), projects)
await this.repository.set(userId, string)
await this.repository.setExpiring(userId, string, 30 * 24 * 3600)
}

async delete(): Promise<void> {
Expand Down