Skip to content

Commit a022564

Browse files
authored
Merge pull request #148 from Patowhiz/pwa
Fixes bugs and makes data checking improvements
2 parents 41aa473 + 18c5774 commit a022564

File tree

65 files changed

+694
-532
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+694
-532
lines changed

back-end/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "api",
3-
"version": "preview-2.0.0",
3+
"version": "preview-2.0.1",
44
"description": "Climsoft API",
55
"author": "Climsoft Foundation",
66
"private": true,

back-end/api/src/main.ts

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { NestFactory } from '@nestjs/core';
22
import { AppModule } from './app.module';
3-
import { ValidationPipe } from '@nestjs/common';
3+
import { ValidationPipe } from '@nestjs/common';
44
import { AppConfig } from './app.config';
55
import * as session from 'express-session';
66
import * as pgSession from 'connect-pg-simple';
77
import { Pool } from 'pg';
8+
import * as express from 'express';
89

910
async function bootstrap() {
1011
const app = await NestFactory.create(AppModule);
@@ -23,11 +24,11 @@ async function bootstrap() {
2324
// origin: process.env.WEB_APP_BASE_URLs ? process.env.WEB_APP_BASE_URLs : 'http://localhost:4200' ,
2425
origin: (origin, callback) => {
2526
//console.log(`Client Origin - ${origin}`);
26-
27+
2728
// TODO. In future implement CORs security feature to enable users to determine origin setting based on their security requirements.
2829
callback(null, true); // Allow the request
29-
30-
30+
31+
3132
// TODO Code below is meant to enfors allowed origins
3233
// Allow requests with no `Origin` (e.g., from desktop and mobile apps)
3334
// Only allows requests from trusted web app origins. This is needed because web browsers require it
@@ -77,21 +78,11 @@ async function bootstrap() {
7778
}),
7879
);
7980

80-
// Left here for reference. This uses the default MemoryStore that is not designed for production
81-
// app.use(
82-
// session({
83-
// name: 'ssid',
84-
// secret: AppConfig.dbCredentials.password,
85-
// resave: false,
86-
// saveUninitialized: false,
87-
// cookie: {
88-
// maxAge: 1000 * 60 * 60 * 24, // set to 24 hours
89-
// sameSite: false,
90-
// secure: false //TODO set to true only when using HTTPS
91-
// },
92-
// }),
93-
// );
81+
// Increase the allowed payload request from the default 100kb to 1MB
82+
app.use(express.json({ limit: '1mb' }));
83+
app.use(express.urlencoded({ limit: '1mb', extended: true }));
9484

85+
// Set the port to listen for connections
9586
await app.listen(3000);
9687
}
9788

back-end/api/src/metadata/source-templates/services/source-templates.service.ts

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,28 +93,32 @@ export class SourceTemplatesService {
9393

9494
await this.sourceRepo.save(entity);
9595

96-
this.eventEmitter.emit('source.created', { id: entity.id, dto });
96+
const viewDto: ViewSourceDto = this.createViewDto(entity);
9797

98-
return this.createViewDto(entity);
98+
this.eventEmitter.emit('source.created', { id: entity.id, viewDto });
99+
100+
return viewDto;
99101

100102
}
101103

102-
public async update(id: number, dto: CreateUpdateSourceDto, userId: number) {
103-
const source = await this.findEntity(id);
104-
source.name = dto.name;
105-
source.description = dto.description;
106-
source.sourceType = dto.sourceType;
107-
source.utcOffset = dto.utcOffset;
108-
source.allowMissingValue = dto.allowMissingValue;
109-
source.sampleImage = dto.sampleImage;
110-
source.parameters = dto.parameters;
111-
source.entryUserId = userId;
104+
public async update(id: number, dto: CreateUpdateSourceDto, userId: number): Promise<ViewSourceDto> {
105+
const entity = await this.findEntity(id);
106+
entity.name = dto.name;
107+
entity.description = dto.description;
108+
entity.sourceType = dto.sourceType;
109+
entity.utcOffset = dto.utcOffset;
110+
entity.allowMissingValue = dto.allowMissingValue;
111+
entity.sampleImage = dto.sampleImage;
112+
entity.parameters = dto.parameters;
113+
entity.entryUserId = userId;
114+
115+
await this.sourceRepo.save(entity);
112116

113-
await this.sourceRepo.save(source);
117+
const viewDto: ViewSourceDto = this.createViewDto(entity);
114118

115-
this.eventEmitter.emit('source.updated', { id, dto });
119+
this.eventEmitter.emit('source.updated', { id, viewDto });
116120

117-
return source;
121+
return viewDto;
118122
}
119123

120124
public async delete(id: number): Promise<number> {
@@ -132,7 +136,7 @@ export class SourceTemplatesService {
132136
return true;
133137
}
134138

135-
private async createViewDto(entity: SourceTemplateEntity): Promise<ViewSourceDto> {
139+
private createViewDto(entity: SourceTemplateEntity): ViewSourceDto {
136140
const dto: ViewSourceDto = {
137141
id: entity.id,
138142
name: entity.name,

back-end/api/src/migrations/migrations.service.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,7 @@ export class MigrationsService {
7777
await this.seedTriggers();
7878
await this.seedFirstUser();
7979
await this.seedMetadata();
80-
81-
// Default general settings
82-
await this.generalSettingsService.bulkPut(GeneralSettingsDefaults.GENERAL_SETTINGS, 1);
80+
await this.seedGeneralSettings();
8381
}
8482

8583
private async seedTriggers() {
@@ -91,7 +89,7 @@ export class MigrationsService {
9189
private async seedFirstUser() {
9290
const count = await this.userService.count();
9391
if (count === 0) {
94-
const newUser = await this.userService.createUser(
92+
const newUser = await this.userService.create(
9593
{
9694
name: "admin",
9795
email: "admin@climsoft.org",
@@ -110,7 +108,7 @@ export class MigrationsService {
110108
}
111109
}
112110

113-
public async seedMetadata() {
111+
private async seedMetadata() {
114112
let count: number;
115113
// Elements metadata
116114
count = await this.elementSubdomainsService.count();
@@ -140,6 +138,13 @@ export class MigrationsService {
140138

141139
}
142140

143-
141+
private async seedGeneralSettings() {
142+
// Default general settings
143+
const count: number = await this.generalSettingsService.count();
144+
if (count === 0) {
145+
await this.generalSettingsService.bulkPut(GeneralSettingsDefaults.GENERAL_SETTINGS, 1);
146+
this.logger.log('general settings added');
147+
}
148+
}
144149

145150
}

back-end/api/src/observation/controllers/observations.controller.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { AuthorisedStationsPipe } from 'src/user/pipes/authorised-stations.pipe'
88
import { Request } from 'express';
99
import { AuthUtil } from 'src/user/services/auth.util';
1010
import { EntryFormObservationQueryDto } from '../dtos/entry-form-observation-query.dto';
11-
import { ViewObservationLogQueryDto } from '../dtos/view-observation-log-query.dto';
1211
import { DeleteObservationDto } from '../dtos/delete-observation.dto';
1312
import { Admin } from 'src/user/decorators/admin.decorator';
1413
import { ExportObservationsService } from '../services/export-observations.service';
@@ -50,23 +49,6 @@ export class ObservationsController {
5049
return this.observationsService.findFormData(createObsevationQuery);
5150
}
5251

53-
// TODO. deprecate this handle
54-
//@Get('correction-data')
55-
//getCorrectionData(@Query(AuthorisedStationsPipe) viewObsevationQuery: ViewObservationQueryDTO) {
56-
//return this.observationsService.findCorrectionData(viewObsevationQuery);
57-
//return this.observationsService.findProcessed(viewObsevationQuery);
58-
//}
59-
60-
//@Get('count-correction-data')
61-
//countCorrectionData(@Query(AuthorisedStationsPipe) viewObsevationQuery: ViewObservationQueryDTO) {
62-
// return this.observationsService.count(viewObsevationQuery);
63-
//}
64-
65-
@Get('log')
66-
getObservationLog(@Query(AuthorisedStationsPipe) viewObsevationQuery: ViewObservationLogQueryDto) {
67-
return this.observationsService.findObservationLog(viewObsevationQuery);
68-
}
69-
7052
@Get('stations-observation-status')
7153
getStationsObservationStatus(@Query(AuthorisedStationsPipe) stationStatusQuery: StationStatusQueryDto) { // TODO. Create dto query to make the necessary filter
7254
return this.observationsService.findStationsStatus(stationStatusQuery);

back-end/api/src/observation/dtos/view-observation-log.dto.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export class ViewObservationLogDto {
77
qcStatus: QCStatusEnum;
88
comment: string | null;
99
deleted: boolean;
10+
entryUserName: string;
1011
entryUserEmail: string;
1112
entryDateTime: string;
1213
}

back-end/api/src/observation/services/data-entry-check.service.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ export class DataEntryCheckService {
3333

3434
@OnEvent('source.created')
3535
handleSourceCreated(payload: { id: number; dto: any }) {
36-
console.log(`Source created: ID ${payload.id}`);
37-
// maybe invalidate cache, trigger sync, etc.
36+
console.log(`Source created: ID ${payload.id}`);
3837
this.resetFormParameters();
3938
}
4039

@@ -74,7 +73,6 @@ export class DataEntryCheckService {
7473
} else {
7574
throw new Error('Developer error: Source type not recognised')
7675
}
77-
7876
}
7977
}
8078

@@ -95,32 +93,49 @@ export class DataEntryCheckService {
9593

9694
const source = this.sourceParameters.get(dto.sourceId);
9795

98-
if (!source) throw new BadRequestException('Source template not found');
96+
if (!source) {
97+
this.logger.error(`Source template not found. Dto: ${dto} | User: ${user}`)
98+
throw new BadRequestException('Source template not found');
99+
}
99100

100101
if (source.sourceType === SourceTypeEnum.FORM) {
101102
const formTemplate: FormParams = source.settings as FormParams;
102103
// check element
103-
if (!formTemplate.form.elementIds.includes(dto.elementId)) throw new BadRequestException('Element not allowed');
104+
if (!formTemplate.form.elementIds.includes(dto.elementId)) {
105+
this.logger.error(`Element not allowed. Dto: ${dto} | User: ${user}`);
106+
throw new BadRequestException('Element not allowed');
107+
}
104108

105109
// Check if hour is allowed for the form
106-
if (!formTemplate.utcAdjustedHours.includes(parseInt(dto.datetime.substring(11, 13), 10))) throw new BadRequestException('Hour not allowed');
110+
if (!formTemplate.utcAdjustedHours.includes(parseInt(dto.datetime.substring(11, 13), 10))) {
111+
this.logger.error(`Hour not allowed. Dto: ${dto} | User: ${user}`);
112+
throw new BadRequestException('Hour not allowed');
113+
}
107114

108115
// Check for interval is allowed for the form
109116
if (!formTemplate.form.allowIntervalEditing) {
110-
if (formTemplate.form.interval !== dto.interval) throw new BadRequestException('Interval not allowed');
117+
if (formTemplate.form.interval !== dto.interval) {
118+
this.logger.error(`Interval not allowed. Dto: ${dto} | User: ${user}`);
119+
throw new BadRequestException('Interval not allowed');
120+
}
111121
}
112122

113123
} else if (source.sourceType === SourceTypeEnum.IMPORT) {
114-
// TODO. Use source params to validate the inut. Use full when doing data correction
124+
// TODO. Use source params to validate the input. Use full when doing data correction
125+
// TODO. Should import validation use DuckDB database engine?
115126
}
116127

117128
// Check for future dates
118129
if (new Date(dto.datetime) > todayDate) {
119130
// TODO. Follow up on when invalid dates are being bypassed at the front end.
120-
this.logger.log(`obs datetime: ${dto.datetime} todayDate: ${todayDate.toISOString()}`);
131+
this.logger.error(`Future dates not allowed. Dto ${dto} | User: ${user} | TodayDate: ${todayDate.toISOString()}`);
121132
throw new BadRequestException('Future dates not allowed');
122133
}
123134

135+
if (dto.value === null && dto.flag === null) {
136+
this.logger.error(`Both value and flag are missing. Dto: ${dto} | User: ${user}`);
137+
throw new BadRequestException('Both value and flag are missing');
138+
}
124139
}
125140

126141
this.logger.log(`observations checks took: ${new Date().getTime() - startTime} milliseconds`);

0 commit comments

Comments
 (0)