Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unternehmer kann Rollen verteilen #122

Merged
merged 49 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
8c4427f
wip
steffenheger Jul 29, 2024
e3ec604
wip
steffenheger Aug 13, 2024
50925bf
add field is_driver to auth_user
steffenheger Aug 23, 2024
220c917
wip
steffenheger Aug 27, 2024
127ed9a
merge prima master
steffenheger Sep 6, 2024
3b6d07c
Merge branch 'master' into entrepreneur_assigns_roles
steffenheger Sep 6, 2024
c5723bc
lint
steffenheger Sep 6, 2024
86fa899
E2E test: addvehicle, set availability, request ride
steffenheger Sep 6, 2024
4bc6c64
wip
steffenheger Sep 6, 2024
c35df1c
wip
steffenheger Sep 6, 2024
1631559
test: move tour
steffenheger Sep 7, 2024
8aa5c66
format
steffenheger Sep 7, 2024
57f597c
wip
steffenheger Sep 9, 2024
95ae62d
update test utils
steffenheger Sep 9, 2024
beaea16
wip
steffenheger Sep 11, 2024
08dbd38
drop is_driver from auth_user
steffenheger Sep 11, 2024
2ac69f8
format+lint
steffenheger Sep 11, 2024
08610da
wip
steffenheger Sep 11, 2024
be44272
update E2E tests, timeouts, dependencies
steffenheger Sep 11, 2024
00d51f5
format
steffenheger Sep 11, 2024
4422ccd
wip
steffenheger Sep 11, 2024
ff5d582
remove contradicting migrations
steffenheger Sep 11, 2024
f971ecf
wip
steffenheger Sep 13, 2024
2c8a2aa
update tests
steffenheger Sep 13, 2024
9f42670
wip
steffenheger Sep 13, 2024
3844c02
wip
steffenheger Sep 13, 2024
246f16f
wip
steffenheger Sep 15, 2024
7e0843d
wip
steffenheger Sep 16, 2024
d00a0f8
Merge branch 'entrepreneur_assigns_roles' of github.com:motis-project…
steffenheger Sep 16, 2024
6d62b6a
wip
steffenheger Sep 16, 2024
4c84b66
wip
steffenheger Sep 17, 2024
c38345e
wip
steffenheger Sep 17, 2024
4d938e2
wip
steffenheger Sep 17, 2024
3a4989a
add timezone emulation
steffenheger Sep 17, 2024
387b1d5
format
steffenheger Sep 17, 2024
26df10a
Self hosted runner (#153)
felixguendling Sep 17, 2024
933e35b
wip
felixguendling Sep 17, 2024
0bab078
restrict /(user) to company owners
felixguendling Sep 17, 2024
d449e49
fix table vs form
felixguendling Sep 17, 2024
4bc60c2
wip
steffenheger Sep 17, 2024
1d6af04
wip
steffenheger Sep 17, 2024
5a7e1d3
wip
steffenheger Sep 17, 2024
b0bad3e
wip
steffenheger Sep 17, 2024
e9b5a4d
wip
steffenheger Sep 18, 2024
4df1f3c
test
steffenheger Sep 18, 2024
68583cf
test
steffenheger Sep 18, 2024
092380a
test
steffenheger Sep 18, 2024
a74f24d
test
steffenheger Sep 18, 2024
b883ac0
test
steffenheger Sep 18, 2024
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
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ node_modules
pnpm-lock.yaml
package-lock.json
yarn.lock

taxidriver-android-app
13 changes: 6 additions & 7 deletions .github/workflows/ui.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
name: UI

defaults:
run:
shell: bash -ieo pipefail {0}

on:
push:
branches: [ "master" ]
Expand All @@ -8,19 +12,14 @@ on:

jobs:
build:
runs-on: ubuntu-latest
runs-on: ['self-hosted', 'prima', 'Linux', 'X64']
permissions: write-all
env:
DATABASE_URL: postgresql://postgres:pw@localhost:6500/prima
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup NodeJS
uses: actions/setup-node@v4
with:
node-version: 20

- name: Install Dependencies
run: npm install -f

Expand All @@ -34,7 +33,7 @@ jobs:
run: npm run test:unit

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

- name: Integration Tests
run: |
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ node_modules
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
booking-generator/data/stops.txt
booking-generator/test/
booking-generator/test
.vscode
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ yarn.lock
src/lib/components/*
.github/*
migrations/*

taxidriver-android-app
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ services:
image: prima
restart: always
ports:
- 8080:3000
- 7777:3000
environment:
- DATABASE_URL=postgresql://postgres:pw@pg/prima
- ORIGIN=http://localhost:8080
- ORIGIN=http://localhost:7777
build:
context: .

Expand Down
31 changes: 20 additions & 11 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,50 @@ export default defineConfig({
// webServer: {
// command: 'npm run dev',
// url: 'http://localhost:5173',
// timeout: 10000,
// timeout: 20000,
// reuseExistingServer: true
// },
// use: {
// baseURL: 'http://localhost:5173/'
// baseURL: 'http://localhost:5173/',
// locale: 'de-DE',
// timezoneId: 'Europe/Berlin',
// },
webServer: {
command: 'docker compose up prima',
url: 'http://127.0.0.1:8080',
timeout: 10000,
url: 'http://127.0.0.1:7777',
timeout: 20000,
reuseExistingServer: true
},
use: {
baseURL: 'http://localhost:8080/'
baseURL: 'http://localhost:7777/',
locale: 'de-DE',
timezoneId: 'Europe/Berlin'
},
testDir: './tests',
projects: [
{
name: 'setup db',
testMatch: /db\.setup\.ts/
testMatch: 'db.setup.ts'
},
{
name: 'login',
testMatch: /login\.setup\.ts/,
testMatch: 'login.setup.ts',
dependencies: ['setup db']
},
{
name: 'company data',
testMatch: /companyData\.test\.ts/,
name: 'entrepreneurAssignsRoles',
testMatch: 'entrepreneurAssignsRoles.ts',
dependencies: ['login']
},
{
name: 'availability',
testMatch: /setAvailability\.test\.ts/,
dependencies: ['company data']
testMatch: 'availability.ts',
dependencies: ['login']
},
{
name: 'move tour',
testMatch: 'moveTour.ts',
dependencies: ['availability']
}
]
});
7 changes: 6 additions & 1 deletion src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { migrateToLatest } from '$lib/migrate';
import { lucia } from '$lib/auth';
import { db } from '$lib/database';
import type { Handle } from '@sveltejs/kit';
import { redirect, type Handle } from '@sveltejs/kit';

migrateToLatest(db);

Expand Down Expand Up @@ -31,5 +31,10 @@ export const handle: Handle = async ({ event, resolve }) => {

event.locals.user = user;
event.locals.session = session;

if (event.route.id?.startsWith('/(user)') && (!user || !user.is_entrepreneur || !user.company)) {
return redirect(302, '/login');
}

return resolve(event);
};
2 changes: 1 addition & 1 deletion src/lib/ConfirmationDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
</AlertDialog.Header>
<AlertDialog.Footer>
<AlertDialog.Cancel>Abbrechen</AlertDialog.Cancel>
<AlertDialog.Action on:click={handleConfirm}>Ok</AlertDialog.Action>
<AlertDialog.Action on:click={handleConfirm}>Bestätigen</AlertDialog.Action>
</AlertDialog.Footer>
</AlertDialog.Content>
</AlertDialog.Root>
Expand Down
10 changes: 9 additions & 1 deletion src/routes/(user)/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,19 @@
{
name: 'Abgeschlossene Fahrten',
href: '/tours'
},
{
name: 'Fahrer',
href: '/drivers'
},
{
name: 'Verwaltung',
href: '/administration'
}
];
</script>

<div class="flex min-h-screen">
<div class="flex max-h-screen">
<div class="container min-w-[1440px] relative my-20">
<section>
<Nav {routeLinks} />
Expand Down
58 changes: 58 additions & 0 deletions src/routes/(user)/administration/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { Actions } from './$types';
import { db } from '$lib/database';
import { fail } from '@sveltejs/kit';
import type { PageServerLoad, RequestEvent } from './$types.js';

export const load: PageServerLoad = async (event) => {
const administrators = await db
.selectFrom('auth_user')
.where('company_id', '=', event.locals.user!.company!)
.where('is_entrepreneur', '=', true)
.selectAll()
.execute();
return {
administrators,
userEmail: event.locals.user!.email
};
};

export const actions = {
assign: async (event: RequestEvent) => {
const email = (await event.request.formData()).get('email')!.toString();
const companyId = event.locals.user!.company!;
if (!email) {
return fail(400, { email, missing: true });
}
const { numUpdatedRows } = await db
.updateTable('auth_user')
.set({
company_id: companyId,
is_entrepreneur: true
})
.where('email', '=', email)
.where('is_entrepreneur', '=', false)
.where('is_maintainer', '=', false)
.where((eb) => eb.or([eb('company_id', 'is', null), eb('company_id', '=', companyId)]))
.executeTakeFirstOrThrow();
if (numUpdatedRows == BigInt(0)) {
return fail(400, { email, incorrect: true });
}
return { updated: true };
},
revoke: async (event: RequestEvent) => {
const email = (await event.request.formData()).get('email')!.toString();
if (event.locals.user!.email == email) {
return fail(400);
}
const companyId = event.locals.user!.company!;
await db
.updateTable('auth_user')
.set({
is_entrepreneur: false,
company_id: null
})
.where('company_id', '=', companyId)
.where('email', '=', email)
.executeTakeFirst();
}
} satisfies Actions;
72 changes: 72 additions & 0 deletions src/routes/(user)/administration/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button';
import * as Card from '$lib/components/ui/card';
import { Input } from '$lib/components/ui/input';
import type { ActionData, PageData } from './$types';
import * as Table from '$lib/components/ui/table/index.js';

const { data, form } = $props<{ data: PageData; form: ActionData }>();
</script>

<div class="w-full h-full">
<Card.Header>
<Card.Title>Unternehmer Zugang</Card.Title>
</Card.Header>
<Card.Content class="w-full h-full">
<form class="mb-6" method="POST" action="?/assign">
<div class=" flex w-full max-w-sm items-center space-x-2">
<Input name="email" type="email" placeholder="Email" />
<Button type="submit">Freischalten</Button>
</div>
<div
class="mt-1 ml-1 text-[0.8rem] font-medium"
class:text-green-600={form?.updated}
class:text-destructive={form?.incorrect}
class:text-yellow-600={form?.existed}
>
{#if form?.missing}
Das Email Feld muss ausgefüllt werden.
{/if}
{#if form?.incorrect}
Nutzer kann nicht freigeschaltet werden.
{/if}
{#if form?.updated}
Freischaltung erfolgreich!
{/if}
</div>
</form>
<div class="rounded-md border mb-6">
<Table.Root>
<Table.Header>
<Table.Row>
<Table.Head>E-Mail</Table.Head>
<Table.Head></Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{#each data.administrators as admin}
<Table.Row>
<Table.Cell>{admin.email}</Table.Cell>
<Table.Cell class="h-16">
<form method="POST" action="?/revoke" style="display: block !important;">
<Input
class="hidden"
hidden={true}
name="email"
type="text"
value={admin.email}
/>
{#if data.userEmail != admin.email}
<Button type="submit" variant="destructive">
Zugang zum Unternehmen löschen
</Button>
{/if}
</form>
</Table.Cell>
</Table.Row>
{/each}
</Table.Body>
</Table.Root>
</div>
</Card.Content>
</div>
52 changes: 52 additions & 0 deletions src/routes/(user)/drivers/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { Actions } from './$types';
import { db } from '$lib/database';
import { fail } from '@sveltejs/kit';
import type { PageServerLoad, RequestEvent } from './$types.js';

export const load: PageServerLoad = async (event) => {
const drivers = await db
.selectFrom('auth_user')
.where('company_id', '=', event.locals.user!.company!)
.where('is_entrepreneur', '=', false)
.selectAll()
.execute();
return {
drivers,
userEmail: event.locals.user!.email
};
};

export const actions = {
assign: async (event: RequestEvent) => {
const email = (await event.request.formData()).get('email')!.toString();
const companyId = event.locals.user!.company!;
if (!email) {
return fail(400, { email, missing: true });
}
const { numUpdatedRows } = await db
.updateTable('auth_user')
.set({ company_id: companyId })
.where('email', '=', email)
.where('company_id', 'is', null)
.where('is_entrepreneur', '=', false)
.where('is_maintainer', '=', false)
.executeTakeFirstOrThrow();
if (numUpdatedRows == BigInt(0)) {
return fail(400, { email, incorrect: true });
}
return { updated: true };
},
revoke: async (event: RequestEvent) => {
const email = (await event.request.formData()).get('email')!.toString();
const companyId = event.locals.user!.company!;
await db
.updateTable('auth_user')
.set({
is_entrepreneur: false,
company_id: null
})
.where('company_id', '=', companyId)
.where('email', '=', email)
.executeTakeFirst();
}
} satisfies Actions;
Loading