diff --git a/.husky/pre-commit b/.husky/pre-commit index e3db172b4a..dba9310457 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -# npm run lint +npm run lint \ No newline at end of file diff --git a/Common/Tests/TestingUtils/Faker.ts b/Common/Tests/TestingUtils/Faker.ts index 49ca94f070..91700c4d2f 100644 --- a/Common/Tests/TestingUtils/Faker.ts +++ b/Common/Tests/TestingUtils/Faker.ts @@ -25,6 +25,6 @@ export default class Faker { } public static generatePhone(): Phone { - return new Phone(faker.phone.phoneNumber()); + return new Phone(faker.phone.phoneNumberFormat()); } } diff --git a/Common/Tests/Types/Database/ColumnLength.test.ts b/Common/Tests/Types/Database/ColumnLength.test.ts new file mode 100644 index 0000000000..1c663b810e --- /dev/null +++ b/Common/Tests/Types/Database/ColumnLength.test.ts @@ -0,0 +1,55 @@ +import ColumnLength from '../../../Types/Database/ColumnLength'; + +describe('enum ColumnLength', () => { + test('ColumnLength.Version', () => { + expect(ColumnLength.Version).toEqual(30); + }); + + test('ColumnLength.Slug', () => { + expect(ColumnLength.Slug).toEqual(100); + }); + + test('ColumnLength.Email', () => { + expect(ColumnLength.Email).toEqual(100); + }); + + test('ColumnLength.Color', () => { + expect(ColumnLength.Color).toEqual(7); + }); + + test('ColumnLength.Name', () => { + expect(ColumnLength.Name).toEqual(50); + }); + + test('ColumnLength.Description', () => { + expect(ColumnLength.Description).toEqual(500); + }); + + test('ColumnLength.LongText', () => { + expect(ColumnLength.LongText).toEqual(500); + }); + + test('ColumnLength.Password', () => { + expect(ColumnLength.Password).toEqual(500); + }); + + test('ColumnLength.ShortURL', () => { + expect(ColumnLength.ShortURL).toEqual(100); + }); + + test('ColumnLength.ShortText', () => { + expect(ColumnLength.ShortText).toEqual(100); + }); + + test('ColumnLength.HashedString', () => { + expect(ColumnLength.HashedString).toEqual(64); + }); + + test('ColumnLength.Phone', () => { + expect(ColumnLength.Phone).toEqual(30); + }); + + test('ColumnLength.OTP', () => { + expect(ColumnLength.OTP).toEqual(8); + }); +}); diff --git a/Common/Tests/Types/Database/ColumnType.test.ts b/Common/Tests/Types/Database/ColumnType.test.ts new file mode 100644 index 0000000000..54685db5df --- /dev/null +++ b/Common/Tests/Types/Database/ColumnType.test.ts @@ -0,0 +1,103 @@ +import ColumnType from '../../../Types/Database/ColumnType'; + +describe('enum ColumnType', () => { + test('ColumnType.Color should be varchar', () => { + expect(ColumnType.Color).toEqual('varchar'); + }); + + test('ColumnType.Version', () => { + expect(ColumnType.Version).toEqual('varchar'); + }); + + test('ColumnType.Phone', () => { + expect(ColumnType.Phone).toEqual('varchar'); + }); + + test('ColumnType.HashedString', () => { + expect(ColumnType.HashedString).toEqual('varchar'); + }); + + test('ColumnType.Password', () => { + expect(ColumnType.Password).toEqual('varchar'); + }); + + test('ColumnType.Email', () => { + expect(ColumnType.Email).toEqual('varchar'); + }); + + test('ColumnType.Slug', () => { + expect(ColumnType.Slug).toEqual('varchar'); + }); + + test('ColumnType.Name', () => { + expect(ColumnType.Name).toEqual('varchar'); + }); + + test('ColumnType.Description', () => { + expect(ColumnType.Description).toEqual('varchar'); + }); + + test('ColumnType.ObjectID', () => { + expect(ColumnType.ObjectID).toEqual('uuid'); + }); + + test('ColumnType.ShortURL', () => { + expect(ColumnType.ShortURL).toEqual('varchar'); + }); + + test('ColumnType.LongURL', () => { + expect(ColumnType.LongURL).toEqual('text'); + }); + + test('ColumnType.ShortText', () => { + expect(ColumnType.ShortText).toEqual('varchar'); + }); + + test('ColumnType.OTP', () => { + expect(ColumnType.OTP).toEqual('varchar'); + }); + + test('ColumnType.LongText', () => { + expect(ColumnType.LongText).toEqual('varchar'); + }); + + test('ColumnType.VeryLongText', () => { + expect(ColumnType.VeryLongText).toEqual('text'); + }); + + test('ColumnType.Date', () => { + expect(ColumnType.Date).toEqual('timestamptz'); + }); + + test('ColumnType.Boolean', () => { + expect(ColumnType.Boolean).toEqual('boolean'); + }); + + test('ColumnType.Array', () => { + expect(ColumnType.Array).toEqual('simple-array'); + }); + + test('ColumnType.SmallPositiveNumber', () => { + expect(ColumnType.SmallPositiveNumber).toEqual('smallint'); + }); + + test('ColumnType.PositiveNumber', () => { + expect(ColumnType.PositiveNumber).toEqual('integer'); + }); + + test('ColumnType.BigPositiveNumber', () => { + expect(ColumnType.BigPositiveNumber).toEqual('bigint'); + }); + + test('ColumnType.SmallNumber', () => { + expect(ColumnType.SmallNumber).toEqual('smallint'); + }); + + test('ColumnType.Number', () => { + expect(ColumnType.Number).toEqual('integer'); + }); + + test('ColumnType.BigNumber', () => { + expect(ColumnType.BigNumber).toEqual('bigint'); + }); +}); diff --git a/Common/Tests/Types/Database/Columns.test.ts b/Common/Tests/Types/Database/Columns.test.ts new file mode 100644 index 0000000000..abdfd7fae6 --- /dev/null +++ b/Common/Tests/Types/Database/Columns.test.ts @@ -0,0 +1,22 @@ +import Columns from '../../../Types/Database/Columns'; + +describe('class Columns', () => { + test('it should return a valid object if Columns is valid', () => { + expect(new Columns(['col1', 'col2'])).toBeInstanceOf(Columns); + expect(new Columns(['col1', 'col2']).columns).toStrictEqual([ + 'col1', + 'col2', + ]); + }); + + test('it should add column', () => { + const cols: Array = ['col1', 'col2']; + new Columns(cols).addColumn('col3'); + expect(new Columns(cols).columns).toContain('col3'); + }); + + test('it should return true if column is inckuded', () => { + const cols: Array = ['col1', 'col2']; + expect(new Columns(cols).hasColumn('col2')).toBeTruthy(); + }); +}); diff --git a/Common/Tests/Types/Database/LimitMax.test.ts b/Common/Tests/Types/Database/LimitMax.test.ts new file mode 100644 index 0000000000..4f8a4544e8 --- /dev/null +++ b/Common/Tests/Types/Database/LimitMax.test.ts @@ -0,0 +1,19 @@ +import LIMIT_MAX, { LIMIT_PER_PROJECT } from '../../../Types/Database/LimitMax'; + +describe('LIMIT_MAX', () => { + test('it should ', () => { + expect(LIMIT_MAX).toEqual(1000); + }); +}); + +describe('LIMIT_MAX', () => { + test('it should have a value', () => { + expect(LIMIT_MAX).toEqual(1000); + }); +}); + +describe('LIMIT_PER_PROJECT', () => { + test('it should have a value ', () => { + expect(LIMIT_PER_PROJECT).toEqual(100); + }); +}); diff --git a/Common/Tests/Types/Phone.test.ts b/Common/Tests/Types/Phone.test.ts new file mode 100644 index 0000000000..dc53474eb4 --- /dev/null +++ b/Common/Tests/Types/Phone.test.ts @@ -0,0 +1,37 @@ +import BadDataException from '../../Types/Exception/BadDataException'; +import Phone from '../../Types/Phone'; + +describe('Testing Class Phone', () => { + test('Should create a phone if the phone is valid phone number', () => { + expect(new Phone('+251912974103').toString()).toEqual('+251912974103'); + expect(new Phone('961-770-7727').phone).toEqual('961-770-7727'); + expect(new Phone('943-627-0355').phone).toEqual('943-627-0355'); + expect(new Phone('282.652.3201').phone).toEqual('282.652.3201'); + }); + + test('Phone.phone should be mutatable', () => { + const value: Phone = new Phone('+251912974103'); + value.phone = '+251925974121'; + expect(value.phone).toEqual('+251925974121'); + expect(value.toString()).toEqual('+251925974121'); + }); + + test('Creating phone number with invalid format should throw BadDataException', () => { + expect(() => { + new Phone('25192599879079074121'); + }).toThrowError(BadDataException); + }); + + test('try to mutating Phone.phone with invalid value should throw an BadDataExcepection', () => { + const value: Phone = new Phone('+251912974103'); + expect(() => { + value.phone = '567'; + }).toThrowError(BadDataException); + expect(() => { + value.phone = '278@$90> '; + }).toThrow('Phone is not in valid format.'); + expect(() => { + value.phone = 'hgjuit879'; + }).toThrowError(BadDataException); + }); +}); diff --git a/Common/Tests/Types/Port.test.ts b/Common/Tests/Types/Port.test.ts new file mode 100644 index 0000000000..907d126cb1 --- /dev/null +++ b/Common/Tests/Types/Port.test.ts @@ -0,0 +1,39 @@ +import BadDataException from '../../Types/Exception/BadDataException'; +import Port from '../../Types/Port'; +import PositiveNumber from '../../Types/PositiveNumber'; + +describe('Testing class port', () => { + test('should return a posetive number', () => { + const value: Port = new Port(3000); + expect(value.port.positiveNumber).toBeGreaterThanOrEqual(0); + expect(new Port('6000').port.positiveNumber).toEqual(6000); + }); + + test('should throw exception "Port should be in the range from 0 to 65535"', () => { + expect(() => { + new Port(67000); + }).toThrow('Port should be in the range from 0 to 65535'); + }); + + test('Port.port should be mutatable', () => { + const value: Port = new Port(5000); + value.port = new PositiveNumber(7000); + expect(value.port.positiveNumber).toEqual(7000); + expect(value.port.toNumber()).toEqual(7000); + }); + + test('try to mutating Port.port with invalid value should throw an BadDataExcepection', () => { + const value: Port = new Port(3000); + expect(() => { + value.port = new PositiveNumber('hj567'); + }).toThrowError(BadDataException); + expect(() => { + value.port = new PositiveNumber(-6000); + }).toThrow(BadDataException); + }); + + test('If the supplied port is string type, is should convert it to number before creating port', () => { + const value: Port = new Port('6000'); + expect(typeof value.port.positiveNumber).toBe('number'); + }); +}); diff --git a/Common/Types/Phone.ts b/Common/Types/Phone.ts index be544f1e69..64607597fc 100644 --- a/Common/Types/Phone.ts +++ b/Common/Types/Phone.ts @@ -1,5 +1,6 @@ import { FindOperator } from 'typeorm'; import DatabaseProperty from './Database/DatabaseProperty'; +import BadDataException from './Exception/BadDataException'; export default class Phone extends DatabaseProperty { private _phone: string = ''; @@ -16,6 +17,12 @@ export default class Phone extends DatabaseProperty { * throw new BadDataException('Phone is not in valid format.'); * } */ + const re: RegExp = + /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/; // regex for international phone numbers format based on (ITU-T E.123) + const isValid: boolean = re.test(v); + if (!isValid) { + throw new BadDataException('Phone is not in valid format.'); + } this._phone = v; } diff --git a/Common/package-lock.json b/Common/package-lock.json index c45076e30b..2c29b07e53 100644 --- a/Common/package-lock.json +++ b/Common/package-lock.json @@ -872,9 +872,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -2434,40 +2434,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dev": true, - "dependencies": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, "node_modules/jest-config": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", @@ -2993,6 +2959,40 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jest/node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5207,9 +5207,9 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", @@ -6334,6 +6334,28 @@ "@jest/core": "^27.5.1", "import-local": "^3.0.2", "jest-cli": "^27.5.1" + }, + "dependencies": { + "jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "requires": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + } + } } }, "jest-changed-files": { @@ -6374,26 +6396,6 @@ "throat": "^6.0.1" } }, - "jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dev": true, - "requires": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - } - }, "jest-config": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", diff --git a/File/package-lock.json b/File/package-lock.json new file mode 100644 index 0000000000..ad9b6aece9 --- /dev/null +++ b/File/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "file", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "file", + "version": "1.0.0", + "license": "MIT" + } + } +} diff --git a/README.md b/README.md index ec60329d15..0671bb7779 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ All under one platform. ## Contents -- [Introduction](/docs/introduction.md) -- [Concept](/docs/concept.md) -- [Architecture](/docs/architecture.md) -- [How OneUptime Works](/docs/how-oneuptime-works-overview) -- [Subproject Description](/docs/project-description.md) -- [Running OneUptime](/docs/run.md) -- [Running tests](/docs/running-tests.md) -- [Deployment](/docs/deployment.md) +- [Introduction](/Docs/introduction.md) +- [Concept](/Docs/concept.md) +- [Architecture](/Docs/architecture.md) +- [How OneUptime Works](/Docs/how-oneuptime-works-overview) +- [Subproject Description](/Docs/project-description.md) +- [Running OneUptime](/Docs/run.md) +- [Running tests](/Docs/running-tests.md) +- [Deployment](/Docs/deployment.md) # Contribute