Merge branch 'dev' into feature/124-testmail
All checks were successful
continuous-integration/drone/pr Build is passing

This commit is contained in:
Nicolai Ort 2021-01-27 17:47:29 +01:00
commit 38223b194b
6 changed files with 195 additions and 17 deletions

View File

@ -9,7 +9,6 @@ steps:
commands: commands:
- git clone $DRONE_REMOTE_URL . - git clone $DRONE_REMOTE_URL .
- git checkout $DRONE_SOURCE_BRANCH - git checkout $DRONE_SOURCE_BRANCH
- mv .env.ci .env
- name: run tests - name: run tests
image: node:latest image: node:latest
commands: commands:

View File

@ -2,9 +2,55 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v0.3.1](https://git.odit.services/lfk/backend/compare/v0.3.1...v0.3.1)
- Merge pull request 'Email Basics feature/118-emails' (#128) from feature/118-emails into dev [`348e6cd`](https://git.odit.services/lfk/backend/commit/348e6cdec7411345953243edfb5322a17ad7614d)
- Added pw reset template provided by @philipp [`c116338`](https://git.odit.services/lfk/backend/commit/c116338cd74cf726362f8fa0ae5eea7ec9fabac4)
- Implemented automatic ci env generation [`536de2a`](https://git.odit.services/lfk/backend/commit/536de2a3199b1befed54b6fe520a2e3fcefe0d90)
- Implemented a basic mailer with reset link sending [`6379753`](https://git.odit.services/lfk/backend/commit/637975305f1adf9bf505507790638cf1e229cfb1)
- Table fix [`1f0c842`](https://git.odit.services/lfk/backend/commit/1f0c842d9e086456f1ae0f6908e474258a04beb4)
- Added documentation for the env vars [`13ccab5`](https://git.odit.services/lfk/backend/commit/13ccab5e289d0a629cefb7fe281a85a46058ae97)
- Password reset now enforces email [`979d36e`](https://git.odit.services/lfk/backend/commit/979d36ea9147dc575e9e989f6833388828285176)
- Translated the pw reset mail to english [`5cade25`](https://git.odit.services/lfk/backend/commit/5cade25eeb137eb5890b3fd450646acfbdff2e8b)
- 🧾New changelog file version [CI SKIP] [skip ci] [`e07f258`](https://git.odit.services/lfk/backend/commit/e07f258a315898d1183c311e7fcd8f65a415504c)
- Merge pull request 'Mail+Env documentation feature/123-mail_documentation' (#129) from feature/123-mail_documentation into dev [`61bbeb0`](https://git.odit.services/lfk/backend/commit/61bbeb0d8f3fd6bfafb65bd11eb4c076a27b4a53)
- Implementes mail sending on pw reset request [`e26744b`](https://git.odit.services/lfk/backend/commit/e26744b7925d32d65ef4cc3911651758cfc9274f)
- Added a txt variant of the pw-reset mail [`d3647e3`](https://git.odit.services/lfk/backend/commit/d3647e339990d989dbca4d91aa8c3fe5789dd24a)
- Changed order [`583a4bc`](https://git.odit.services/lfk/backend/commit/583a4bc0dd0de8026bb2eb6a9b0c31f59344e813)
- The auth tests now use mail to identify the user [`c43334b`](https://git.odit.services/lfk/backend/commit/c43334bf96901bfd5116301ff7cf4b2ae1dfcbd3)
- Added the first mail error [`c418603`](https://git.odit.services/lfk/backend/commit/c4186034233a296b5971fbef16e7ef6809fbac51)
- Now also sending txt mail body [`b92f633`](https://git.odit.services/lfk/backend/commit/b92f633d68604636cecc5e9fdd0d6990b9cb83fe)
- Removed tests working directly with the old pw-reset response [`d02e9de`](https://git.odit.services/lfk/backend/commit/d02e9dec5637aedefdf2ed3cd2c6d73216b6464b)
- Added the basics about mail templates to the readme [`b5018eb`](https://git.odit.services/lfk/backend/commit/b5018eb11492884db9f4ec969c767c3cce53f105)
- Cleaned up the replacements [`389e423`](https://git.odit.services/lfk/backend/commit/389e423850d68a5fe440b62413a6c662353ac9c6)
- Added mail env vars [`d7ea928`](https://git.odit.services/lfk/backend/commit/d7ea928714f94814695cbd2815c8730df58033f6)
- Added a barebones class for handleing mail stuff [`cf012c0`](https://git.odit.services/lfk/backend/commit/cf012c0b7efffb81b03497a04b0fdad0423c72f7)
- Added env vars [`470703c`](https://git.odit.services/lfk/backend/commit/470703c4de954da94726879becd57986b59e1f69)
- 🧾New changelog file version [CI SKIP] [skip ci] [`2071c4d`](https://git.odit.services/lfk/backend/commit/2071c4db33bbb9fd41ef650b409cac789732225f)
- Added a hint to ethereal.email [`53fcff7`](https://git.odit.services/lfk/backend/commit/53fcff77d00fc2b205ada0bcee7bdfe83d94a9f4)
- Fixed missing app_url protocol [`46af786`](https://git.odit.services/lfk/backend/commit/46af7865165bbfb97ed3e6cdfef15dfb72add611)
- Removed the duplicate env copy/create from ci tests [`08e6e59`](https://git.odit.services/lfk/backend/commit/08e6e5965544906f5033f2080166bddc37cc30c7)
- Removed bs console.log [`71c4caa`](https://git.odit.services/lfk/backend/commit/71c4caae8ba67e253d893409b3c5c3a39b08060a)
- Added nodemailer types [`78d2ac3`](https://git.odit.services/lfk/backend/commit/78d2ac3027f7109161ee36e9b3dda628a7039468)
- Added nodemailer dependecy [`908ac4f`](https://git.odit.services/lfk/backend/commit/908ac4f1ce9d78749268353c668e67b57eae6f94)
- Fixed wrong file location [`b4c117b`](https://git.odit.services/lfk/backend/commit/b4c117b7dc326d212598b6e720d0a422134e383d)
- Renamed the template [`fb77f4d`](https://git.odit.services/lfk/backend/commit/fb77f4d798550fdb6fe6b2c8a81198db0328f71e)
- Added a folder for the mail templates [`6b0155f`](https://git.odit.services/lfk/backend/commit/6b0155f01464f5ef73ab679b9e3219743e9db66b)
- Added a folder for the mail templates [`33890b5`](https://git.odit.services/lfk/backend/commit/33890b544b77272ab1c4797e91375d24568eae58)
#### [v0.3.1](https://git.odit.services/lfk/backend/compare/v0.3.0...v0.3.1) #### [v0.3.1](https://git.odit.services/lfk/backend/compare/v0.3.0...v0.3.1)
> 27 January 2021
- Merge pull request 'Alpha Release 0.3.1' (#127) from dev into main [`20f960e`](https://git.odit.services/lfk/backend/commit/20f960ed6700fe58c0556895e6485d26c4a4f5e2)
- 🧾New changelog file version [CI SKIP] [skip ci] [`e6fe8fc`](https://git.odit.services/lfk/backend/commit/e6fe8fcd587751392970d3ee412559b4c1d60f21)
- Merge pull request 'new advanced endpoints feature/125-team_runner' (#126) from feature/125-team_runner into dev [`870fd47`](https://git.odit.services/lfk/backend/commit/870fd47c83389345d7b24a15df6a4e61e930d140)
- Added get runners by team test [`69417e9`](https://git.odit.services/lfk/backend/commit/69417e93c081422561db1e211b12f32e539010ce)
- 🧾New changelog file version [CI SKIP] [skip ci] [`71898d5`](https://git.odit.services/lfk/backend/commit/71898d576c2620d2f2e2b4336e62f1d04a443201) - 🧾New changelog file version [CI SKIP] [skip ci] [`71898d5`](https://git.odit.services/lfk/backend/commit/71898d576c2620d2f2e2b4336e62f1d04a443201)
- Created the organizations/runners endpoint [`570c34b`](https://git.odit.services/lfk/backend/commit/570c34bed04e359f389a8f427486bf92891f1dcb)
- Created the runnerTeam/runners endpoint [`7be2971`](https://git.odit.services/lfk/backend/commit/7be2971a9e02bf0e784f7fe5cdd82afbbbf7f854)
- 🧾New changelog file version [CI SKIP] [skip ci] [`aedfcfc`](https://git.odit.services/lfk/backend/commit/aedfcfcc8359afd7dba4fa5e515e8e77fbb3fc6e)
- Added get runners by org test [`f71a22f`](https://git.odit.services/lfk/backend/commit/f71a22f4dd9bf14d39ced91908f6f6a5d8395e56)
- 🚀Bumped version to v0.3.1 [`db08760`](https://git.odit.services/lfk/backend/commit/db0876015bf0599dabb21357f172735888c79aa8) - 🚀Bumped version to v0.3.1 [`db08760`](https://git.odit.services/lfk/backend/commit/db0876015bf0599dabb21357f172735888c79aa8)
#### [v0.3.0](https://git.odit.services/lfk/backend/compare/v0.2.1...v0.3.0) #### [v0.3.0](https://git.odit.services/lfk/backend/compare/v0.2.1...v0.3.0)

View File

@ -35,11 +35,41 @@ yarn test:watch
yarn test:ci yarn test:ci
``` ```
### Use your own mail templates
> You use your own mail templates by replacing the default ones we provided (either in-code or by mounting them into the /app/static/mail_templates folder).
The mail templates always come in a .html and a .txt variant to provide compatability with legacy mail clients.
Currently the following templates exist:
* pw-reset.(html/txt)
### Generate Docs ### Generate Docs
```bash ```bash
yarn docs yarn docs
``` ```
## ENV Vars
> You can provide them via .env file or docker env vars.
> You can use the `test:ci:generate_env` package script to generate a example env (uses [ethereal.email](https://ethereal.email) as the mailserver).
| Name | Type | Default | Description
| - | - | - | -
| APP_PORT | Number | 4010 | The port the backend server listens on. Is optional.
| DB_TYPE | String | N/A | The type of the db u want to use. It has to be supported by typeorm. Possible: `sqlite`, `mysql`, `postgresql`
| DB_HOST | String | N/A | The db's host's ip-address/fqdn or file path for sqlite
| DB_PORT | String | N/A | The db's port
| DB_USER | String | N/A | The user for accessing the db
| DB_PASSWORD | String | N/A | The user's password for accessing the db
| DB_NAME | String | N/A | The db's name
| NODE_ENV | String | dev | The apps env - influences debug info.
| POSTALCODE_COUNTRYCODE | String/CountryCode | N/A | The countrycode used to validate address's postal codes
| PHONE_COUNTRYCODE | String/CountryCode | null (international) | The countrycode used to validate phone numers
| SEED_TEST_DATA | Boolean | False | If you want the app to seed some example data set this to true
| MAIL_SERVER | String | N/A | The smtp server's ip-address/fqdn
| MAIL_PORT | String | N/A | The smtp server's port
| MAIL_USER | String | N/A | The username for sending mails
| MAIL_PASSWORD | String | N/A | The user's password for sending mails
| MAIL_FROM | String | N/A | The from-address for sending mails
## Recommended Editor ## Recommended Editor
[Visual Studio Code](https://code.visualstudio.com/) [Visual Studio Code](https://code.visualstudio.com/)

View File

@ -4,8 +4,10 @@ import { getConnectionManager, Repository } from 'typeorm';
import { RunnerOrganizationHasRunnersError, RunnerOrganizationHasTeamsError, RunnerOrganizationIdsNotMatchingError, RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors'; import { RunnerOrganizationHasRunnersError, RunnerOrganizationHasTeamsError, RunnerOrganizationIdsNotMatchingError, RunnerOrganizationNotFoundError } from '../errors/RunnerOrganizationErrors';
import { CreateRunnerOrganization } from '../models/actions/create/CreateRunnerOrganization'; import { CreateRunnerOrganization } from '../models/actions/create/CreateRunnerOrganization';
import { UpdateRunnerOrganization } from '../models/actions/update/UpdateRunnerOrganization'; import { UpdateRunnerOrganization } from '../models/actions/update/UpdateRunnerOrganization';
import { Runner } from '../models/entities/Runner';
import { RunnerOrganization } from '../models/entities/RunnerOrganization'; import { RunnerOrganization } from '../models/entities/RunnerOrganization';
import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseRunner } from '../models/responses/ResponseRunner';
import { ResponseRunnerOrganization } from '../models/responses/ResponseRunnerOrganization'; import { ResponseRunnerOrganization } from '../models/responses/ResponseRunnerOrganization';
import { RunnerController } from './RunnerController'; import { RunnerController } from './RunnerController';
import { RunnerTeamController } from './RunnerTeamController'; import { RunnerTeamController } from './RunnerTeamController';
@ -48,6 +50,22 @@ export class RunnerOrganizationController {
return new ResponseRunnerOrganization(runnerOrg); return new ResponseRunnerOrganization(runnerOrg);
} }
@Get('/:id/runners')
@Authorized(["RUNNER:GET", "SCAN:GET"])
@ResponseSchema(ResponseRunner, { isArray: true })
@ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Lists all runners from this org and it\'s teams (if you don\'t provide the ?onlyDirect=true param). <br> This includes the runner\'s group and distance ran.' })
async getRunners(@Param('id') id: number, @QueryParam('onlyDirect') onlyDirect: boolean) {
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
let runners: Runner[];
if (!onlyDirect) { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.scans', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.group', 'teams.runners.scans', 'teams.runners.scans.track'] })).allRunners; }
else { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.scans', 'runners.scans.track'] })).runners; }
runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner));
});
return responseRunners;
}
@Post() @Post()
@Authorized("ORGANIZATION:CREATE") @Authorized("ORGANIZATION:CREATE")
@ResponseSchema(ResponseRunnerOrganization) @ResponseSchema(ResponseRunnerOrganization)

View File

@ -6,6 +6,7 @@ import { CreateRunnerTeam } from '../models/actions/create/CreateRunnerTeam';
import { UpdateRunnerTeam } from '../models/actions/update/UpdateRunnerTeam'; import { UpdateRunnerTeam } from '../models/actions/update/UpdateRunnerTeam';
import { RunnerTeam } from '../models/entities/RunnerTeam'; import { RunnerTeam } from '../models/entities/RunnerTeam';
import { ResponseEmpty } from '../models/responses/ResponseEmpty'; import { ResponseEmpty } from '../models/responses/ResponseEmpty';
import { ResponseRunner } from '../models/responses/ResponseRunner';
import { ResponseRunnerTeam } from '../models/responses/ResponseRunnerTeam'; import { ResponseRunnerTeam } from '../models/responses/ResponseRunnerTeam';
import { RunnerController } from './RunnerController'; import { RunnerController } from './RunnerController';
@ -47,6 +48,20 @@ export class RunnerTeamController {
return new ResponseRunnerTeam(runnerTeam); return new ResponseRunnerTeam(runnerTeam);
} }
@Get('/:id/runners')
@Authorized(["RUNNER:GET", "SCAN:GET"])
@ResponseSchema(ResponseRunner, { isArray: true })
@ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 })
@OpenAPI({ description: 'Lists all runners from this team. <br> This includes the runner\'s group and distance ran.' })
async getRunners(@Param('id') id: number) {
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
const runners = (await this.runnerTeamRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.scans', 'runners.scans.track'] })).runners;
runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner));
});
return responseRunners;
}
@Post() @Post()
@Authorized("TEAM:CREATE") @Authorized("TEAM:CREATE")
@ResponseSchema(ResponseRunnerTeam) @ResponseSchema(ResponseRunnerTeam)

View File

@ -33,36 +33,106 @@ describe('GET /api/runners after adding', () => {
let added_org_id; let added_org_id;
let added_runner; let added_runner;
it('creating a new org with just a name should return 200', async () => { it('creating a new org with just a name should return 200', async () => {
const res1 = await axios.post(base + '/api/organizations', { const res = await axios.post(base + '/api/organizations', {
"name": "test123" "name": "test123"
}, axios_config); }, axios_config);
let added_org = res1.data let added_org = res.data
added_org_id = added_org.id; added_org_id = added_org.id;
expect(res1.status).toEqual(200); expect(res.status).toEqual(200);
expect(res1.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('creating a new runner with only needed params should return 200', async () => { it('creating a new runner with only needed params should return 200', async () => {
const res2 = await axios.post(base + '/api/runners', { const res = await axios.post(base + '/api/runners', {
"firstname": "first", "firstname": "first",
"lastname": "last", "lastname": "last",
"group": added_org_id "group": added_org_id
}, axios_config); }, axios_config);
added_runner = res2.data; added_runner = res.data;
expect(res2.status).toEqual(200); expect(res.status).toEqual(200);
expect(res2.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
}); });
it('explicit get should return 200', async () => { it('explicit get should return 200', async () => {
const res3 = await axios.get(base + '/api/runners/' + added_runner.id, axios_config); const res = await axios.get(base + '/api/runners/' + added_runner.id, axios_config);
expect(res3.status).toEqual(200); expect(res.status).toEqual(200);
expect(res3.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
let gotten_runner = res3.data let gotten_runner = res.data
expect(gotten_runner).toEqual(added_runner); expect(gotten_runner).toEqual(added_runner);
}); });
it('get from all runners should return 200', async () => { it('get from all runners should return 200', async () => {
const res4 = await axios.get(base + '/api/runners/', axios_config); const res = await axios.get(base + '/api/runners/', axios_config);
expect(res4.status).toEqual(200); expect(res.status).toEqual(200);
expect(res4.headers['content-type']).toContain("application/json") expect(res.headers['content-type']).toContain("application/json")
let gotten_runners = res4.data let gotten_runners = res.data
expect(gotten_runners).toContainEqual(added_runner); expect(gotten_runners).toContainEqual(added_runner);
}); });
});
// ---------------
describe('GET /api/organizations/:id/runners after adding', () => {
let added_org_id;
let added_runner;
it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organizations', {
"name": "test123"
}, axios_config);
let added_org = res.data
added_org_id = added_org.id;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('creating a new runner with only needed params should return 200', async () => {
const res = await axios.post(base + '/api/runners', {
"firstname": "first",
"lastname": "last",
"group": added_org_id
}, axios_config);
added_runner = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('check if scans was added via the orgs/runners endpoint.', async () => {
const res = await axios.get(base + '/api/organizations/' + added_org_id + "/runners", axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
expect(res.data).toContainEqual(added_runner);
});
});
// ---------------
describe('GET /api/teams/:id/runners after adding', () => {
let added_org_id;
let added_team;
let added_runner;
it('creating a new org with just a name should return 200', async () => {
const res = await axios.post(base + '/api/organizations', {
"name": "test123"
}, axios_config);
let added_org = res.data
added_org_id = added_org.id;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('creating a new team with a parent org should return 200', async () => {
const res = await axios.post(base + '/api/teams', {
"name": "test_team",
"parentGroup": added_org_id
}, axios_config);
added_team = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('creating a new runner with only needed params should return 200', async () => {
const res = await axios.post(base + '/api/runners', {
"firstname": "first",
"lastname": "last",
"group": added_team.id
}, axios_config);
added_runner = res.data;
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json")
});
it('check if scans was added via the orgs/runners endpoint.', async () => {
const res = await axios.get(base + '/api/teams/' + added_team.id + "/runners", axios_config);
expect(res.status).toEqual(200);
expect(res.headers['content-type']).toContain("application/json");
expect(res.data).toContainEqual(added_runner);
});
}); });