incyclist-services 1.4.18 → 1.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/activities/upload/velohero.d.ts +2 -0
- package/lib/activities/upload/velohero.js +6 -0
- package/lib/apps/base/api/komoot/api.d.ts +3 -1
- package/lib/apps/base/api/komoot/api.js +61 -31
- package/lib/apps/base/api/komoot/types.d.ts +2 -1
- package/lib/apps/service.d.ts +1 -0
- package/lib/apps/service.js +4 -0
- package/lib/routes/base/parsers/epm.js +0 -2
- package/lib/routes/base/types/index.d.ts +1 -0
- package/lib/routes/list/cards/ActiveImportCard.d.ts +4 -0
- package/lib/routes/list/cards/ActiveImportCard.js +18 -4
- package/lib/routes/list/cards/RouteCard.d.ts +5 -2
- package/lib/routes/list/cards/RouteCard.js +9 -5
- package/lib/routes/list/service.d.ts +7 -3
- package/lib/routes/list/service.js +90 -47
- package/lib/routes/list/types.d.ts +4 -1
- package/lib/routes/sync/factory.js +1 -0
- package/lib/routes/sync/komoot/provider.d.ts +15 -4
- package/lib/routes/sync/komoot/provider.js +69 -28
- package/package.json +1 -1
|
@@ -8,6 +8,8 @@ export declare class VeloHeroUpload extends IncyclistService implements IActivit
|
|
|
8
8
|
constructor();
|
|
9
9
|
init(): boolean;
|
|
10
10
|
isConnected(): boolean;
|
|
11
|
+
isConnecting(): boolean;
|
|
12
|
+
disconnect(): void;
|
|
11
13
|
upload(activity: ActivityDetails, format?: string): Promise<boolean>;
|
|
12
14
|
getUrl(id: string): string;
|
|
13
15
|
protected ensureInitialized(): any;
|
|
@@ -77,6 +77,12 @@ let VeloHeroUpload = (() => {
|
|
|
77
77
|
isConnected() {
|
|
78
78
|
return this.getVeloHeroAppConnection().isConnected();
|
|
79
79
|
}
|
|
80
|
+
isConnecting() {
|
|
81
|
+
return this.getVeloHeroAppConnection().isConnecting();
|
|
82
|
+
}
|
|
83
|
+
disconnect() {
|
|
84
|
+
return this.getVeloHeroAppConnection().disconnect();
|
|
85
|
+
}
|
|
80
86
|
upload(activity_1) {
|
|
81
87
|
return __awaiter(this, arguments, void 0, function* (activity, format = 'TCX') {
|
|
82
88
|
var _a;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
import { EventLogger } from 'gd-eventlog';
|
|
1
2
|
import { AppApiBase } from '../base';
|
|
2
3
|
import { KomootAuthConfig, KomootCoordinate, KomootGetTourRequestFilters, KomootGetTourRequestParams, KomootLoginResponse, KomootTourSummary } from './types';
|
|
3
4
|
export declare class KomootApi extends AppApiBase {
|
|
4
5
|
protected username: string;
|
|
5
6
|
protected password: string;
|
|
6
7
|
protected userid: string;
|
|
7
|
-
protected
|
|
8
|
+
protected logger: EventLogger;
|
|
8
9
|
constructor();
|
|
9
10
|
login(username: string, password: string, userid: string): Promise<KomootLoginResponse>;
|
|
10
11
|
setAuth(auth: KomootAuthConfig | null): void;
|
|
11
12
|
isAuthenticated(): boolean;
|
|
12
13
|
getTours(params?: KomootGetTourRequestParams, filters?: KomootGetTourRequestFilters): Promise<Array<KomootTourSummary>>;
|
|
13
14
|
getTourCoordinates(id: number): Promise<Array<KomootCoordinate>>;
|
|
15
|
+
protected applyFilter(tours: Array<KomootTourSummary>, filters?: KomootGetTourRequestFilters): KomootTourSummary[];
|
|
14
16
|
protected getBasicAuthCredentials(): {
|
|
15
17
|
username: string;
|
|
16
18
|
password: string;
|
|
@@ -10,14 +10,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.KomootApi = void 0;
|
|
13
|
+
const gd_eventlog_1 = require("gd-eventlog");
|
|
13
14
|
const valid_1 = require("../../../../utils/valid");
|
|
14
15
|
const base_1 = require("../base");
|
|
15
16
|
const API_BASE_URL = 'https://api.komoot.de/v007';
|
|
16
|
-
let IID = 0;
|
|
17
17
|
class KomootApi extends base_1.AppApiBase {
|
|
18
18
|
constructor() {
|
|
19
19
|
super();
|
|
20
|
-
this.
|
|
20
|
+
this.logger = new gd_eventlog_1.EventLogger('KomootAPI');
|
|
21
21
|
}
|
|
22
22
|
login(username, password, userid) {
|
|
23
23
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -71,43 +71,73 @@ class KomootApi extends base_1.AppApiBase {
|
|
|
71
71
|
getTours() {
|
|
72
72
|
return __awaiter(this, arguments, void 0, function* (params = {}, filters) {
|
|
73
73
|
var _a, _b, _c;
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
74
|
+
const tsStart = Date.now();
|
|
75
|
+
let args;
|
|
76
|
+
try {
|
|
77
|
+
const auth = this.getBasicAuthCredentials();
|
|
78
|
+
if (!this.userid) {
|
|
79
|
+
this.logger.logEvent({ message: 'getTours failed', reason: 'invalid credentials' });
|
|
80
|
+
throw new Error('invalid credentials');
|
|
81
|
+
}
|
|
82
|
+
const keys = Object.keys(params !== null && params !== void 0 ? params : {});
|
|
83
|
+
args = keys.map(key => `${key}=${params[key]}`).join('&');
|
|
84
|
+
const url = keys.length > 0 ? `/users/${this.userid}/tours/?` + args : `/users/${this.userid}/tours/`;
|
|
85
|
+
const response = yield this.get(url, { auth });
|
|
86
|
+
if (response.status >= 400 && response.status < 500) {
|
|
87
|
+
this.logger.logEvent({ message: 'getTours failed', args, reason: 'invalid credentials', duration: Date.now() - tsStart });
|
|
88
|
+
throw new Error('invalid credentials');
|
|
89
|
+
}
|
|
90
|
+
const tours = (_c = (_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a._embedded) === null || _b === void 0 ? void 0 : _b.tours) !== null && _c !== void 0 ? _c : [];
|
|
91
|
+
const result = this.applyFilter(tours, filters);
|
|
92
|
+
this.logger.logEvent({ message: 'getTours result', args, tours: result.length, duration: Date.now() - tsStart });
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
this.logger.logEvent({ message: 'getTours failed', args, reason: err.message, duration: Date.now() - tsStart });
|
|
97
|
+
throw (err);
|
|
83
98
|
}
|
|
84
|
-
const tours = (_c = (_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a._embedded) === null || _b === void 0 ? void 0 : _b.tours) !== null && _c !== void 0 ? _c : [];
|
|
85
|
-
return tours.filter(tour => {
|
|
86
|
-
let valid = true;
|
|
87
|
-
if (filters === null || filters === void 0 ? void 0 : filters.sport)
|
|
88
|
-
valid = valid && (tour.sport === filters.sport);
|
|
89
|
-
if (filters === null || filters === void 0 ? void 0 : filters.after)
|
|
90
|
-
valid = valid && (new Date(tour.date).valueOf() > filters.after.valueOf());
|
|
91
|
-
if (filters === null || filters === void 0 ? void 0 : filters.lastUpdateAfter)
|
|
92
|
-
valid = valid && (new Date(tour.changed_at).valueOf() > filters.lastUpdateAfter.valueOf());
|
|
93
|
-
return valid;
|
|
94
|
-
});
|
|
95
99
|
});
|
|
96
100
|
}
|
|
97
101
|
getTourCoordinates(id) {
|
|
98
102
|
return __awaiter(this, void 0, void 0, function* () {
|
|
99
103
|
var _a, _b;
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
const tsStart = Date.now();
|
|
105
|
+
try {
|
|
106
|
+
const url = `/tours/${id}/coordinates`;
|
|
107
|
+
const auth = this.getBasicAuthCredentials();
|
|
108
|
+
const response = yield this.get(url, { auth });
|
|
109
|
+
if (response.status === 404) {
|
|
110
|
+
this.logger.logEvent({ message: 'getTourCoordinates failed', id, reason: 'not found', duration: Date.now() - tsStart });
|
|
111
|
+
throw new Error('not found');
|
|
112
|
+
}
|
|
113
|
+
else if (response.status >= 400 && response.status < 500) {
|
|
114
|
+
this.logger.logEvent({ message: 'getTourCoordinates failed', id, reason: 'invalid credentials', duration: Date.now() - tsStart });
|
|
115
|
+
throw new Error('invalid credentials');
|
|
116
|
+
}
|
|
117
|
+
const points = (_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : [];
|
|
118
|
+
this.logger.logEvent({ message: 'getTourCoordinates result', id, points: points.length, duration: Date.now() - tsStart });
|
|
119
|
+
return points;
|
|
105
120
|
}
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
catch (err) {
|
|
122
|
+
this.logger.logEvent({ message: 'getTourCoordinates failed', id, reason: err.message, duration: Date.now() - tsStart });
|
|
123
|
+
throw (err);
|
|
108
124
|
}
|
|
109
|
-
|
|
110
|
-
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
applyFilter(tours, filters) {
|
|
128
|
+
var _a, _b;
|
|
129
|
+
if (!filters)
|
|
130
|
+
return tours;
|
|
131
|
+
const sportTypeFilter = (_b = (_a = filters.sport) === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
|
|
132
|
+
return tours.filter(tour => {
|
|
133
|
+
let valid = true;
|
|
134
|
+
if (filters === null || filters === void 0 ? void 0 : filters.sport)
|
|
135
|
+
valid = valid && (sportTypeFilter.includes(tour.sport));
|
|
136
|
+
if (filters === null || filters === void 0 ? void 0 : filters.after)
|
|
137
|
+
valid = valid && (new Date(tour.date).valueOf() > filters.after.valueOf());
|
|
138
|
+
if (filters === null || filters === void 0 ? void 0 : filters.lastUpdateAfter)
|
|
139
|
+
valid = valid && (new Date(tour.changed_at).valueOf() > filters.lastUpdateAfter.valueOf());
|
|
140
|
+
return valid;
|
|
111
141
|
});
|
|
112
142
|
}
|
|
113
143
|
getBasicAuthCredentials() {
|
|
@@ -90,4 +90,5 @@ export interface KomootCoordinate extends KomootPoint {
|
|
|
90
90
|
t: number;
|
|
91
91
|
}
|
|
92
92
|
export type KomootTourType = 'tour_planned' | 'tour_recorded';
|
|
93
|
-
export type KomootSportType = 'hike' | 'touringbicycle' | '
|
|
93
|
+
export type KomootSportType = 'hike' | 'touringbicycle' | 'mtb' | 'racebike' | 'jogging' | 'mtb_easy' | 'mtb_advancde' | 'mountaineering';
|
|
94
|
+
export type KomootSportTypeNames = 'Hiking' | 'Cycling' | 'Mountain biking' | 'Road cycling' | 'Running' | 'Gravel riding' | 'Enduro mountain biking' | 'Mountaineering';
|
package/lib/apps/service.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export declare class AppsService extends IncyclistService {
|
|
|
24
24
|
getAppOperationSettings(app: string): any[];
|
|
25
25
|
getConnectedServices(operation: AppsOperation): Array<AppDefinition>;
|
|
26
26
|
getName(key: string): string;
|
|
27
|
+
getKey(name: string): string;
|
|
27
28
|
protected getAppDisplayProps(key: string): {
|
|
28
29
|
name: string;
|
|
29
30
|
key: string;
|
package/lib/apps/service.js
CHANGED
|
@@ -156,6 +156,10 @@ let AppsService = (() => {
|
|
|
156
156
|
const found = this.serviceMap.find(r => r.key === key);
|
|
157
157
|
return found ? found.name : key;
|
|
158
158
|
}
|
|
159
|
+
getKey(name) {
|
|
160
|
+
const found = this.serviceMap.find(r => r.name === name);
|
|
161
|
+
return found ? found.key : name;
|
|
162
|
+
}
|
|
159
163
|
getAppDisplayProps(key) {
|
|
160
164
|
const entry = this.serviceMap.find(e => e.key === key);
|
|
161
165
|
const { name, iconUrl } = entry;
|
|
@@ -91,8 +91,6 @@ class EPMParser extends xml_1.XMLParser {
|
|
|
91
91
|
json.min = reader.ReadUint32();
|
|
92
92
|
json.max = reader.ReadUint32();
|
|
93
93
|
json.cnt = reader.ReadUint32();
|
|
94
|
-
if (json.cnt !== num) {
|
|
95
|
-
}
|
|
96
94
|
json.sampleRate = reader.ReadUint32();
|
|
97
95
|
json.validFor = reader.ReadUint32();
|
|
98
96
|
json.elevationStart = reader.ReadFloat();
|
|
@@ -6,15 +6,18 @@ import { Route } from "../../base/model/route";
|
|
|
6
6
|
import { BaseCard } from "./base";
|
|
7
7
|
import { RouteCardType, ActiveImportProps } from "./types";
|
|
8
8
|
import { AppStatus } from "../../base/types";
|
|
9
|
+
import { EventLogger } from "gd-eventlog";
|
|
9
10
|
export declare class ActiveImportCard extends BaseCard implements Card<Route> {
|
|
10
11
|
protected file: FileInfo;
|
|
11
12
|
protected error: Error;
|
|
12
13
|
protected cardObserver: any;
|
|
13
14
|
protected deleteObserver: PromiseObserver<void>;
|
|
15
|
+
protected logger: EventLogger;
|
|
14
16
|
constructor(file: FileInfo);
|
|
15
17
|
setVisible(): void;
|
|
16
18
|
canStart(status: AppStatus): boolean;
|
|
17
19
|
delete(): PromiseObserver<boolean>;
|
|
20
|
+
setInitialized(init: boolean): void;
|
|
18
21
|
setError(error: Error): void;
|
|
19
22
|
setData(): void;
|
|
20
23
|
emitUpdate(): void;
|
|
@@ -25,4 +28,5 @@ export declare class ActiveImportCard extends BaseCard implements Card<Route> {
|
|
|
25
28
|
getTitle(): string;
|
|
26
29
|
getDisplayProperties(): ActiveImportProps;
|
|
27
30
|
retry(): void;
|
|
31
|
+
protected logError(err: Error, fn: string): void;
|
|
28
32
|
}
|
|
@@ -5,12 +5,14 @@ const observer_1 = require("../../../base/types/observer");
|
|
|
5
5
|
const service_1 = require("../service");
|
|
6
6
|
const base_1 = require("./base");
|
|
7
7
|
const types_1 = require("./types");
|
|
8
|
+
const gd_eventlog_1 = require("gd-eventlog");
|
|
8
9
|
class ActiveImportCard extends base_1.BaseCard {
|
|
9
10
|
constructor(file) {
|
|
10
11
|
super();
|
|
11
12
|
this.file = file;
|
|
12
13
|
this.error = null;
|
|
13
14
|
this.cardObserver = new observer_1.Observer();
|
|
15
|
+
this.logger = new gd_eventlog_1.EventLogger('ActiveImportCard');
|
|
14
16
|
}
|
|
15
17
|
setVisible() {
|
|
16
18
|
this.visible = true;
|
|
@@ -26,17 +28,26 @@ class ActiveImportCard extends base_1.BaseCard {
|
|
|
26
28
|
}
|
|
27
29
|
return observer_1.PromiseObserver.alwaysReturning(true);
|
|
28
30
|
}
|
|
31
|
+
setInitialized(init) {
|
|
32
|
+
try {
|
|
33
|
+
const prev = this.initialized;
|
|
34
|
+
this.initialized = init;
|
|
35
|
+
if (init && !prev)
|
|
36
|
+
this.emitUpdate();
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
this.logError(err, 'setInitialized');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
29
42
|
setError(error) {
|
|
30
43
|
this.error = error;
|
|
31
|
-
process.nextTick(() => {
|
|
32
|
-
this.emitUpdate();
|
|
33
|
-
});
|
|
44
|
+
process.nextTick(() => { this.emitUpdate(); });
|
|
34
45
|
}
|
|
35
46
|
setData() {
|
|
36
47
|
}
|
|
37
48
|
emitUpdate() {
|
|
38
49
|
const props = this.getDisplayProperties();
|
|
39
|
-
this.cardObserver.emit('update', props);
|
|
50
|
+
this.cardObserver.emit('update', Object.assign({}, props));
|
|
40
51
|
}
|
|
41
52
|
getData() {
|
|
42
53
|
return undefined;
|
|
@@ -65,5 +76,8 @@ class ActiveImportCard extends base_1.BaseCard {
|
|
|
65
76
|
this.emitUpdate();
|
|
66
77
|
(0, service_1.useRouteList)().import(this.file, this);
|
|
67
78
|
}
|
|
79
|
+
logError(err, fn) {
|
|
80
|
+
this.logger.logEvent({ message: 'error', error: err.message, fn, stack: err.stack });
|
|
81
|
+
}
|
|
68
82
|
}
|
|
69
83
|
exports.ActiveImportCard = ActiveImportCard;
|
|
@@ -92,8 +92,11 @@ export declare class RouteCard extends BaseCard implements Card<Route> {
|
|
|
92
92
|
changeSettings(props: RouteSettings): void;
|
|
93
93
|
protected adjustStartPosAvi(settings: RouteSettings): void;
|
|
94
94
|
save(): Promise<void>;
|
|
95
|
-
delete(
|
|
96
|
-
|
|
95
|
+
delete(props?: {
|
|
96
|
+
enforced?: boolean;
|
|
97
|
+
source: 'user' | 'system';
|
|
98
|
+
}): PromiseObserver<boolean>;
|
|
99
|
+
protected _delete(enforced?: boolean, source?: 'user' | 'system'): Promise<boolean>;
|
|
97
100
|
start(): void;
|
|
98
101
|
cancel(): void;
|
|
99
102
|
addWorkout(): void;
|
|
@@ -338,22 +338,23 @@ class RouteCard extends base_1.BaseCard {
|
|
|
338
338
|
}
|
|
339
339
|
});
|
|
340
340
|
}
|
|
341
|
-
delete(
|
|
341
|
+
delete(props) {
|
|
342
|
+
const { enforced, source = 'user' } = props !== null && props !== void 0 ? props : {};
|
|
342
343
|
try {
|
|
343
344
|
this.logger.logEvent({ message: 'delete card', card: this.getTitle() });
|
|
344
345
|
const service = (0, service_1.getRouteList)();
|
|
345
346
|
service.unselectCard(this);
|
|
346
347
|
if (this.deleteObserver)
|
|
347
348
|
return this.deleteObserver;
|
|
348
|
-
this.deleteObserver = new observer_1.PromiseObserver(this._delete(enforced));
|
|
349
|
+
this.deleteObserver = new observer_1.PromiseObserver(this._delete(enforced, source));
|
|
349
350
|
return this.deleteObserver;
|
|
350
351
|
}
|
|
351
352
|
catch (err) {
|
|
352
353
|
this.logError(err, 'delete');
|
|
353
354
|
}
|
|
354
355
|
}
|
|
355
|
-
_delete(
|
|
356
|
-
return __awaiter(this,
|
|
356
|
+
_delete(enforced_1) {
|
|
357
|
+
return __awaiter(this, arguments, void 0, function* (enforced, source = 'user') {
|
|
357
358
|
yield (0, utils_1.waitNextTick)();
|
|
358
359
|
let deleted = false;
|
|
359
360
|
try {
|
|
@@ -384,7 +385,7 @@ class RouteCard extends base_1.BaseCard {
|
|
|
384
385
|
this.deleteFromUIList();
|
|
385
386
|
this.deleteRouteUserSettings();
|
|
386
387
|
this.logger.logEvent({ message: 'card deleted', card: this.getTitle() });
|
|
387
|
-
(0, service_1.getRouteList)().emitLists('updated', { log: true });
|
|
388
|
+
(0, service_1.getRouteList)().emitLists('updated', { log: true, source });
|
|
388
389
|
deleted = true;
|
|
389
390
|
}
|
|
390
391
|
catch (err) {
|
|
@@ -742,6 +743,8 @@ class RouteCard extends base_1.BaseCard {
|
|
|
742
743
|
}
|
|
743
744
|
verifyRoute(route) {
|
|
744
745
|
var _a, _b;
|
|
746
|
+
if (route.description.isLoopVerified)
|
|
747
|
+
return;
|
|
745
748
|
if ((0, route_1.checkIsLoop)(route)) {
|
|
746
749
|
const points = (_b = (_a = route.details) === null || _a === void 0 ? void 0 : _a.points) !== null && _b !== void 0 ? _b : [];
|
|
747
750
|
if (!points.length)
|
|
@@ -753,6 +756,7 @@ class RouteCard extends base_1.BaseCard {
|
|
|
753
756
|
if (Math.abs(slope) > 1) {
|
|
754
757
|
this.logger.logEvent({ message: 'Loop elevation profile adjusted', route: route.description.title });
|
|
755
758
|
(0, route_1.updateSlopes)(route.details.points);
|
|
759
|
+
route.description.isLoopVerified = true;
|
|
756
760
|
}
|
|
757
761
|
}
|
|
758
762
|
}
|
|
@@ -91,6 +91,8 @@ export declare class RouteListService extends IncyclistService implements IRoute
|
|
|
91
91
|
observer?: undefined;
|
|
92
92
|
cards?: undefined;
|
|
93
93
|
};
|
|
94
|
+
getVisibleRoutes(): Array<Route>;
|
|
95
|
+
getAllAppRoutes(source: string): Array<RouteInfo>;
|
|
94
96
|
searchRepo(requestedFilters?: SearchFilter): {
|
|
95
97
|
routes: SummaryCardDisplayProps[];
|
|
96
98
|
filters: SearchFilter;
|
|
@@ -137,27 +139,29 @@ export declare class RouteListService extends IncyclistService implements IRoute
|
|
|
137
139
|
import(info: FileInfo | Array<FileInfo>, retry?: ActiveImportCard): void;
|
|
138
140
|
emitLists(event: 'loaded' | 'updated', props?: {
|
|
139
141
|
log?: boolean;
|
|
142
|
+
source?: 'user' | 'system';
|
|
140
143
|
}): void;
|
|
141
144
|
getCard(id: string): RouteCard;
|
|
142
145
|
addCardAgain(card: RouteCard): void;
|
|
143
146
|
protected addImportCard(file: FileInfo): ActiveImportCard;
|
|
144
147
|
protected getFilterContentTypes(): Array<string>;
|
|
145
148
|
protected getFilterRouteTypes(): Array<string>;
|
|
149
|
+
protected getFilterRouteSources(): Array<string>;
|
|
146
150
|
protected getFilterCountries(): Array<string>;
|
|
147
|
-
protected addRoute(route: Route): void;
|
|
151
|
+
protected addRoute(route: Route, source?: 'user' | 'system'): void;
|
|
148
152
|
protected verifyPoints(card: RouteCard, route: Route): Promise<void>;
|
|
149
153
|
protected addFromApi(route: Route): Promise<void>;
|
|
150
|
-
protected update(route: Route): Promise<void>;
|
|
154
|
+
protected update(route: Route, source?: 'user' | 'system'): Promise<void>;
|
|
151
155
|
protected loadRoutes(): Promise<void>;
|
|
152
156
|
protected preloadDetails(): Promise<void>;
|
|
153
157
|
protected startSync(): void;
|
|
154
158
|
protected getSyncFrequency(): any;
|
|
155
|
-
protected checkKomootFeatureEnabled(): any;
|
|
156
159
|
protected stopSync(): void;
|
|
157
160
|
protected performSync(service?: string): Promise<void>;
|
|
158
161
|
protected loadSyncedRouteDetails(route: Route): Promise<Route>;
|
|
159
162
|
protected onSyncRouteAdded(source: string, descriptions: Array<RouteInfo>): void;
|
|
160
163
|
protected onSyncRouteUpdated(source: string, routes: Array<Route>): void;
|
|
164
|
+
protected onSyncRouteDeleted(source: string, routes: Array<string>): void;
|
|
161
165
|
protected checkUIUpdateWithNoRepoStats(): Promise<void>;
|
|
162
166
|
protected loadRoutesFromRepo(): Promise<void>;
|
|
163
167
|
protected loadRoutesFromApi(): Promise<void>;
|
|
@@ -103,7 +103,7 @@ let RouteListService = (() => {
|
|
|
103
103
|
this.db = new db_1.RoutesDbLoader();
|
|
104
104
|
this.createPreviewQueue = [];
|
|
105
105
|
this.routes = [];
|
|
106
|
-
this.filters =
|
|
106
|
+
this.filters = this.getFilters();
|
|
107
107
|
this.syncInfo = {};
|
|
108
108
|
this.getRouteSyncFactory().setRouteList(this);
|
|
109
109
|
this.handleConfigChanges();
|
|
@@ -182,13 +182,16 @@ let RouteListService = (() => {
|
|
|
182
182
|
saveFilters(requestedFilters) {
|
|
183
183
|
this.filters = requestedFilters;
|
|
184
184
|
const settings = this.getUserSettings();
|
|
185
|
-
settings.set('
|
|
185
|
+
settings.set('preferences.search.filter', requestedFilters !== null && requestedFilters !== void 0 ? requestedFilters : null);
|
|
186
186
|
}
|
|
187
187
|
getFilters() {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
try {
|
|
189
|
+
if (!this.filters) {
|
|
190
|
+
const settings = this.getUserSettings();
|
|
191
|
+
this.filters = settings.get('preferences.search.filter', undefined);
|
|
192
|
+
}
|
|
191
193
|
}
|
|
194
|
+
catch (_a) { }
|
|
192
195
|
return this.filters;
|
|
193
196
|
}
|
|
194
197
|
searchAgain() {
|
|
@@ -199,28 +202,39 @@ let RouteListService = (() => {
|
|
|
199
202
|
if (!this.initialized)
|
|
200
203
|
this.preload();
|
|
201
204
|
const filters = requestedFilters || this.filters;
|
|
202
|
-
this.prevFilters
|
|
203
|
-
|
|
205
|
+
if (filters !== this.prevFilters) {
|
|
206
|
+
this.prevFilters = filters;
|
|
207
|
+
this.saveFilters(filters);
|
|
208
|
+
}
|
|
209
|
+
return this.searchRepo(filters);
|
|
210
|
+
}
|
|
211
|
+
getVisibleRoutes() {
|
|
212
|
+
return this.routes.filter(r => r.description && !r.description.isDeleted);
|
|
213
|
+
}
|
|
214
|
+
getAllAppRoutes(source) {
|
|
215
|
+
let routes = this.routes.map(r => r.description);
|
|
216
|
+
routes = this.applySourceFilter({ routeSource: source }, routes);
|
|
217
|
+
return routes;
|
|
204
218
|
}
|
|
205
219
|
searchRepo(requestedFilters) {
|
|
206
220
|
if (!this.observer)
|
|
207
221
|
this.observer = new RouteListObserver_1.RouteListObserver(this);
|
|
208
222
|
try {
|
|
209
|
-
const filters = requestedFilters
|
|
223
|
+
const filters = requestedFilters !== null && requestedFilters !== void 0 ? requestedFilters : this.filters;
|
|
210
224
|
let routes = Array.from(this.getAllSearchCards().map(c => c.getDisplayProperties()));
|
|
211
225
|
routes.sort((a, b) => a.title > b.title ? 1 : -1);
|
|
212
226
|
if (!filters) {
|
|
213
227
|
return { routes, filters, observer: this.observer };
|
|
214
228
|
}
|
|
215
|
-
|
|
229
|
+
if (!filters.includeDeleted)
|
|
230
|
+
routes = routes.filter(r => !(r === null || r === void 0 ? void 0 : r.isDeleted));
|
|
216
231
|
routes = this.applyTitleFilter(filters, routes);
|
|
217
232
|
routes = this.applyDistanceFilter(filters, routes);
|
|
218
233
|
routes = this.applyElevationFilter(filters, routes);
|
|
219
234
|
routes = this.applyCountryFilter(filters, routes);
|
|
220
235
|
routes = this.applyContentTypeFilter(filters, routes);
|
|
221
236
|
routes = this.applyRouteTypeFilter(filters, routes);
|
|
222
|
-
|
|
223
|
-
routes = this.applySourceFilter(filters, routes);
|
|
237
|
+
routes = this.applySourceFilter(filters, routes);
|
|
224
238
|
const cards = routes.map(r => this.getCard(r.id));
|
|
225
239
|
this.setListTop('list', 0);
|
|
226
240
|
this.setListTop('tiles', 0);
|
|
@@ -260,11 +274,12 @@ let RouteListService = (() => {
|
|
|
260
274
|
}
|
|
261
275
|
applySourceFilter(filters, routes) {
|
|
262
276
|
routes = routes.filter(r => r.source === undefined || this.getAppsService().isEnabled(r.source, 'RouteDownload'));
|
|
263
|
-
if (filters.
|
|
264
|
-
const
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
277
|
+
if (filters.routeSource) {
|
|
278
|
+
const local = filters.routeSource === 'Local';
|
|
279
|
+
const internal = filters.routeSource === 'Incyclist';
|
|
280
|
+
const sources = filters.routeSource.split('|').map(s => this.getAppsService().getKey(s));
|
|
281
|
+
routes = routes.filter(r => (r.source === undefined && !r.isLocal && internal) ||
|
|
282
|
+
(r.source === undefined && r.isLocal && local) ||
|
|
268
283
|
(r.source && !internal && sources.includes(r.source)));
|
|
269
284
|
}
|
|
270
285
|
return routes;
|
|
@@ -319,15 +334,17 @@ let RouteListService = (() => {
|
|
|
319
334
|
let countries = [];
|
|
320
335
|
let contentTypes = [];
|
|
321
336
|
let routeTypes = [];
|
|
337
|
+
let routeSources = [];
|
|
322
338
|
try {
|
|
323
339
|
countries = this.getFilterCountries();
|
|
324
340
|
contentTypes = this.getFilterContentTypes();
|
|
325
341
|
routeTypes = this.getFilterRouteTypes();
|
|
342
|
+
routeSources = this.getFilterRouteSources();
|
|
326
343
|
}
|
|
327
344
|
catch (err) {
|
|
328
345
|
this.logError(err, 'getFilterOption');
|
|
329
346
|
}
|
|
330
|
-
return { countries, contentTypes, routeTypes };
|
|
347
|
+
return { countries, contentTypes, routeTypes, routeSources };
|
|
331
348
|
}
|
|
332
349
|
onResize() {
|
|
333
350
|
try {
|
|
@@ -439,7 +456,7 @@ let RouteListService = (() => {
|
|
|
439
456
|
getRouteDetails(id_1) {
|
|
440
457
|
return __awaiter(this, arguments, void 0, function* (id, expectLocal = false) {
|
|
441
458
|
try {
|
|
442
|
-
const route = this.
|
|
459
|
+
const route = this.getVisibleRoutes().find(r => r.description.id === id);
|
|
443
460
|
if (!route)
|
|
444
461
|
return;
|
|
445
462
|
if (expectLocal && route.description.requiresDownload && !route.description.isDownloaded) {
|
|
@@ -459,7 +476,7 @@ let RouteListService = (() => {
|
|
|
459
476
|
getRouteDescription(id) {
|
|
460
477
|
var _a;
|
|
461
478
|
try {
|
|
462
|
-
return (_a = this.
|
|
479
|
+
return (_a = this.getVisibleRoutes().find(r => r.description.id === id)) === null || _a === void 0 ? void 0 : _a.description;
|
|
463
480
|
}
|
|
464
481
|
catch (err) {
|
|
465
482
|
this.logError(err, 'getRouteDescription', id);
|
|
@@ -550,20 +567,19 @@ let RouteListService = (() => {
|
|
|
550
567
|
emitLists(event, props) {
|
|
551
568
|
var _a;
|
|
552
569
|
try {
|
|
570
|
+
const { log, source = 'user' } = props !== null && props !== void 0 ? props : {};
|
|
553
571
|
if (this.currentView === 'grid' || this.currentView === 'list') {
|
|
554
572
|
const d = this.searchAgain();
|
|
555
|
-
this.observer.emit(event, d);
|
|
573
|
+
this.observer.emit(event, d, source);
|
|
556
574
|
return;
|
|
557
575
|
}
|
|
558
|
-
const { log } = props !== null && props !== void 0 ? props : {};
|
|
559
576
|
if (log) {
|
|
560
577
|
const logs = (_a = this.createRoutesLogEntry(true)) !== null && _a !== void 0 ? _a : {};
|
|
561
578
|
this.logEvent(Object.assign({ message: `RoutesList ${event}` }, logs));
|
|
562
579
|
}
|
|
563
580
|
const lists = this.getLists();
|
|
564
|
-
const hash = lists ? lists.map(l => l.getCards().map(c => c.getId()).join(',')).join(':') : '';
|
|
565
581
|
if (this.observer)
|
|
566
|
-
this.observer.emit(event, lists,
|
|
582
|
+
this.observer.emit(event, lists, source);
|
|
567
583
|
}
|
|
568
584
|
catch (err) {
|
|
569
585
|
this.logError(err, 'emitLists', event);
|
|
@@ -593,10 +609,23 @@ let RouteListService = (() => {
|
|
|
593
609
|
getFilterRouteTypes() {
|
|
594
610
|
return ['Loop', 'Point to Point'];
|
|
595
611
|
}
|
|
612
|
+
getFilterRouteSources() {
|
|
613
|
+
const options = ['Local', 'Incyclist'];
|
|
614
|
+
this.getVisibleRoutes().forEach(r => {
|
|
615
|
+
const source = r.description.source;
|
|
616
|
+
if (!source)
|
|
617
|
+
return;
|
|
618
|
+
const option = this.getAppsService().getName(source);
|
|
619
|
+
if (option && !options.includes(option)) {
|
|
620
|
+
options.push(option);
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
return options;
|
|
624
|
+
}
|
|
596
625
|
getFilterCountries() {
|
|
597
626
|
try {
|
|
598
627
|
const countries = [];
|
|
599
|
-
this.
|
|
628
|
+
this.getVisibleRoutes().forEach(r => {
|
|
600
629
|
const iso = r.description.country;
|
|
601
630
|
let country = 'Unknown';
|
|
602
631
|
if (iso)
|
|
@@ -618,16 +647,21 @@ let RouteListService = (() => {
|
|
|
618
647
|
return [];
|
|
619
648
|
}
|
|
620
649
|
}
|
|
621
|
-
addRoute(route) {
|
|
622
|
-
var _a;
|
|
623
|
-
this.
|
|
650
|
+
addRoute(route, source = 'system') {
|
|
651
|
+
var _a, _b;
|
|
652
|
+
this.routes.push(route);
|
|
624
653
|
if ((_a = route.description) === null || _a === void 0 ? void 0 : _a.isDeleted)
|
|
625
654
|
return;
|
|
626
|
-
if (!route.description.
|
|
627
|
-
|
|
628
|
-
.
|
|
629
|
-
|
|
630
|
-
|
|
655
|
+
if (!((_b = route.description) === null || _b === void 0 ? void 0 : _b.isDeleted)) {
|
|
656
|
+
if (source === 'user') {
|
|
657
|
+
this.logEvent({ message: 'route added', route: route.description.title, source: route.description.source });
|
|
658
|
+
}
|
|
659
|
+
if (!route.description.country) {
|
|
660
|
+
route.updateCountryFromPoints()
|
|
661
|
+
.then(() => {
|
|
662
|
+
this.db.save(route, false);
|
|
663
|
+
});
|
|
664
|
+
}
|
|
631
665
|
}
|
|
632
666
|
const list = this.selectList(route);
|
|
633
667
|
const card = new RouteCard_1.RouteCard(route, { list });
|
|
@@ -635,8 +669,7 @@ let RouteListService = (() => {
|
|
|
635
669
|
list.add(card);
|
|
636
670
|
if (list.getId() === 'myRoutes')
|
|
637
671
|
card.enableDelete(true);
|
|
638
|
-
this.
|
|
639
|
-
this.emitLists('updated');
|
|
672
|
+
this.emitLists('updated', { source });
|
|
640
673
|
}
|
|
641
674
|
verifyPoints(card, route) {
|
|
642
675
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -651,11 +684,11 @@ let RouteListService = (() => {
|
|
|
651
684
|
const existing = this.findCard(route);
|
|
652
685
|
if (existing)
|
|
653
686
|
return;
|
|
654
|
-
this.addRoute(route);
|
|
687
|
+
this.addRoute(route, 'system');
|
|
655
688
|
});
|
|
656
689
|
}
|
|
657
|
-
update(
|
|
658
|
-
return __awaiter(this,
|
|
690
|
+
update(route_2) {
|
|
691
|
+
return __awaiter(this, arguments, void 0, function* (route, source = 'user') {
|
|
659
692
|
const existing = this.findCard(route);
|
|
660
693
|
if (existing)
|
|
661
694
|
existing.card.updateRoute(route);
|
|
@@ -701,8 +734,6 @@ let RouteListService = (() => {
|
|
|
701
734
|
});
|
|
702
735
|
}
|
|
703
736
|
startSync() {
|
|
704
|
-
if (!this.checkKomootFeatureEnabled())
|
|
705
|
-
return;
|
|
706
737
|
try {
|
|
707
738
|
if (!this.syncInfo.iv) {
|
|
708
739
|
this.syncInfo.iv = setInterval(() => this.performSync(), this.getSyncFrequency());
|
|
@@ -716,10 +747,6 @@ let RouteListService = (() => {
|
|
|
716
747
|
getSyncFrequency() {
|
|
717
748
|
return this.getUserSettings().get('syncFrequency', SYNC_INTERVAL);
|
|
718
749
|
}
|
|
719
|
-
checkKomootFeatureEnabled() {
|
|
720
|
-
const settings = (0, settings_1.useUserSettings)();
|
|
721
|
-
return settings.get('KOMOOT', false);
|
|
722
|
-
}
|
|
723
750
|
stopSync() {
|
|
724
751
|
var _a;
|
|
725
752
|
if (!this.syncInfo.iv)
|
|
@@ -739,8 +766,10 @@ let RouteListService = (() => {
|
|
|
739
766
|
this.syncInfo.observer = observer;
|
|
740
767
|
const onAdded = this.onSyncRouteAdded.bind(this);
|
|
741
768
|
const onUpdated = this.onSyncRouteUpdated.bind(this);
|
|
769
|
+
const onDeleted = this.onSyncRouteDeleted.bind(this);
|
|
742
770
|
observer.on('added', onAdded);
|
|
743
771
|
observer.on('updated', onUpdated);
|
|
772
|
+
observer.on('deleted', onDeleted);
|
|
744
773
|
observer.once('done', () => {
|
|
745
774
|
delete this.syncInfo.observer;
|
|
746
775
|
this.observer.emit('sync-done');
|
|
@@ -769,7 +798,8 @@ let RouteListService = (() => {
|
|
|
769
798
|
descriptions.forEach(descr => {
|
|
770
799
|
const route = new route_1.Route(descr);
|
|
771
800
|
this.db.save(route);
|
|
772
|
-
this.addRoute(route);
|
|
801
|
+
this.addRoute(route, 'system');
|
|
802
|
+
this.logEvent({ message: 'route added', route: route.description.title, source });
|
|
773
803
|
});
|
|
774
804
|
}
|
|
775
805
|
onSyncRouteUpdated(source, routes) {
|
|
@@ -777,7 +807,18 @@ let RouteListService = (() => {
|
|
|
777
807
|
descriptions.forEach(descr => {
|
|
778
808
|
const route = new route_1.Route(descr);
|
|
779
809
|
this.loadSyncedRouteDetails(route);
|
|
780
|
-
this.update(route);
|
|
810
|
+
this.update(route, 'system');
|
|
811
|
+
this.logEvent({ message: 'route updated', route: route.description.title, source });
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
onSyncRouteDeleted(source, routes) {
|
|
815
|
+
routes.forEach(id => {
|
|
816
|
+
const card = this.getCard(id);
|
|
817
|
+
if (card) {
|
|
818
|
+
card.delete({ source: 'system' });
|
|
819
|
+
const description = card.getRouteDescription();
|
|
820
|
+
this.logEvent({ message: 'route deleted', route: description === null || description === void 0 ? void 0 : description.title, source });
|
|
821
|
+
}
|
|
781
822
|
});
|
|
782
823
|
}
|
|
783
824
|
checkUIUpdateWithNoRepoStats() {
|
|
@@ -826,6 +867,8 @@ let RouteListService = (() => {
|
|
|
826
867
|
yield this.loadSyncedRouteDetails(route);
|
|
827
868
|
}
|
|
828
869
|
else {
|
|
870
|
+
const target = [{ route, added: false }];
|
|
871
|
+
yield this.api.loadDetails(target);
|
|
829
872
|
}
|
|
830
873
|
}
|
|
831
874
|
if (route.description.hasVideo) {
|
|
@@ -843,7 +886,7 @@ let RouteListService = (() => {
|
|
|
843
886
|
this.db.save(route, false);
|
|
844
887
|
})
|
|
845
888
|
.catch(err => {
|
|
846
|
-
|
|
889
|
+
this.logError(err, 'verifyRouteCountry', { id: route.description.id, title: route.description.title });
|
|
847
890
|
});
|
|
848
891
|
}
|
|
849
892
|
}
|
|
@@ -993,7 +1036,7 @@ let RouteListService = (() => {
|
|
|
993
1036
|
const legacyCard = this.myRoutes.getCards().find(c => { var _a, _b; return ((_b = (_a = c.getData()) === null || _a === void 0 ? void 0 : _a.description) === null || _b === void 0 ? void 0 : _b.id) === legacyId; });
|
|
994
1037
|
if (legacyCard) {
|
|
995
1038
|
this.myRoutes.remove(legacyCard);
|
|
996
|
-
const idx = this.routes.findIndex(r => r.description.id === legacyId);
|
|
1039
|
+
const idx = this.routes.findIndex(r => r.description.id === legacyId && !r.description.isDeleted);
|
|
997
1040
|
if (idx !== -1) {
|
|
998
1041
|
this.routes.splice(idx, 1);
|
|
999
1042
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LatLng } from "../../utils/geo";
|
|
2
|
+
import { RouteInfo } from "../base/types";
|
|
2
3
|
import { SummaryCardDisplayProps } from "./cards/RouteCard";
|
|
3
4
|
import { RouteCardType } from "./cards/types";
|
|
4
5
|
export interface RouteStartSettings {
|
|
@@ -37,13 +38,14 @@ export interface SearchFilter {
|
|
|
37
38
|
country?: string;
|
|
38
39
|
contentType?: string;
|
|
39
40
|
routeType?: string;
|
|
40
|
-
|
|
41
|
+
routeSource?: string;
|
|
41
42
|
includeDeleted?: boolean;
|
|
42
43
|
}
|
|
43
44
|
export interface SearchFilterOptions {
|
|
44
45
|
countries: Array<string>;
|
|
45
46
|
contentTypes: Array<string>;
|
|
46
47
|
routeTypes: Array<string>;
|
|
48
|
+
routeSources: Array<string>;
|
|
47
49
|
}
|
|
48
50
|
export interface RoutesRepoUpdates {
|
|
49
51
|
prev?: number;
|
|
@@ -58,4 +60,5 @@ export interface IRouteList {
|
|
|
58
60
|
searchRepo(requestedFilters?: SearchFilter): {
|
|
59
61
|
routes: Array<SummaryCardDisplayProps>;
|
|
60
62
|
};
|
|
63
|
+
getAllAppRoutes(source: string): Array<RouteInfo>;
|
|
61
64
|
}
|
|
@@ -90,6 +90,7 @@ let RouteSyncFactory = (() => {
|
|
|
90
90
|
syncs[service] = so;
|
|
91
91
|
so.on('added', (info) => observer.emit('added', service, info));
|
|
92
92
|
so.on('updated', (routes) => observer.emit('updated', service, routes));
|
|
93
|
+
so.on('deleted', (routes) => observer.emit('deleted', service, routes));
|
|
93
94
|
so.on('details', (route) => observer.emit('details', service, route));
|
|
94
95
|
so.on('done', () => {
|
|
95
96
|
delete syncs[service];
|
|
@@ -7,6 +7,11 @@ import { RouteInfo, RoutePoint } from "../../base/types";
|
|
|
7
7
|
import { IRouteList } from "../../list/types";
|
|
8
8
|
import { RouteSyncFactory } from "../factory";
|
|
9
9
|
import { IRouteSyncProvider } from "../types";
|
|
10
|
+
interface SyncModifications {
|
|
11
|
+
added: Array<KomootTourSummary>;
|
|
12
|
+
updated: Array<Route>;
|
|
13
|
+
deleted: Array<string>;
|
|
14
|
+
}
|
|
10
15
|
export declare class KomootSyncProvider extends IncyclistService implements IRouteSyncProvider {
|
|
11
16
|
protected lastSyncTS: number;
|
|
12
17
|
protected observer: Observer;
|
|
@@ -18,18 +23,23 @@ export declare class KomootSyncProvider extends IncyclistService implements IRou
|
|
|
18
23
|
protected getKomootId(route: Route): number;
|
|
19
24
|
protected stopSync(): void;
|
|
20
25
|
protected loadTours(): Promise<Array<KomootTourSummary>>;
|
|
21
|
-
protected
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
protected emitUpdates(added: KomootTourSummary[], updated: Route[], deleted: string[]): void;
|
|
27
|
+
protected loadToursFromApi(): Promise<{
|
|
28
|
+
tours: Array<KomootTourSummary>;
|
|
29
|
+
done: boolean;
|
|
30
|
+
}>;
|
|
31
|
+
protected checkTours(tours: Array<KomootTourSummary>): SyncModifications;
|
|
25
32
|
protected buildRouteInfo(tour: KomootTourSummary): RouteInfo;
|
|
26
33
|
protected adddRouteDetails(route: Route, coordinates: Array<KomootCoordinate>): Promise<void>;
|
|
27
34
|
protected buildRoutePoints(coordinates: KomootCoordinate[], points: RoutePoint[]): RoutePoint[];
|
|
28
35
|
protected emitAdded(tours: Array<KomootTourSummary>): void;
|
|
29
36
|
protected emitUpdated(routes: Array<Route>): void;
|
|
37
|
+
protected emitDeleted(routes: Array<string>): void;
|
|
30
38
|
protected getLastSyncTime(): Date;
|
|
31
39
|
protected getSportFilter(): string;
|
|
40
|
+
protected getAvailableSports(): Array<string>;
|
|
32
41
|
protected getCreatedFilter(days?: number): Date;
|
|
42
|
+
protected updateLastSyncTime(): void;
|
|
33
43
|
protected saveLastSyncTime(): void;
|
|
34
44
|
protected getUserSettings(): import("../../../settings").UserSettingsService;
|
|
35
45
|
protected getRouteListService(): IRouteList;
|
|
@@ -38,3 +48,4 @@ export declare class KomootSyncProvider extends IncyclistService implements IRou
|
|
|
38
48
|
protected getKomootAppConnection(): KomootAppConnection;
|
|
39
49
|
protected getAppsService(): import("../../../apps").AppsService;
|
|
40
50
|
}
|
|
51
|
+
export {};
|
|
@@ -56,6 +56,14 @@ const geo_1 = require("../../../utils/geo");
|
|
|
56
56
|
const route_1 = require("../../base/model/route");
|
|
57
57
|
const factory_1 = require("../factory");
|
|
58
58
|
const PAGE_LIMIT = 50;
|
|
59
|
+
const SPORTS_FILTER = 'racebike';
|
|
60
|
+
const sportsOptions = {
|
|
61
|
+
touringbicycle: 'Cycling',
|
|
62
|
+
mtb: 'Mountain biking',
|
|
63
|
+
racebike: 'Road cycling',
|
|
64
|
+
mtb_easy: 'Gravel riding',
|
|
65
|
+
mtb_advancde: 'Enduro mountain biking'
|
|
66
|
+
};
|
|
59
67
|
let KomootSyncProvider = (() => {
|
|
60
68
|
var _a;
|
|
61
69
|
let _classSuper = service_1.IncyclistService;
|
|
@@ -127,32 +135,48 @@ let KomootSyncProvider = (() => {
|
|
|
127
135
|
return [];
|
|
128
136
|
}
|
|
129
137
|
this.logEvent({ message: 'start komoot route sync' });
|
|
138
|
+
const { tours, done } = yield this.loadToursFromApi();
|
|
139
|
+
if (done) {
|
|
140
|
+
const { added, updated, deleted } = this.checkTours(tours);
|
|
141
|
+
this.updateLastSyncTime();
|
|
142
|
+
this.observer.emit('done');
|
|
143
|
+
this.logEvent({ message: 'komoot route sync finished', added: added === null || added === void 0 ? void 0 : added.length, updated: updated === null || updated === void 0 ? void 0 : updated.length, deleted: deleted.length });
|
|
144
|
+
return added;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
this.observer.emit('done');
|
|
148
|
+
this.logEvent({ message: 'komoot route sync stopped' });
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
emitUpdates(added, updated, deleted) {
|
|
154
|
+
if (added.length > 0) {
|
|
155
|
+
this.emitAdded(added);
|
|
156
|
+
}
|
|
157
|
+
if (updated.length > 0) {
|
|
158
|
+
this.emitUpdated(updated);
|
|
159
|
+
}
|
|
160
|
+
if (deleted.length > 0) {
|
|
161
|
+
this.emitDeleted(deleted);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
loadToursFromApi() {
|
|
165
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
130
166
|
const api = this.getKomootApi();
|
|
131
167
|
let page = 0;
|
|
132
168
|
let done = false;
|
|
133
169
|
const tours = [];
|
|
134
|
-
let cntAdded = 0;
|
|
135
|
-
let cntUpdated = 0;
|
|
136
170
|
while (!done && !this.stopRequested) {
|
|
137
171
|
try {
|
|
138
|
-
const filters = {
|
|
172
|
+
const filters = { sport: this.getSportFilter(), after: this.getCreatedFilter() };
|
|
139
173
|
const pageTours = yield api.getTours({ type: 'tour_planned', page, limit: PAGE_LIMIT }, filters);
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
if (added.length > 0) {
|
|
143
|
-
cntAdded += added.length;
|
|
144
|
-
this.emitAdded(added);
|
|
145
|
-
tours.push(...added);
|
|
146
|
-
}
|
|
147
|
-
if (updated.length > 0) {
|
|
148
|
-
cntUpdated += updated.length;
|
|
149
|
-
this.emitUpdated(updated);
|
|
150
|
-
}
|
|
174
|
+
if (pageTours.length > 0) {
|
|
175
|
+
tours.push(...pageTours);
|
|
151
176
|
page++;
|
|
152
177
|
}
|
|
153
|
-
else
|
|
178
|
+
else
|
|
154
179
|
done = true;
|
|
155
|
-
}
|
|
156
180
|
yield (0, utils_1.sleep)(100);
|
|
157
181
|
}
|
|
158
182
|
catch (err) {
|
|
@@ -160,18 +184,13 @@ let KomootSyncProvider = (() => {
|
|
|
160
184
|
done = true;
|
|
161
185
|
}
|
|
162
186
|
}
|
|
163
|
-
|
|
164
|
-
this.lastSyncTS = Date.now();
|
|
165
|
-
this.saveLastSyncTime();
|
|
166
|
-
}
|
|
167
|
-
this.logEvent({ message: 'komoot route sync finished', added: cntAdded, updated: cntUpdated });
|
|
168
|
-
this.observer.emit('done');
|
|
169
|
-
return tours;
|
|
187
|
+
return { tours, done };
|
|
170
188
|
});
|
|
171
189
|
}
|
|
172
190
|
checkTours(tours) {
|
|
173
|
-
var _b, _c
|
|
174
|
-
const routes = (
|
|
191
|
+
var _b, _c;
|
|
192
|
+
const routes = (_c = (_b = this.getRouteListService()) === null || _b === void 0 ? void 0 : _b.getAllAppRoutes('komoot')) !== null && _c !== void 0 ? _c : [];
|
|
193
|
+
const matched = routes.map(r => ({ id: r.id, matched: false }));
|
|
175
194
|
const added = [];
|
|
176
195
|
const updated = [];
|
|
177
196
|
tours.forEach(tour => {
|
|
@@ -181,7 +200,15 @@ let KomootSyncProvider = (() => {
|
|
|
181
200
|
if (!route) {
|
|
182
201
|
added.push(tour);
|
|
183
202
|
}
|
|
203
|
+
else if (route.isDeleted) {
|
|
204
|
+
const matchRecord = matched.find(r => r.id === id);
|
|
205
|
+
if (matchRecord)
|
|
206
|
+
matchRecord.matched = true;
|
|
207
|
+
}
|
|
184
208
|
else {
|
|
209
|
+
const matchRecord = matched.find(r => r.id === id);
|
|
210
|
+
if (matchRecord)
|
|
211
|
+
matchRecord.matched = true;
|
|
185
212
|
const routeTS = (_b = route.tsLastChange) !== null && _b !== void 0 ? _b : 0;
|
|
186
213
|
const tourTS = (new Date(tour.changed_at)).valueOf();
|
|
187
214
|
if (tourTS > routeTS) {
|
|
@@ -190,7 +217,10 @@ let KomootSyncProvider = (() => {
|
|
|
190
217
|
}
|
|
191
218
|
}
|
|
192
219
|
});
|
|
193
|
-
|
|
220
|
+
const unmatched = matched.filter(r => !r.matched);
|
|
221
|
+
const deleted = unmatched.map(r => r.id);
|
|
222
|
+
this.emitUpdates(added, updated, deleted);
|
|
223
|
+
return { added, updated, deleted };
|
|
194
224
|
}
|
|
195
225
|
buildRouteInfo(tour) {
|
|
196
226
|
var _b;
|
|
@@ -203,7 +233,7 @@ let KomootSyncProvider = (() => {
|
|
|
203
233
|
distance: tour.distance,
|
|
204
234
|
category: 'external',
|
|
205
235
|
source: 'komoot',
|
|
206
|
-
previewUrl: (_b = tour.
|
|
236
|
+
previewUrl: (_b = tour.vector_map_image_preview) === null || _b === void 0 ? void 0 : _b.src,
|
|
207
237
|
tsLastChange: (new Date(tour.changed_at)).valueOf()
|
|
208
238
|
};
|
|
209
239
|
return info;
|
|
@@ -288,6 +318,9 @@ let KomootSyncProvider = (() => {
|
|
|
288
318
|
emitUpdated(routes) {
|
|
289
319
|
this.observer.emit('updated', routes);
|
|
290
320
|
}
|
|
321
|
+
emitDeleted(routes) {
|
|
322
|
+
this.observer.emit('deleted', routes);
|
|
323
|
+
}
|
|
291
324
|
getLastSyncTime() {
|
|
292
325
|
var _b;
|
|
293
326
|
const lastSyncTS = (_b = this.lastSyncTS) !== null && _b !== void 0 ? _b : 0;
|
|
@@ -295,11 +328,19 @@ let KomootSyncProvider = (() => {
|
|
|
295
328
|
return this.lastSyncTS > 0 ? new Date(this.lastSyncTS) : undefined;
|
|
296
329
|
}
|
|
297
330
|
getSportFilter() {
|
|
298
|
-
return
|
|
331
|
+
return SPORTS_FILTER;
|
|
332
|
+
}
|
|
333
|
+
getAvailableSports() {
|
|
334
|
+
const keys = Object.keys(sportsOptions);
|
|
335
|
+
return keys.map(sport => sportsOptions[sport]);
|
|
299
336
|
}
|
|
300
337
|
getCreatedFilter(days = 365) {
|
|
301
338
|
return new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
302
339
|
}
|
|
340
|
+
updateLastSyncTime() {
|
|
341
|
+
this.lastSyncTS = Date.now();
|
|
342
|
+
this.saveLastSyncTime();
|
|
343
|
+
}
|
|
303
344
|
saveLastSyncTime() {
|
|
304
345
|
if (!this.lastSyncTS)
|
|
305
346
|
return;
|