diff --git a/api/.gitignore b/api/.gitignore new file mode 100644 index 00000000..5add9449 --- /dev/null +++ b/api/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/yarn.lock diff --git a/api/.prettierrc b/api/.prettierrc new file mode 100644 index 00000000..dcb72794 --- /dev/null +++ b/api/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} \ No newline at end of file diff --git a/api/README.md b/api/README.md new file mode 100644 index 00000000..6f6c6037 --- /dev/null +++ b/api/README.md @@ -0,0 +1,55 @@ +

+ OhMyForm Logo +

+ +## Description + +[OhMyForm](https://github.com/ohmyforn) api backend + +## Installation + +```bash +$ yarn install +``` + +## Running the app + +```bash +# development +$ npm run start + +# watch mode +$ npm run start:dev + +# incremental rebuild (webpack) +$ npm run webpack +$ npm run start:hmr + +# production mode +$ npm run start:prod +``` + +## Test + +```bash +# unit tests +$ npm run test + +# e2e tests +$ npm run test:e2e + +# test coverage +$ npm run test:cov +``` + +## Support + +TODO + +## Stay in touch + +- Website - [https://ohmyform.com](https://ohmyform.com/) + +## License + +TODO diff --git a/api/nest-cli.json b/api/nest-cli.json new file mode 100644 index 00000000..0dde5f8c --- /dev/null +++ b/api/nest-cli.json @@ -0,0 +1,5 @@ +{ + "language": "ts", + "collection": "@nestjs/schematics", + "sourceRoot": "src" +} diff --git a/api/nodemon-debug.json b/api/nodemon-debug.json new file mode 100644 index 00000000..7caf94b0 --- /dev/null +++ b/api/nodemon-debug.json @@ -0,0 +1,6 @@ +{ + "watch": ["src"], + "ext": "ts", + "ignore": ["src/**/*.spec.ts"], + "exec": "node --inspect-brk -r ts-node/register src/main.ts" +} \ No newline at end of file diff --git a/api/nodemon.json b/api/nodemon.json new file mode 100644 index 00000000..583bb426 --- /dev/null +++ b/api/nodemon.json @@ -0,0 +1,6 @@ +{ + "watch": ["src"], + "ext": "ts", + "ignore": ["src/**/*.spec.ts"], + "exec": "ts-node -r tsconfig-paths/register src/main.ts" +} diff --git a/api/package.json b/api/package.json new file mode 100644 index 00000000..c76a2102 --- /dev/null +++ b/api/package.json @@ -0,0 +1,66 @@ +{ + "name": "ohmyform", + "version": "0.1.0", + "description": "Opensource alternative to TypeForm", + "author": "multiple", + "license": "MIT", + "scripts": { + "build": "rimraf dist && tsc -p tsconfig.build.json", + "format": "prettier --write \"src/**/*.ts\"", + "start": "ts-node -r tsconfig-paths/register src/main.ts", + "start:dev": "tsc-watch -p tsconfig.build.json --onSuccess \"node dist/main.js\"", + "start:debug": "tsc-watch -p tsconfig.build.json --onSuccess \"node --inspect-brk dist/main.js\"", + "start:prod": "node dist/main.js", + "lint": "tslint -p tsconfig.json -c tslint.json", + "test": "jest", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json" + }, + "dependencies": { + "@godaddy/terminus": "^4.1.2", + "@nestjs/common": "^6.0.0", + "@nestjs/core": "^6.0.0", + "@nestjs/mongoose": "^6.1.2", + "@nestjs/platform-express": "^6.0.0", + "@nestjs/swagger": "^3.1.0", + "@nestjs/terminus": "^6.5.0", + "@types/mongoose": "^5.5.11", + "mongoose": "^5.6.7", + "reflect-metadata": "^0.1.12", + "rimraf": "^2.6.2", + "rxjs": "^6.3.3", + "swagger-ui-express": "^4.0.7" + }, + "devDependencies": { + "@nestjs/testing": "6.1.1", + "@types/express": "4.16.1", + "@types/jest": "24.0.11", + "@types/node": "11.13.4", + "@types/supertest": "2.0.7", + "jest": "24.7.1", + "prettier": "1.17.0", + "supertest": "4.0.2", + "ts-jest": "24.0.2", + "ts-node": "8.1.0", + "tsc-watch": "2.2.1", + "tsconfig-paths": "3.8.0", + "tslint": "5.16.0", + "typescript": "3.4.3" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": "src", + "testRegex": ".spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } +} diff --git a/api/src/app.controller.spec.ts b/api/src/app.controller.spec.ts new file mode 100644 index 00000000..d22f3890 --- /dev/null +++ b/api/src/app.controller.spec.ts @@ -0,0 +1,22 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; + +describe('AppController', () => { + let appController: AppController; + + beforeEach(async () => { + const app: TestingModule = await Test.createTestingModule({ + controllers: [AppController], + providers: [AppService], + }).compile(); + + appController = app.get(AppController); + }); + + describe('root', () => { + it('should return "Hello World!"', () => { + expect(appController.getHello()).toBe('Hello World!'); + }); + }); +}); diff --git a/api/src/app.controller.ts b/api/src/app.controller.ts new file mode 100644 index 00000000..cce879ee --- /dev/null +++ b/api/src/app.controller.ts @@ -0,0 +1,12 @@ +import { Controller, Get } from '@nestjs/common'; +import { AppService } from './app.service'; + +@Controller() +export class AppController { + constructor(private readonly appService: AppService) {} + + @Get() + getHello(): string { + return this.appService.getHello(); + } +} diff --git a/api/src/app.module.ts b/api/src/app.module.ts new file mode 100644 index 00000000..26a16ed0 --- /dev/null +++ b/api/src/app.module.ts @@ -0,0 +1,22 @@ +import { Module } from '@nestjs/common'; +import { TerminusModule } from '@nestjs/terminus'; +import { MongooseModule } from '@nestjs/mongoose'; +import { TerminusOptionsService } from './terminus-options.service'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; +import {UsersModule} from "./users/users.module" +import {FormsModule} from "./forms/forms.module" + +@Module({ + imports: [ + MongooseModule.forRoot('mongodb://localhost/nest'), + TerminusModule.forRootAsync({ + useClass: TerminusOptionsService, + }), + UsersModule, + FormsModule, + ], + controllers: [AppController], + providers: [AppService], +}) +export class AppModule {} diff --git a/api/src/app.service.ts b/api/src/app.service.ts new file mode 100644 index 00000000..927d7cca --- /dev/null +++ b/api/src/app.service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class AppService { + getHello(): string { + return 'Hello World!'; + } +} diff --git a/api/src/forms/forms.module.ts b/api/src/forms/forms.module.ts new file mode 100644 index 00000000..ad6d579c --- /dev/null +++ b/api/src/forms/forms.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; + +@Module({ + providers: [], + exports: [], +}) +export class FormsModule {} diff --git a/api/src/main.ts b/api/src/main.ts new file mode 100644 index 00000000..1e7989a5 --- /dev/null +++ b/api/src/main.ts @@ -0,0 +1,22 @@ +import { NestFactory } from '@nestjs/core'; +import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; +import { AppModule } from './app.module'; + +const pkg = require('../package.json') + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + + const options = new DocumentBuilder() + .setTitle('OhMyForm') + .setDescription('API documentation') + .setVersion(pkg.version) + .build(); + + const document = SwaggerModule.createDocument(app, options); + SwaggerModule.setup('doc', app, document); + + await app.listen(3000); +} + +bootstrap(); diff --git a/api/src/terminus-options.service.ts b/api/src/terminus-options.service.ts new file mode 100644 index 00000000..5346b416 --- /dev/null +++ b/api/src/terminus-options.service.ts @@ -0,0 +1,29 @@ +import { + TerminusEndpoint, + TerminusOptionsFactory, + DNSHealthIndicator, + MongooseHealthIndicator, + TerminusModuleOptions +} from '@nestjs/terminus'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class TerminusOptionsService implements TerminusOptionsFactory { + constructor( + private readonly dns: DNSHealthIndicator, + private readonly mongoose: MongooseHealthIndicator + ) {} + + createTerminusOptions(): TerminusModuleOptions { + const healthEndpoint: TerminusEndpoint = { + url: '/health', + healthIndicators: [ + async () => this.dns.pingCheck('mail', 'https://google.com'), + async () => this.mongoose.pingCheck('mongo') + ], + }; + return { + endpoints: [healthEndpoint], + }; + } +} diff --git a/api/src/users/users.module.ts b/api/src/users/users.module.ts new file mode 100644 index 00000000..fa1c4450 --- /dev/null +++ b/api/src/users/users.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; + +@Module({ + providers: [], + exports: [], +}) +export class UsersModule {} diff --git a/api/tsconfig.build.json b/api/tsconfig.build.json new file mode 100644 index 00000000..64f86c6b --- /dev/null +++ b/api/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] +} diff --git a/api/tsconfig.json b/api/tsconfig.json new file mode 100644 index 00000000..69f185fd --- /dev/null +++ b/api/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es2017", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true + }, + "exclude": ["node_modules", "dist"] +} diff --git a/api/tslint.json b/api/tslint.json new file mode 100644 index 00000000..e66f0a4a --- /dev/null +++ b/api/tslint.json @@ -0,0 +1,55 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": { + "no-unused-expression": true + }, + "rules": { + "eofline": false, + "quotemark": [ + true, + "single" + ], + "indent": false, + "member-access": [ + false + ], + "ordered-imports": [ + false + ], + "max-line-length": [ + true, + 150 + ], + "member-ordering": [ + false + ], + "curly": false, + "interface-name": [ + false + ], + "array-type": [ + false + ], + "no-empty-interface": false, + "no-empty": false, + "arrow-parens": false, + "object-literal-sort-keys": false, + "no-unused-expression": false, + "max-classes-per-file": [ + false + ], + "variable-name": [ + false + ], + "one-line": [ + false + ], + "one-variable-per-declaration": [ + false + ] + }, + "rulesDirectory": [] +}