Merge branch 'develop' of https://git.it.hs-heilbronn.de/tjohn/cc-data into feature/trivago
This commit is contained in:
commit
bb14c9955d
27
backend/Dockerfile
Normal file
27
backend/Dockerfile
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
FROM node:12
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# COPY package.json .
|
||||||
|
# For npm@5 or later, copy package-lock.json as well
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
|
||||||
|
# Install app dependencies
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Bundle app source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENV PORT=3000
|
||||||
|
ENV METEOSTAT_API_KEY=LMlDskju
|
||||||
|
ENV DB_HOST=127.0.0.1
|
||||||
|
ENV DB_USER=root
|
||||||
|
ENV DB_PASSWORD=devtest
|
||||||
|
ENV DB_PORT=3306
|
||||||
|
ENV DATABASE=travopti
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Start Node server
|
||||||
|
CMD [ "node", "./index.js" ]
|
||||||
@ -2,7 +2,8 @@ const router = require("express").Router();
|
|||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const getSearchPresets = require("../models/getSearchPresets.js");
|
const getSearchPresets = require("../models/getSearchPresets.js");
|
||||||
const base64 = require("../util/base64.js")
|
const base64 = require("../util/base64.js")
|
||||||
const sas = require("../util/scoreAndSearch.js")
|
const sas = require("../util/scoreAndSearch.js");
|
||||||
|
const { filter } = require("lodash");
|
||||||
|
|
||||||
|
|
||||||
module.exports = dbConn => {
|
module.exports = dbConn => {
|
||||||
@ -57,8 +58,13 @@ function searchHandler(dbConn) {
|
|||||||
}
|
}
|
||||||
scoreAndSearch(q.from, q.to, scoreQueryObj).then(searchResults => {
|
scoreAndSearch(q.from, q.to, scoreQueryObj).then(searchResults => {
|
||||||
|
|
||||||
response.data = searchResults
|
//response.data = searchResults
|
||||||
response = searchResults
|
// FILTER if query contains filterString
|
||||||
|
if (q.textfilter) {
|
||||||
|
response = filterByString(searchResults, q.textfilter, q.fulltext)
|
||||||
|
} else {
|
||||||
|
response = searchResults
|
||||||
|
}
|
||||||
res.json(response)
|
res.json(response)
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
// TODO error handling
|
// TODO error handling
|
||||||
@ -66,4 +72,19 @@ function searchHandler(dbConn) {
|
|||||||
res.json(e.message)
|
res.json(e.message)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterByString(searchResults, filterString, boolFulltext) {
|
||||||
|
return _.filter(searchResults, region => {
|
||||||
|
console.log("filtering: filterString, boolFulltext");
|
||||||
|
console.log(filterString, boolFulltext);
|
||||||
|
filterString = filterString.toLowerCase()
|
||||||
|
let name = region.name.toLowerCase()
|
||||||
|
let country = region.country.toLowerCase()
|
||||||
|
if (boolFulltext) {
|
||||||
|
let desc = region.description.toLowerCase()
|
||||||
|
return name.includes(filterString) || country.includes(filterString) || desc.includes(filterString)
|
||||||
|
}
|
||||||
|
return name.includes(filterString) || country.includes(filterString)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@
|
|||||||
> .region-footer {
|
> .region-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
> .region-title {
|
> .region-title {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
> .result-footer {
|
> .result-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
> .result-title {
|
> .result-title {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|||||||
@ -5,12 +5,44 @@
|
|||||||
<span class="region-country">{{region.country}}</span>
|
<span class="region-country">{{region.country}}</span>
|
||||||
<span class="region-name">{{region.name}}</span>
|
<span class="region-name">{{region.name}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<button mat-icon-button>
|
||||||
|
<mat-icon>bookmark</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button>
|
||||||
|
<mat-icon>share</mat-icon>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p *ngIf="region.description" class="region-decsription">
|
<p *ngIf="region.description" class="region-decsription">
|
||||||
<span>{{region.description.substr(0, DESC_CUT_POINT)}}</span>
|
<span>{{region.description.substr(0, DESC_CUT_POINT)}}</span>
|
||||||
<span (click)="isDescExtended=true" *ngIf="!isDescExtended" class="more-btn"> ...more</span>
|
<span (click)="isDescExtended=true" *ngIf="!isDescExtended && region.description.length > DESC_CUT_POINT"
|
||||||
|
class="more-btn"> ...more</span>
|
||||||
<span *ngIf="isDescExtended">{{region.description.substr(DESC_CUT_POINT)}}</span>
|
<span *ngIf="isDescExtended">{{region.description.substr(DESC_CUT_POINT)}}</span>
|
||||||
</p>
|
</p>
|
||||||
|
<div class="region-stats-group">
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr *ngFor="let prop of SHOWN_PROPS">
|
||||||
|
<td>
|
||||||
|
<div class="cell">
|
||||||
|
<mat-icon>{{prop.icon}}</mat-icon>
|
||||||
|
<span>{{prop.property|translate}}:</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="cell right">
|
||||||
|
<span>{{region[prop.property].toFixed(2)}}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="cell">
|
||||||
|
<span>{{prop.unit}}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="region-stats-group">
|
<div class="region-stats-group">
|
||||||
<span class="group-title">Max Temperatures [°C]</span>
|
<span class="group-title">Max Temperatures [°C]</span>
|
||||||
<app-graph [monthlyData]="region.temperature_mean_max" class="graph"></app-graph>
|
<app-graph [monthlyData]="region.temperature_mean_max" class="graph"></app-graph>
|
||||||
|
|||||||
@ -14,9 +14,10 @@
|
|||||||
.region-details-header {
|
.region-details-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
> .region-title {
|
> .region-title {
|
||||||
flex: 0 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: 0.25rem 0;
|
margin: 0.25rem 0;
|
||||||
@ -58,6 +59,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
align-self: center;
|
||||||
|
|
||||||
|
&.right {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
> mat-icon {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|||||||
@ -4,6 +4,12 @@ import {ActivatedRoute, ParamMap} from '@angular/router';
|
|||||||
import {DataService} from '../../services/data.service';
|
import {DataService} from '../../services/data.service';
|
||||||
import {switchMap} from 'rxjs/operators';
|
import {switchMap} from 'rxjs/operators';
|
||||||
|
|
||||||
|
interface VisualRegionPropDef {
|
||||||
|
property: string;
|
||||||
|
icon: string;
|
||||||
|
unit: string;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-region-details',
|
selector: 'app-region-details',
|
||||||
templateUrl: './region-details.component.html',
|
templateUrl: './region-details.component.html',
|
||||||
@ -13,6 +19,34 @@ export class RegionDetailsComponent implements OnInit {
|
|||||||
|
|
||||||
/** Cut descriptions after x chars */
|
/** Cut descriptions after x chars */
|
||||||
readonly DESC_CUT_POINT = 300;
|
readonly DESC_CUT_POINT = 300;
|
||||||
|
/** Region property to show in view */
|
||||||
|
readonly SHOWN_PROPS: VisualRegionPropDef[] = [
|
||||||
|
{
|
||||||
|
property: 'average_per_day_costs',
|
||||||
|
icon: 'euro',
|
||||||
|
unit: '€/day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'food_costs',
|
||||||
|
icon: 'local_dining',
|
||||||
|
unit: '€/day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'alcohol_costs',
|
||||||
|
icon: 'local_bar',
|
||||||
|
unit: '€/day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'local_transportation_costs',
|
||||||
|
icon: 'commute',
|
||||||
|
unit: '€/day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'entertainment_costs',
|
||||||
|
icon: 'local_activity',
|
||||||
|
unit: '€/day',
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
/** Current region */
|
/** Current region */
|
||||||
region: Region;
|
region: Region;
|
||||||
|
|||||||
@ -8,10 +8,16 @@ export interface Region {
|
|||||||
country: string;
|
country: string;
|
||||||
/** Short description of the region */
|
/** Short description of the region */
|
||||||
description: string;
|
description: string;
|
||||||
|
/** Temperature means per month */
|
||||||
|
temperature_mean: number[];
|
||||||
|
/** Min temperature means per month */
|
||||||
|
temperature_mean_min: number[];
|
||||||
/** Max temperature means per month */
|
/** Max temperature means per month */
|
||||||
temperature_mean_max: number[];
|
temperature_mean_max: number[];
|
||||||
/** Monthly precipitation */
|
/** Monthly precipitation */
|
||||||
precipitation: number[];
|
precipitation: number[];
|
||||||
|
/** Monthly humidity */
|
||||||
|
humidity: number[];
|
||||||
/** Monthly sun hours */
|
/** Monthly sun hours */
|
||||||
sun_hours: number[];
|
sun_hours: number[];
|
||||||
/** Monthly rainy days */
|
/** Monthly rainy days */
|
||||||
@ -30,4 +36,6 @@ export interface Region {
|
|||||||
accommodation_costs: number;
|
accommodation_costs: number;
|
||||||
/** Average costs per day */
|
/** Average costs per day */
|
||||||
average_per_day_costs: number;
|
average_per_day_costs: number;
|
||||||
|
/** Monthly price derivation in percent */
|
||||||
|
avg_price_relative: number[];
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -5,9 +5,12 @@
|
|||||||
"sun_hours": "Sunny hours",
|
"sun_hours": "Sunny hours",
|
||||||
"precipitation": "Precipitation",
|
"precipitation": "Precipitation",
|
||||||
"humidity": "Humidity",
|
"humidity": "Humidity",
|
||||||
"alcohol_costs": "Alcohol coasts per day",
|
"alcohol_costs": "Alcohol costs",
|
||||||
"food_costs": "Food costs per day",
|
"food_costs": "Food costs",
|
||||||
"cheap_alcohol": "Cheap alcohol",
|
"cheap_alcohol": "Cheap alcohol",
|
||||||
|
"local_transportation_costs": "Public transport",
|
||||||
|
"average_per_day_costs": "Average total costs",
|
||||||
|
"entertainment_costs": "Entertainment costs",
|
||||||
"cheap_food": "Cheap food",
|
"cheap_food": "Cheap food",
|
||||||
"cheap_water": "Cheap water",
|
"cheap_water": "Cheap water",
|
||||||
"cheap_transportations": "Cheap public transport",
|
"cheap_transportations": "Cheap public transport",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user