Skip to content

Commit

Permalink
merge: master into dynamic-environments
Browse files Browse the repository at this point in the history
  • Loading branch information
sw-wayner committed Feb 16, 2024
2 parents 6c53f93 + c6e35a1 commit ec4de6c
Show file tree
Hide file tree
Showing 61 changed files with 1,978 additions and 443 deletions.
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ SENDGRID_TEMPLATE_DRIVE_SHARING_ROLE_UPDATED=d-0c9cbd0a649d4cee8eac6a4ae68736c9
SENDGRID_TEMPLATE_SEND_LINK_CREATE_RECEIVER=d-eb5a1fd73d764e9991a25e2a0297f279
SENDGRID_TEMPLATE_SEND_LINK_CREATE_SENDER=d-7889146930fa421083b4bf1cdcaedab3
SENDGRID_TEMPLATE_DRIVE_UPDATE_USER_EMAIL=d-46a66194ad8e4bb6919d39e20d9c34d1
SENDGRID_TEMPLATE_DRIVE_UNBLOCK_ACCOUNT=d-d91905dc7a7549ada00d0fc0bb0a55b1
SHARE_DOMAINS=http://localhost:3000
PCREATED_USERS_PASSWORD=example

Expand Down
19 changes: 19 additions & 0 deletions migrations/20240109071854-add-lastPasswordChangedAt-to-users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict';

const tableName = 'users';
const newColumn = 'last_password_changed_at';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn(tableName, newColumn, {
type: Sequelize.DATE,
allowNull: true,
defaultValue: null,
});
},

async down(queryInterface) {
await queryInterface.removeColumn(tableName, newColumn);
},
};
20 changes: 20 additions & 0 deletions migrations/20240117140256-add-unblock-account-to-mailtype-enum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
up: async (queryInterface) => {
await queryInterface.sequelize.query(
`ALTER TYPE mail_type ADD VALUE 'unblock_account';`,
);
},
down: async (queryInterface) => {
await queryInterface.sequelize.query(
`
ALTER TYPE mail_type RENAME TO mail_type_old;
CREATE TYPE mail_type AS ENUM('invite_friend', 'reset_password', 'remove_account', 'deactivate_account');
ALTER TABLE mail_limits ALTER COLUMN mail_type TYPE mail_type USING mail_type::text::mail_type;
DROP TYPE mail_type_old;
`,
);
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.removeConstraint('files', 'files_user_id_fkey');
},

down: async (queryInterface, Sequelize) => {
await queryInterface.addConstraint('files', {
fields: ['user_id'],
type: 'foreign key',
name: 'files_user_id_fkey',
references: {
table: 'users',
field: 'id',
},
onDelete: 'SET NULL',
onUpdate: 'CASCADE',
});
},
};
16 changes: 16 additions & 0 deletions migrations/20240213132333-create-index-parent-uuid-folders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.sequelize.query(
`CREATE INDEX CONCURRENTLY folders_parent_uuid_index ON folders (parent_uuid)`,
);
},

async down(queryInterface, Sequelize) {
await queryInterface.sequelize.query(
`DROP INDEX CONCURRENTLY folders_parent_uuid_index`,
);
},
};
20 changes: 3 additions & 17 deletions src/common/base-http.exception.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import { HttpStatus } from '@nestjs/common';

export class BaseHttpException extends Error {
private readonly _statusCode: number;
private readonly _code: string;

constructor(
message: string,
statusCode = HttpStatus.INTERNAL_SERVER_ERROR,
code?: string,
public readonly message: string,
public readonly statusCode = HttpStatus.INTERNAL_SERVER_ERROR,
public readonly code?: string,
) {
super(message);
this.message = message;
this._statusCode = statusCode;
this._code = code;
}

get statusCode(): number {
return this._statusCode;
}

get code(): string {
return this._code;
}
}
33 changes: 33 additions & 0 deletions src/common/uuid.dto.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { validate } from 'class-validator';
import { UuidDto } from './uuid.dto';
import { newUser } from '../../test/fixtures';

describe('UuidDto Validation', () => {
const user = newUser();

it('When a valid UUID is passed, then pass', async () => {
const dto = new UuidDto();
dto.id = user.uuid;

const errors = await validate(dto);
expect(errors.length).toBe(0);
});

it('When an invalid UUID is passed, then fail', async () => {
const dto = new UuidDto();
dto.id = 'invalid_uuid_string';

const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
expect(errors[0].constraints).toHaveProperty('isUuid');
});

it('When an empty string is passed, then fail', async () => {
const dto = new UuidDto();
dto.id = 'invalid-uuid';
const errors = await validate(dto);

expect(errors.length).toBeGreaterThan(0);
expect(errors[0].constraints).toHaveProperty('isUuid');
});
});
6 changes: 6 additions & 0 deletions src/common/uuid.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IsUUID } from 'class-validator';

export class UuidDto {
@IsUUID()
id: string;
}
4 changes: 3 additions & 1 deletion src/config/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default () => ({
url: process.env.STORAGE_API_URL,
auth: {
username: process.env.GATEWAY_USER,
password: process.env.GATEWAY_PASSWORD,
password: process.env.GATEWAY_PASS,
},
},
drive: {
Expand Down Expand Up @@ -93,6 +93,8 @@ export default () => ({
process.env.SENDGRID_TEMPLATE_DRIVE_SHARING_ROLE_UPDATED || '',
updateUserEmail:
process.env.SENDGRID_TEMPLATE_DRIVE_UPDATE_USER_EMAIL || '',
unblockAccountEmail:
process.env.SENDGRID_TEMPLATE_DRIVE_UNBLOCK_ACCOUNT || '',
},
},
newsletter: {
Expand Down
1 change: 1 addition & 0 deletions src/externals/bridge/bridge.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ describe('Bridge Service', () => {
hKey: undefined,
secret_2FA: '',
tempKey: '',
lastPasswordChangedAt: new Date(),
});

beforeEach(async () => {
Expand Down
12 changes: 12 additions & 0 deletions src/externals/mailer/mailer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,16 @@ export class MailerService {
},
);
}

async sendAutoAccountUnblockEmail(email: User['email'], url: string) {
const context = {
email,
unblock_url: url,
};
await this.send(
email,
this.configService.get('mailer.templates.unblockAccountEmail'),
context,
);
}
}
2 changes: 1 addition & 1 deletion src/lib/http/http-exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class HttpExceptionFilter implements ExceptionFilter {
`
UNHANDLE ERROR:
${JSON.stringify(exception)}
${JSON.stringify(exception.message ?? exception)}
`,
);

Expand Down
8 changes: 8 additions & 0 deletions src/lib/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,11 @@ export function verifyToken(token: string, secret: string) {
export function verifyWithDefaultSecret(token: string) {
return verify(token, getEnv().secrets.jwt);
}

export function getTokenDefaultIat() {
return Math.floor(Date.now() / 1000);
}

export function isTokenIatGreaterThanDate(date: Date, iat: number) {
return Math.floor(date.getTime() / 1000) < iat;
}
70 changes: 70 additions & 0 deletions src/lib/time.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Time } from './time';

describe('Time class', () => {
const fixedSystemCurrentDate = new Date('2022-01-01');

beforeAll(() => {
jest.useFakeTimers();
jest.setSystemTime(fixedSystemCurrentDate);
});

afterAll(() => {
jest.useRealTimers();
});

describe('now()', () => {
it('When is called, then returns the current date', () => {
const currentDate = Time.now();
expect(currentDate.getTime()).toBeGreaterThanOrEqual(
new Date('2022-01-01').getTime(),
);
});

it('When is called and date is provided, then returns the date provided', () => {
const initialDate = new Date('2022-02-02');
const currentDate = Time.now(initialDate);
expect(currentDate).toEqual(initialDate);
});
});

describe('dateWithDaysAdded()', () => {
it('When days are added, then returns correct current date and days added', () => {
const systemFutureDate = new Date(fixedSystemCurrentDate);
systemFutureDate.setDate(systemFutureDate.getDate() + 5);

const futureDate = Time.dateWithDaysAdded(5);

expect(futureDate.getUTCDate()).toBe(systemFutureDate.getUTCDate());
});
});

describe('isToday()', () => {
it('When provided date is today, then returns true', () => {
const today = new Date();

const isToday = Time.isToday(today);

expect(isToday).toBe(true);
});

it('When provided date is another day, then returns false', () => {
const notToday = new Date();
notToday.setDate(notToday.getDate() + 1);

const isToday = Time.isToday(notToday);

expect(isToday).toBe(false);
});
});

describe('convertTimestampToDate()', () => {
it('When a date in timestamp is provided, then same date should be returned', () => {
const timestamp = 1642531200;

const timestampDate = Time.convertTimestampToDate(timestamp);

expect(timestampDate).toBeInstanceOf(Date);
expect(timestampDate).toEqual(new Date(timestamp * 1000));
});
});
});
13 changes: 13 additions & 0 deletions src/lib/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,17 @@ export class Time {
public static resumeTime(): void {
Time.freeze = null;
}

public static isToday = (date: Date) => {
const todayDate = new Date();
return (
date.getDate() === todayDate.getDate() &&
date.getMonth() === todayDate.getMonth() &&
date.getFullYear() === todayDate.getFullYear()
);
};

public static convertTimestampToDate = (timestamp: number) => {
return new Date(timestamp * 1000);
};
}
12 changes: 9 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ import {
SwaggerCustomOptions,
SwaggerModule,
} from '@nestjs/swagger';
import configuration from './config/configuration';
import { TransformInterceptor } from './lib/transform.interceptor';
import { RequestLoggerMiddleware } from './middlewares/requests-logger';
import { NestExpressApplication } from '@nestjs/platform-express';
import { AuthGuard } from './modules/auth/auth.guard';

const APP_PORT = process.env.PORT || 3000;
const config = configuration();
const APP_PORT = config.port || 3000;

async function bootstrap() {
const logger = new Logger();
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
Expand All @@ -41,7 +44,7 @@ async function bootstrap() {
// logger: WinstonLogger.getLogger(),
});

const enableTrustProxy = process.env.NODE_ENV === 'production';
const enableTrustProxy = config.isProduction;

app.set('trust proxy', enableTrustProxy);
app.useGlobalPipes(new ValidationPipe({ transform: true }));
Expand All @@ -50,7 +53,10 @@ async function bootstrap() {
app.use(helmet());
app.use(apiMetrics());

app.use(RequestLoggerMiddleware);
if (!config.isProduction) {
app.use(RequestLoggerMiddleware);
}

app.setGlobalPrefix('api');
app.disable('x-powered-by');
app.enableShutdownHooks();
Expand Down
Loading

0 comments on commit ec4de6c

Please sign in to comment.