Skip to content

Commit

Permalink
feat: Expire URLs automatically after set period of time
Browse files Browse the repository at this point in the history
  • Loading branch information
blefebvre committed Oct 2, 2024
1 parent c9ca7f2 commit 5b58f8d
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 18 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions packages/spacecat-shared-data-access/docs/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,10 @@
}
},
"NonKeyAttributes": [
{
"AttributeName": "expiresAt",
"AttributeType": "S"
},
{
"AttributeName": "file",
"AttributeType": "S"
Expand Down
10 changes: 1 addition & 9 deletions packages/spacecat-shared-data-access/src/dto/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,7 @@
import { isObject } from '@adobe/spacecat-shared-utils';

import { createAudit } from '../models/audit.js';

function parseEpochToDate(epochInSeconds) {
const milliseconds = epochInSeconds * 1000;
return new Date(milliseconds);
}

function convertDateToEpochSeconds(date) {
return Math.floor(date.getTime() / 1000);
}
import { convertDateToEpochSeconds, parseEpochToDate } from './dto-utils.js';

/**
* Data transfer object for Audit.
Expand Down
30 changes: 30 additions & 0 deletions packages/spacecat-shared-data-access/src/dto/dto-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2024 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

/**
* Parse the given Epoch timestamp, in seconds, to a Date object.
* @param {number} epochInSeconds - The Epoch timestamp in seconds.
* @returns {Date} A new Date object set to the given timestamp.
*/
export function parseEpochToDate(epochInSeconds) {
const milliseconds = epochInSeconds * 1000;
return new Date(milliseconds);
}

/**
* Convert the given Date object to an Epoch timestamp, in seconds.
* @param {Date} date - The Date object to convert.
* @returns {number} The Epoch timestamp in seconds.
*/
export function convertDateToEpochSeconds(date) {
return Math.floor(date.getTime() / 1000);
}
3 changes: 3 additions & 0 deletions packages/spacecat-shared-data-access/src/dto/import-url.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/

import { createImportUrl } from '../models/importer/import-url.js';
import { convertDateToEpochSeconds, parseEpochToDate } from './dto-utils.js';

/**
* The ImportUrlDto is a helper that can convert an ImportUrl object to a DynamoDB item and
Expand All @@ -30,6 +31,7 @@ export const ImportUrlDto = {
reason: importUrl.getReason(),
path: importUrl.getPath(),
file: importUrl.getFile(),
expiresAt: convertDateToEpochSeconds(importUrl.getExpiresAt()),
}),

/**
Expand All @@ -46,6 +48,7 @@ export const ImportUrlDto = {
reason: dynamoItem.reason,
path: dynamoItem.path,
file: dynamoItem.file,
expiresAt: parseEpochToDate(dynamoItem.expiresAt),
};
return createImportUrl(importUrlData);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { hasText, isValidUrl } from '@adobe/spacecat-shared-utils';
import { Base } from '../base.js';
import { ImportUrlStatus } from './import-constants.js';

const EXPIRES_IN_DAYS = 30;
export const IMPORT_URL_EXPIRES_IN_DAYS = 30;

/**
* Creates a new ImportUrl object
Expand All @@ -33,11 +33,8 @@ const ImportUrl = (data) => {
self.getPath = () => self.state.path;
// Resulting path and filename of the imported .docx file
self.getFile = () => self.state.file;

if (!self.expiresAt) {
self.expiresAt = new Date();
self.expiresAt.setDate(self.expiresAt.getDate() + EXPIRES_IN_DAYS);
}
// Expiration date for the URL
self.getExpiresAt = () => self.state.expiresAt;

/**
* Updates the state of the ImportJob.
Expand Down Expand Up @@ -109,5 +106,10 @@ export const createImportUrl = (data) => {
throw new Error(`Invalid Import URL status: ${newState.status}`);
}

if (!newState.expiresAt) {
newState.expiresAt = new Date();
newState.expiresAt.setDate(newState.expiresAt.getDate() + IMPORT_URL_EXPIRES_IN_DAYS);
}

return ImportUrl(newState);
};
7 changes: 7 additions & 0 deletions packages/spacecat-shared-data-access/test/it/db.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
import { KEY_EVENT_TYPES } from '../../src/models/key-event.js';
import { ConfigurationDto } from '../../src/dto/configuration.js';
import { ImportJobStatus, ImportOptions, ImportUrlStatus } from '../../src/index.js';
import { IMPORT_URL_EXPIRES_IN_DAYS } from '../../src/models/importer/import-url.js';

use(chaiAsPromised);

Expand Down Expand Up @@ -1094,6 +1095,12 @@ describe('DynamoDB Integration Test', async () => {

expect(url.getId()).to.be.a('string');
expect(url.getJobId()).to.equal(job.getId());

// Check that expiresAt was set correctly
const expectedExpiresAtDate = new Date();
expectedExpiresAtDate.setDate(expectedExpiresAtDate.getDate() + IMPORT_URL_EXPIRES_IN_DAYS);

expect(url.getExpiresAt().toDateString()).to.equal(expectedExpiresAtDate.toDateString());
});

it('Verify getImportUrlById', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
import { expect } from 'chai';

import { ImportUrlStatus } from '../../../../src/index.js';
import { createImportUrl } from '../../../../src/models/importer/import-url.js';
import {
createImportUrl,
IMPORT_URL_EXPIRES_IN_DAYS,
} from '../../../../src/models/importer/import-url.js';
import { ImportUrlDto } from '../../../../src/dto/import-url.js';

const validImportUrlData = {
Expand Down Expand Up @@ -107,7 +110,20 @@ describe('ImportUrl Model tests', () => {
describe('Import URL DTO Tests', () => {
it('should serialize to a Dynamo-compatible object', () => {
const importUrlRedirect = createImportUrl(importUrlRedirectData);
expect(ImportUrlDto.toDynamoItem(importUrlRedirect)).to.deep.equal({

const expiresAtDate = importUrlRedirect.getExpiresAt();

// Check that expiresAtDate is IMPORT_URL_EXPIRES_IN_DAYS days from today
const expectedExpiresAtDate = new Date();
expectedExpiresAtDate.setDate(expectedExpiresAtDate.getDate() + IMPORT_URL_EXPIRES_IN_DAYS);

expect(expiresAtDate.toDateString()).to.equal(expectedExpiresAtDate.toDateString());

// expiresAt is dynamic, so now that we've checked it we'll remove it from the object
const importUrlDynamoItem = ImportUrlDto.toDynamoItem(importUrlRedirect);
delete importUrlDynamoItem.expiresAt;

expect(importUrlDynamoItem).to.deep.equal({
id: '456',
url: 'https://www.example.com/redirect',
jobId: '456',
Expand Down

0 comments on commit 5b58f8d

Please sign in to comment.