Skip to content

Commit 948c2c8

Browse files
committed
feat: add safeBrowsingExpiry column to urls table
1 parent 2d94333 commit 948c2c8

File tree

9 files changed

+43
-9
lines changed

9 files changed

+43
-9
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- This adds the safeBrowsingExpiry column to the urls table, which is
2+
-- backwards-compatible with the current codebase as it allows NULL values.
3+
4+
BEGIN TRANSACTION;
5+
6+
ALTER TABLE urls ADD "safeBrowsingExpiry" TIMESTAMP WITH TIME ZONE;
7+
8+
COMMIT;
9+
10+
-- Down migration
11+
-- ALTER TABLE urls DROP COLUMN "safeBrowsingExpiry";

src/server/mappers/UrlMapper.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class UrlMapper implements Mapper<StorableUrl, UrlType> {
3232
contactEmail: urlType.contactEmail,
3333
source: urlType.source,
3434
tagStrings: urlType.tagStrings,
35+
safeBrowsingExpiry: urlType.safeBrowsingExpiry,
3536
}
3637
}
3738
}

src/server/models/url.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface UrlBaseType extends IdType {
2424
readonly description: string
2525
readonly source: StorableUrlSource
2626
readonly tagStrings: string
27+
readonly safeBrowsingExpiry: string | null
2728
}
2829

2930
export interface UrlType extends IdType, UrlBaseType, Sequelize.Model {
@@ -229,6 +230,10 @@ export const Url = <UrlTypeStatic>sequelize.define(
229230
allowNull: false,
230231
defaultValue: '',
231232
},
233+
safeBrowsingExpiry: {
234+
type: Sequelize.DATE,
235+
allowNull: true,
236+
},
232237
},
233238
{
234239
hooks: {

src/server/repositories/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export type StorableUrl = Pick<
1616
| 'contactEmail'
1717
| 'source'
1818
| 'tagStrings'
19+
| 'safeBrowsingExpiry'
1920
> &
2021
Pick<UrlClicksType, 'clicks'> & { tags?: string[] }
2122

test/integration/api/user/Urls.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ describe('Url integration tests', () => {
8686
tagStrings: '',
8787
createdAt: expect.stringMatching(DATETIME_REGEX),
8888
updatedAt: expect.stringMatching(DATETIME_REGEX),
89+
safeBrowsingExpiry: null,
8990
})
9091
})
9192

@@ -108,6 +109,7 @@ describe('Url integration tests', () => {
108109
tagStrings: '',
109110
createdAt: expect.stringMatching(DATETIME_REGEX),
110111
updatedAt: expect.stringMatching(DATETIME_REGEX),
112+
safeBrowsingExpiry: null,
111113
})
112114
})
113115

@@ -151,6 +153,7 @@ describe('Url integration tests', () => {
151153
tagStrings: '',
152154
createdAt: expect.stringMatching(DATETIME_REGEX),
153155
updatedAt: expect.stringMatching(DATETIME_REGEX),
156+
safeBrowsingExpiry: null,
154157
})
155158

156159
// Should be able to get updated link URL
@@ -172,6 +175,7 @@ describe('Url integration tests', () => {
172175
tagStrings: '',
173176
createdAt: expect.stringMatching(DATETIME_REGEX),
174177
updatedAt: expect.stringMatching(DATETIME_REGEX),
178+
safeBrowsingExpiry: null,
175179
},
176180
],
177181
count: 1,
@@ -203,6 +207,7 @@ describe('Url integration tests', () => {
203207
tagStrings: '',
204208
createdAt: expect.stringMatching(DATETIME_REGEX),
205209
updatedAt: expect.stringMatching(DATETIME_REGEX),
210+
safeBrowsingExpiry: null,
206211
})
207212

208213
// Should be able to get updated file URL
@@ -224,6 +229,7 @@ describe('Url integration tests', () => {
224229
tagStrings: '',
225230
createdAt: expect.stringMatching(DATETIME_REGEX),
226231
updatedAt: expect.stringMatching(DATETIME_REGEX),
232+
safeBrowsingExpiry: null,
227233
},
228234
],
229235
count: 1,

test/server/mappers/UrlV1Mapper.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ describe('url v1 mapper', () => {
2121
tagStrings: '1;abc;foo-bar',
2222
contactEmail: '[email protected]',
2323
description: 'this-is-a-description',
24+
safeBrowsingExpiry: null,
2425
}
2526
const urlV1DTO = urlV1Mapper.persistenceToDto(storableUrl)
2627
expect(urlV1DTO).toEqual({

test/server/mocks/repositories/UrlRepository.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export class UrlRepositoryMock implements UrlRepositoryInterface {
8484
clicks: 0,
8585
source: StorableUrlSource.Console,
8686
tagStrings: '',
87+
safeBrowsingExpiry: null,
8788
},
8889
],
8990
count: 0,

test/server/repositories/UrlRepository.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
import { DirectoryQueryConditions } from '../../../src/server/modules/directory'
2525
import TagRepositoryMock from '../mocks/repositories/TagRepository'
2626
import { TAG_SEPARATOR } from '../../../src/shared/constants'
27+
import { StorableUrl } from '../../../src/server/repositories/types'
2728

2829
jest.mock('../../../src/server/models/url', () => ({
2930
Url: urlModelMock,
@@ -75,17 +76,18 @@ describe('UrlRepository', () => {
7576
const baseUrlClicks = {
7677
clicks: 2,
7778
}
78-
const baseTemplate = {
79+
const baseTemplate: Omit<StorableUrl, 'tagStrings' | 'clicks'> = {
7980
shortUrl: baseShortUrl,
8081
longUrl: baseLongUrl,
81-
state: 'ACTIVE',
82+
state: StorableUrlState.Active,
8283
isFile: false,
83-
createdAt: new Date(),
84-
updatedAt: new Date(),
84+
createdAt: new Date().toISOString(),
85+
updatedAt: new Date().toISOString(),
8586
description: 'An agency of the Singapore Government',
8687
contactEmail: '[email protected]',
8788
source: StorableUrlSource.Console,
8889
tags: [],
90+
safeBrowsingExpiry: null,
8991
}
9092
const baseUrl = {
9193
...baseTemplate,

test/server/repositories/UserRepository.test.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import { UserRepository } from '../../../src/server/repositories/UserRepository'
33
import { UrlMapper } from '../../../src/server/mappers/UrlMapper'
44
import { UserMapper } from '../../../src/server/mappers/UserMapper'
55
import { NotFoundError } from '../../../src/server/util/error'
6+
import { StorableUrl } from '../../../src/server/repositories/types'
7+
import {
8+
StorableUrlSource,
9+
StorableUrlState,
10+
} from '../../../src/server/repositories/enums'
611

712
jest.mock('../../../src/server/models/user', () => ({
813
User: userModelMock,
@@ -17,16 +22,17 @@ const userRepo = new UserRepository(
1722
new UrlMapper(),
1823
)
1924

20-
const baseUrlTemplate = {
25+
const baseUrlTemplate: Omit<StorableUrl, 'tagStrings' | 'clicks'> = {
2126
shortUrl: 'short-link',
2227
longUrl: 'https://www.agency.gov.sg',
23-
state: 'ACTIVE',
28+
state: StorableUrlState.Active,
2429
isFile: false,
25-
createdAt: Date.now(),
26-
updatedAt: Date.now(),
30+
createdAt: new Date().toISOString(),
31+
updatedAt: new Date().toISOString(),
2732
description: 'An agency of the Singapore Government',
2833
contactEmail: '[email protected]',
29-
source: 'CONSOLE',
34+
source: StorableUrlSource.Console,
35+
safeBrowsingExpiry: null,
3036
}
3137

3238
const urlClicks = {

0 commit comments

Comments
 (0)