Skip to content

Commit

Permalink
Add Blacklisting API (#142)
Browse files Browse the repository at this point in the history
* Add Blacklisting API

	Enables fast checking of some necessary conditions for new the
	viability of new Tours.

* wip

* wip

* Change constat MAX_PASSENGER_WAITING_TIME

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Add tests for blacklisting API

* Remove unnecessary tests

* wip

* wip

* Format

* wip

* Run unit tests when db is set up

* wip

* wip

* Format

* wip

* wip

* Remove unused import

* Split blacklist Query into multiple functions

* Move sql for checking if a zone covers a point into its' own function

* Add variables for readability in blacklisting API

* Format

* wip

* wip

* Rename variable

* wip

---------

Co-authored-by: nils_penzel <penzel.nils @web.de>
  • Loading branch information
nilspenzel and nils_penzel authored Sep 19, 2024
1 parent 90785a6 commit 4ef43f3
Show file tree
Hide file tree
Showing 13 changed files with 812 additions and 15 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ jobs:
- name: Svelte Check
run: npm run check

- name: Unit Tests
run: npm run test:unit

- name: Install Playwright Dependencies
run: npx playwright install --with-deps

Expand All @@ -45,6 +42,9 @@ jobs:
echo "CREATE DATABASE prima;" | PGPASSWORD=pw psql postgresql://localhost:6500 --user postgres
npx playwright test
- name: Unit Tests
run: npm run test:unit

- name: Docker setup-buildx
uses: docker/setup-buildx-action@v3
with:
Expand Down
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@sveltejs/kit": "^2.5.18",
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@types/eslint": "^8.56.10",
"@types/jsonschema": "^1.1.1",
"@types/pg": "^8.11.6",
"@typescript-eslint/eslint-plugin": "^7.16.1",
"@typescript-eslint/parser": "^7.16.1",
Expand Down Expand Up @@ -51,6 +52,7 @@
"clsx": "^2.1.1",
"formsnap": "^1.0.1",
"geojson": "^0.5.0",
"jsonschema": "^1.4.1",
"kysely": "^0.27.4",
"lucia": "^3.2.0",
"lucide-svelte": "^0.379.0",
Expand Down
83 changes: 83 additions & 0 deletions src/lib/bookingApiParameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { BusStop } from './busStop';
import type { Capacities } from './capacities';
import type { Coordinates } from './location';

export type BookingRequestParameters = {
userChosen: Coordinates;
busStops: BusStop[];
startFixed: boolean;
capacities: Capacities;
};

export const schema = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
definitions: {
coordinates: {
type: 'object',
properties: {
lat: {
type: 'number',
minimum: -90,
maximum: 90
},
lng: {
type: 'number',
minimum: -180,
maximum: 180
}
},
required: ['lat', 'lng']
}
},
properties: {
userChosen: {
$ref: '#/definitions/coordinates'
},
busStops: {
type: 'array',
items: {
type: 'object',
properties: {
coordinates: {
$ref: '#/definitions/coordinates'
},
times: {
type: 'array',
items: {
type: 'string',
format: 'date-time'
}
}
},
required: ['coordinates', 'times']
}
},
startFixed: {
type: 'boolean'
},
capacities: {
type: 'object',
properties: {
passengers: {
type: 'integer',
minimum: 0
},
wheelchairs: {
type: 'integer',
minimum: 0
},
bikes: {
type: 'integer',
minimum: 0
},
luggage: {
type: 'integer',
minimum: 0
}
},
required: ['passengers', 'wheelchairs', 'bikes', 'luggage']
}
},
required: ['userChosen', 'busStops', 'startFixed', 'capacities']
};
6 changes: 6 additions & 0 deletions src/lib/busStop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { Coordinates } from './location';

export type BusStop = {
coordinates: Coordinates;
times: Date[];
};
5 changes: 4 additions & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { hoursToMs } from './time_utils';
import { hoursToMs, minutesToMs } from './time_utils';

export const TZ = 'Europe/Berlin';
export const MIN_PREP_MINUTES = 30;
export const MAX_TRAVEL_DURATION = hoursToMs(1);
export const MAX_PASSENGER_WAITING_TIME_PICKUP = minutesToMs(10);
export const MAX_PASSENGER_WAITING_TIME_DROPOFF = minutesToMs(10);
export const SRID = 4326;
12 changes: 12 additions & 0 deletions src/lib/sqlHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { db } from '$lib/database';
import { sql } from 'kysely';
import type { Coordinates } from './location';
import type { ExpressionBuilder, RawBuilder } from 'kysely';
import type { Database } from './types';
import { SRID } from './constants';

export const queryCompletedTours = async (companyId: number | undefined) => {
return await db
Expand All @@ -21,3 +26,10 @@ export const queryCompletedTours = async (companyId: number | undefined) => {
])
.execute();
};

export const covers = (
eb: ExpressionBuilder<Database, 'zone'>,
coordinates: Coordinates
): RawBuilder<boolean> => {
return sql<boolean>`ST_Covers(zone.area, ST_SetSRID(ST_MakePoint(${coordinates!.lng}, ${coordinates!.lat}),${SRID}))`;
};
59 changes: 59 additions & 0 deletions src/lib/testHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { Capacities } from './capacities';
import { db } from './database';

let plate = 1;

export enum Zone {
ALTKREIS_BAUTZEN = 1,
WEIßWASSER = 2,
NIESKY = 3,
GÖRLITZ = 4,
LÖBAU = 5,
ZITTAU = 6
}

export const addCompany = async (zone: Zone): Promise<number> => {
return (
await db.insertInto('company').values({ zone: zone }).returning('id').executeTakeFirstOrThrow()
).id;
};

export const addTaxi = async (company: number, capacities: Capacities): Promise<number> => {
++plate;
return (
await db
.insertInto('vehicle')
.values({
license_plate: String(plate),
company,
seats: capacities.passengers,
wheelchair_capacity: capacities.wheelchairs,
bike_capacity: capacities.bikes,
storage_space: capacities.luggage
})
.returning('id')
.executeTakeFirstOrThrow()
).id;
};

export const setAvailability = async (vehicle: number, start_time: Date, end_time: Date) => {
await db.insertInto('availability').values({ vehicle, start_time, end_time }).execute();
};

export const setTour = async (vehicle: number, departure: Date, arrival: Date) => {
await db.insertInto('tour').values({ vehicle, arrival, departure }).execute();
};

export const clearDatabase = async () => {
await Promise.all([
db.deleteFrom('address').execute(),
db.deleteFrom('availability').execute(),
db.deleteFrom('event').execute(),
db.deleteFrom('request').execute(),
db.deleteFrom('tour').execute(),
db.deleteFrom('vehicle').execute(),
db.deleteFrom('user_session').execute(),
db.deleteFrom('auth_user').execute(),
db.deleteFrom('company').execute()
]);
};
6 changes: 2 additions & 4 deletions src/routes/(user)/company/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { fail } from '@sveltejs/kit';
import { db } from '$lib/database';
import { AddressGuess, geoCode } from '$lib/api.js';
import { sql } from 'kysely';
import { covers } from '$lib/sqlHelpers.js';

export const load: PageServerLoad = async (event) => {
const companyId = event.locals.user?.company;
Expand Down Expand Up @@ -75,10 +76,7 @@ export const actions = {
!(await db
.selectFrom('zone')
.where((eb) =>
eb.and([
eb('zone.id', '=', community_area),
sql<boolean>`ST_Covers(zone.area, ST_SetSRID(ST_MakePoint(${bestAddressGuess!.pos.lng}, ${bestAddressGuess!.pos.lat}),4326))`
])
eb.and([eb('zone.id', '=', community_area), covers(eb, bestAddressGuess!.pos)])
)
.executeTakeFirst())
) {
Expand Down
27 changes: 27 additions & 0 deletions src/routes/api/blacklisting/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Validator } from 'jsonschema';
import { getViableBusStops } from './viableBusStops';
import type { RequestEvent } from './$types';
import { json } from '@sveltejs/kit';
import { schema } from '$lib/bookingApiParameters';

export const POST = async (event: RequestEvent) => {
const parameters = await event.request.json();
const validator = new Validator();
const result = validator.validate(parameters, schema);
if (!result.valid) {
return json(
{
message: result.errors
},
{ status: 400 }
);
}
return json(
getViableBusStops(
parameters.userChosen,
parameters.busStops,
parameters.startFixed,
parameters.capacities
)
);
};
Loading

0 comments on commit 4ef43f3

Please sign in to comment.