Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion e2e/availability.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
COMPANY1,
moveMouse,
offset,
dayString
dayString,
logout
} from './utils';

test.describe.configure({ mode: 'serial' });
Expand Down Expand Up @@ -87,4 +88,37 @@ test('Request ride', async ({ page }) => {
'background-color',
'rgb(251, 146, 60)'
);
await logout(page);
});

test('Get availability', async ({ page }) => {
await login(page, TAXI_OWNER);

const response = await page
.context()
.request.get(`/taxi/availability/api/availability?offset=${offset}&date=${dayString}`);
expect(response.status()).toBe(200);

const responseBody = await response.json();
expect(responseBody).toHaveProperty('tours');
expect(responseBody).toHaveProperty('vehicles');
expect(responseBody).not.toHaveProperty('companyDataComplete');
expect(responseBody).not.toHaveProperty('companyCoordinates');
expect(responseBody).not.toHaveProperty('utcDate');

const vehicles = responseBody['vehicles'];
expect(vehicles).toHaveLength(1);
expect(vehicles[0].availability).not.toHaveLength(0);

const response2 = await page
.context()
.request.get(`/taxi/availability/api/availability?offset=NaN&date=${dayString}`);
expect(response2.status()).toBe(400);

const response3 = await page
.context()
.request.get(`/taxi/availability/api/availability?offset=${offset}&date=noDate`);
expect(response3.status()).toBe(400);

await logout(page);
});
8 changes: 2 additions & 6 deletions e2e/rideShare.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
login,
RIDE_SHARE_CUSTOMER,
execSQL,
UserCredentials
UserCredentials,
logout
} from './utils';
import { sql } from 'kysely';

Expand Down Expand Up @@ -103,11 +104,6 @@ async function chooseFromTypeAhead(
await suggestion.click();
}

async function logout(page: Page) {
await page.goto('/account/settings');
await page.getByRole('button', { name: 'Abmelden' }).click();
}

async function isFeedbackBannerVisible(page: Page, user: UserCredentials, xpct: boolean) {
await login(page, user);
await page.goto('/routing');
Expand Down
5 changes: 5 additions & 0 deletions e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,8 @@ export async function moveMouse(page: Page, id: string) {
const { x, y, width, height } = (await element.boundingBox())!;
await page.mouse.move(x + width / 2, y + height / 2);
}

export async function logout(page: Page) {
await page.goto('/account/settings');
await page.getByRole('button', { name: 'Abmelden' }).click();
}
55 changes: 55 additions & 0 deletions src/lib/server/getAvailability.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { db } from '$lib/server/db';
import { jsonArrayFrom } from 'kysely/helpers/postgres';
import { getToursWithRequests } from '$lib/server/db/getTours.js';

export async function getAvailability(utcDate: Date, companyId: number) {
const fromTime = new Date(utcDate);
fromTime.setHours(utcDate.getHours() - 1);
const toTime = new Date(utcDate);
toTime.setHours(utcDate.getHours() + 25);

const vehicles = db
.selectFrom('vehicle')
.where('company', '=', companyId)
.selectAll()
.select((eb) => [
jsonArrayFrom(
eb
.selectFrom('availability')
.whereRef('availability.vehicle', '=', 'vehicle.id')
.where('availability.startTime', '<', toTime.getTime())
.where('availability.endTime', '>', fromTime.getTime())
.select(['availability.id', 'availability.startTime', 'availability.endTime'])
.orderBy('availability.startTime')
).as('availability')
])
.execute();

const tours = getToursWithRequests(false, companyId, [fromTime.getTime(), toTime.getTime()]);

const company = await db
.selectFrom('company')
.where('id', '=', companyId)
.selectAll()
.executeTakeFirstOrThrow();

const companyDataComplete =
company.name !== null &&
company.address !== null &&
company.zone !== null &&
company.lat !== null &&
company.lng !== null;

return {
tours: await tours,
vehicles: await vehicles,
utcDate,
companyDataComplete,
companyCoordinates: companyDataComplete
? {
lat: company.lat!,
lng: company.lng!
}
: null
};
}
62 changes: 8 additions & 54 deletions src/routes/taxi/availability/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,30 @@
import { db } from '$lib/server/db';
import { getToursWithRequests } from '$lib/server/db/getTours.js';
import { jsonArrayFrom } from 'kysely/helpers/postgres';
import type { Actions, RequestEvent } from './$types';
import { fail } from '@sveltejs/kit';
import { msg } from '$lib/msg';
import { readInt } from '$lib/server/util/readForm';
import { getPossibleInsertions } from '$lib/util/booking/getPossibleInsertions';
import { retry } from '$lib/server/db/retryQuery';
import { LICENSE_PLATE_REGEX } from '$lib/constants';
import { getAvailability } from '$lib/server/getAvailability.js';

const LICENSE_PLATE_REGEX = /^([A-ZÄÖÜ]{1,3})-([A-ZÄÖÜ]{1,2})-([0-9]{1,4})$/;

export async function load(event: RequestEvent) {
const companyId = event.locals.session?.companyId;
if (!companyId) {
throw 'company not defined';
}

const url = event.url;
const localDateParam = url.searchParams.get('date');
const timezoneOffset = url.searchParams.get('offset');
const localDateParam = event.url.searchParams.get('date');
const timezoneOffset = event.url.searchParams.get('offset');

const utcDate =
localDateParam && timezoneOffset
? new Date(new Date(localDateParam!).getTime() + Number(timezoneOffset) * 60 * 1000)
: new Date();
const fromTime = new Date(utcDate);
fromTime.setHours(utcDate.getHours() - 1);
const toTime = new Date(utcDate);
toTime.setHours(utcDate.getHours() + 25);

const vehicles = db
.selectFrom('vehicle')
.where('company', '=', companyId)
.selectAll()
.select((eb) => [
jsonArrayFrom(
eb
.selectFrom('availability')
.whereRef('availability.vehicle', '=', 'vehicle.id')
.where('availability.startTime', '<', toTime.getTime())
.where('availability.endTime', '>', fromTime.getTime())
.select(['availability.id', 'availability.startTime', 'availability.endTime'])
.orderBy('availability.startTime')
).as('availability')
])
.execute();

const tours = getToursWithRequests(false, companyId, [fromTime.getTime(), toTime.getTime()]);

const company = await db
.selectFrom('company')
.where('id', '=', companyId)
.selectAll()
.executeTakeFirstOrThrow();

const companyDataComplete =
company.name !== null &&
company.address !== null &&
company.zone !== null &&
company.lat !== null &&
company.lng !== null;

return {
tours: await tours,
vehicles: await vehicles,
utcDate,
companyDataComplete,
companyCoordinates: companyDataComplete
? {
lat: company.lat!,
lng: company.lng!
}
: null
};

return getAvailability(utcDate, companyId);
}

export const actions: Actions = {
Expand Down
31 changes: 30 additions & 1 deletion src/routes/taxi/availability/api/availability/+server.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { db, type Database } from '$lib/server/db';
import { Interval } from '$lib/util/interval';
import { json } from '@sveltejs/kit';
import { error, json } from '@sveltejs/kit';
import { type Insertable, type Selectable } from 'kysely';
import { getAlterableTimeframe } from '$lib/util/getAlterableTimeframe';
import { addAvailability } from '$lib/server/addAvailability';
import { retry } from '$lib/server/db/retryQuery';
import { getAvailability } from '$lib/server/getAvailability.js';
import { readInt } from '$lib/server/util/readForm';

type Availability = Selectable<Database['availability']>;
type NewAvailability = Insertable<Database['availability']>;
Expand Down Expand Up @@ -127,3 +129,30 @@ export const POST = async ({ locals, request }) => {
await addAvailability(interval, companyId, vehicleId);
return json({});
};

export const GET = async ({ locals, url }) => {
const companyId = locals.session?.companyId;
if (!companyId) {
throw 'no company';
}
const timezoneOffset = readInt(url.searchParams.get('offset'));
if (isNaN(timezoneOffset)) {
error(400, { message: 'Invalid offset parameter' });
}
const localDateParam = url.searchParams.get('date');
if (!localDateParam) {
error(400, { message: 'Invalid date parameter' });
}
const time = new Date(localDateParam).getTime();
if (isNaN(time)) {
error(400, { message: 'Invalid date parameter' });
}
const utcDate = new Date(time + timezoneOffset * 60 * 1000);
const {
companyDataComplete: _a,
companyCoordinates: _b,
utcDate: _c,
...res
} = await getAvailability(utcDate, companyId);
return json(res);
};
Loading