Skip to content

Commit 0497ddf

Browse files
committed
Merge branch 'release/v1.0'
2 parents ae458fa + b55656a commit 0497ddf

47 files changed

Lines changed: 10964 additions & 8478 deletions

Some content is hidden

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

.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
.env*
44
.gitignore
55
dist
6+
logs
67
test
8+
.github
79
node_modules
810
Procfile
911
README.md

.env.example

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,9 @@ PORT=3000
1717
LOG_LEVEL='debug'
1818

1919
# App endpoint prefix
20-
ENDPOINT_PREFIX='api'
20+
ENDPOINT_PREFIX='api'
21+
22+
# Send grid API key
23+
SENDGRID_API_KEY=''
24+
SENDGRID_SEND_EMAIL=''
25+
SENDGRID_REPLY_EMAIL=''

.github/workflows/cd.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,9 @@ jobs:
3131
context: .
3232
push: true
3333
tags: registry.vecolo.fr/veapi-ci:latest
34+
35+
- name: Trigger API Webhook reload service
36+
uses: joelwmale/webhook-action@2.1.0
37+
with:
38+
url: ${{ secrets.WEBHOOK_URL }}
39+

Dockerfile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ WORKDIR /usr/app
1212
COPY package*.json ormconfig.js ./
1313
RUN npm ci --production
1414

15+
VOLUME /usr/app/upload
16+
VOLUME /usr/app/logs
17+
1518
COPY --from=builder /usr/app/dist ./dist
19+
COPY ./media ./media
1620

1721
ENV JWT_SECRET ='mon-token-secret' \
1822
DB_TYPE='mariadb' \
@@ -24,7 +28,12 @@ ENV JWT_SECRET ='mon-token-secret' \
2428
PORT=3000 \
2529
LOG_LEVEL='debug' \
2630
ENDPOINT_PREFIX='' \
27-
NODE_ENV='production'
31+
NODE_ENV='production'\
32+
SENDGRID_API_KEY=''\
33+
SENDGRID_SEND_EMAIL=''\
34+
SENDGRID_REPLY_EMAIL=''\
35+
RECAPTCHA_KEY=''
36+
2837

2938
EXPOSE 3000
3039
CMD node dist/app.js

commands/seed.ts

Lines changed: 0 additions & 49 deletions
This file was deleted.

commands/seed_bike.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import Logger from '../src/logger';
2+
import BikeModelService from '../src/api/services/BikeModelService';
3+
import {Container} from 'typedi';
4+
import databaseLoader from '../src/loaders/database';
5+
import BikeService from '../src/api/services/BikeService';
6+
import {BikeModel} from '../src/api/entities/BikeModel';
7+
import {Bike, BikeStatus} from '../src/api/entities/Bike';
8+
9+
const fillCount = 5;
10+
11+
const run = async () => {
12+
Container.set('logger', Logger);
13+
const log = Logger.info;
14+
const connection = await databaseLoader();
15+
log('Database connection loaded successfully!');
16+
17+
const bikeModelService: BikeModelService = Container.get(BikeModelService);
18+
const bikeService: BikeService = Container.get(BikeService);
19+
20+
const modelList: BikeModel[] = await bikeModelService.getRepo().find();
21+
const enumStatus = [
22+
BikeStatus.OFF,
23+
BikeStatus.RECHARGING,
24+
BikeStatus.IN_RIDE,
25+
BikeStatus.MAINTAINING,
26+
];
27+
28+
for (let i = 0; i < fillCount; i++) {
29+
let matriculate;
30+
while (!matriculate) {
31+
matriculate = Math.floor(100000 + Math.random() * 100000).toString();
32+
if (await bikeService.getRepo().findOne({where: {matriculate}})) {
33+
matriculate = undefined;
34+
}
35+
}
36+
const bike: Partial<Bike> = {
37+
matriculate,
38+
model: modelList[Math.floor(Math.random() * 1000) % modelList.length],
39+
status: enumStatus[Math.floor(Math.random() * 100) % enumStatus.length],
40+
recharging: true,
41+
batteryPercent: Math.floor(Math.random() * 100),
42+
station: null
43+
};
44+
const bikeDB = await bikeService.getRepo().save(bike);
45+
log(`Bike ${bikeDB.id} inserted (${i + 1}/${fillCount})`);
46+
}
47+
};
48+
49+
50+
run().then(r => console.log('Bikes Seeded'));

commands/seed_bike_on_station.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import Logger from '../src/logger';
2+
import {Container} from 'typedi';
3+
import databaseLoader from '../src/loaders/database';
4+
import BikeService from '../src/api/services/BikeService';
5+
import {Bike} from '../src/api/entities/Bike';
6+
import StationService from '../src/api/services/StationService';
7+
8+
const fillStationPercent = 90;
9+
10+
const run = async () => {
11+
Container.set('logger', Logger);
12+
const log = Logger.info;
13+
const connection = await databaseLoader();
14+
log('Database connection loaded successfully!');
15+
16+
const bikeService: BikeService = Container.get(BikeService);
17+
const stationService: StationService = Container.get(StationService);
18+
19+
const bikeList: Bike[] = await bikeService.getRepo().find({where: {station: null}});
20+
for (const bike of bikeList) {
21+
const station = await stationService.getRepo().createQueryBuilder('station')
22+
.leftJoin('bike', 'b', 'b.stationId = station.id')
23+
.select()
24+
.addSelect('count(distinct b.id) as bikeCount')
25+
.groupBy('station.id, station.bikeCapacity')
26+
.having(`bikeCount < ROUND(station.bikeCapacity * ${fillStationPercent} / 100)`)
27+
.getOne();
28+
if (!station) {
29+
log('Can\'t fill anymore station !');
30+
return;
31+
}
32+
bike.station = station;
33+
await bikeService.update(bike.id, bike);
34+
log(`Bike ${bike.id} attached to station ${station.id}`);
35+
}
36+
};
37+
38+
39+
run().then(r => console.log('Bikes on station Seeded'));

commands/seed_ride.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import Logger from '../src/logger';
2+
import {Container} from 'typedi';
3+
import databaseLoader from '../src/loaders/database';
4+
import RideService from '../src/api/services/RideService';
5+
import UserService from '../src/api/services/UserService';
6+
import {User} from '../src/api/entities/User';
7+
import BikeService from '../src/api/services/BikeService';
8+
import {Station} from '../src/api/entities/Station';
9+
import StationService from '../src/api/services/StationService';
10+
import {Bike} from '../src/api/entities/Bike';
11+
import {Ride} from '../src/api/entities/Ride';
12+
import {addDays, addMinutes, differenceInCalendarDays} from 'date-fns';
13+
14+
const rideCount = 10;
15+
const start = new Date();
16+
const end = new Date('2021-07-26');
17+
const difference = differenceInCalendarDays(end, start);
18+
19+
const run = async () => {
20+
Container.set('logger', Logger);
21+
const log = Logger.info;
22+
const connection = await databaseLoader();
23+
log('Database connection loaded successfully!');
24+
25+
const rideService: RideService = Container.get(RideService);
26+
const userService: UserService = Container.get(UserService);
27+
const bikeService: BikeService = Container.get(BikeService);
28+
const stationService: StationService = Container.get(StationService);
29+
30+
const userIds: { id: number }[] = await userService.getRepo().createQueryBuilder('user')
31+
.select('id')
32+
.getRawMany();
33+
34+
const stationIds: { id: number }[] = await stationService.getRepo().createQueryBuilder('station')
35+
.select('id')
36+
.getRawMany();
37+
38+
for (let i = 0; i < rideCount; i++) {
39+
const user: User = await userService.findOne(userIds[Math.floor(Math.random() * 10000 % userIds.length)].id);
40+
if (user.subscriptions?.length == 0) {
41+
log(`User ${user.id} don't have subscription, skipping...`);
42+
i--;
43+
continue;
44+
}
45+
const startDate = addDays(start, Math.floor(Math.random() * difference));
46+
const rideDuration = 1 + Math.floor(Math.random() * 60);
47+
const endDate = addMinutes(startDate, rideDuration);
48+
49+
const startStation: Station = await stationService.findOne(stationIds[Math.floor(Math.random() * 10000 % stationIds.length)].id);
50+
const endStation: Station = await stationService.getRepo().createQueryBuilder('station')
51+
.leftJoin('bike', 'b', 'b.stationId = station.id')
52+
.select()
53+
.addSelect('count(distinct b.id) as bikeCount')
54+
.groupBy('station.id, station.bikeCapacity')
55+
.having(`bikeCount < station.bikeCapacity`)
56+
.getOne();
57+
58+
const availableBikes: Bike[] = await bikeService.getAllFromStation(startStation.id, {limit: 100, offset: 0});
59+
if (availableBikes.length == 0) {
60+
log('Start station don\'t have available bikes, skipping...');
61+
i--;
62+
continue;
63+
}
64+
65+
const ride: Ride = await rideService.startRide(
66+
availableBikes[Math.floor(Math.random() * 10000 % availableBikes.length)],
67+
startStation,
68+
user,
69+
startDate
70+
);
71+
await rideService.endRide(
72+
user,
73+
ride,
74+
endStation,
75+
Math.floor(rideDuration * Math.random() * 20),
76+
endDate
77+
);
78+
log(`Ride ${ride.id} inserted (${i + 1}/${rideCount})`);
79+
}
80+
81+
82+
};
83+
84+
85+
run().then(r => console.log('Rides Seeded'));

media/vecolo.png

22.7 KB
Loading

0 commit comments

Comments
 (0)