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

Integrate the fines list page with the API #19

Merged
merged 9 commits into from
Jul 24, 2023
1 change: 1 addition & 0 deletions src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ declare global {
// interface Error {}
interface Locals {
sql: Sql;
accessToken: string;
}
// interface PageData {}
// interface Platform {}
Expand Down
8 changes: 7 additions & 1 deletion src/lib/api/document.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
export enum DocType {
PASSPORT = 'Passport',
PASSPORT = '01',
STS = '24',
}

export const docName: Record<DocType, string> = {
[DocType.PASSPORT]: 'Passport',
[DocType.STS]: 'STS',
};

export type Doc = {
type: string;
value: string;
Expand Down
41 changes: 16 additions & 25 deletions src/lib/api/fines.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
export type TFines = {
requestUID: string;
/** if resultCode is 9996 you have to re-request after some time. if you get resultCode=0, then it is ready. */
resultCode: string;
resultDescription: string;
chargeResponseList: TFine[];
};

export type TFine = {
/** ISO timestamp (with timezone) */
validUntil: string;
/** Title */
billFor: string;
totalAmount: string;
changeStatus: {
meaning: string;
};
additionalData: Array<{ name: string; value: string }>;
supplierBillID: string;
/** ISO timestamp (with timezone) */
billDate: string;
amountToPay: number;
};

export const sampleFines: TFines = {
chargeResponseList: [
{
billFor: 'Aliqua enim cillum qui culpa cupidatat amet do est amet cupidatat.',
billDate: new Date().toISOString(),
amountToPay: 100,
},
{
billFor: 'Aliqua enim cillum qui culpa cupidatat amet do est amet cupidatat.',
billDate: new Date().toISOString(),
amountToPay: 100,
},
{
billFor: 'Aliqua enim cillum qui culpa cupidatat amet do est amet cupidatat.',
billDate: new Date().toISOString(),
amountToPay: 100,
},
{
billFor: 'Aliqua enim cillum qui culpa cupidatat amet do est amet cupidatat.',
billDate: new Date().toISOString(),
amountToPay: 100,
},
],
chargeType: 'FINES';
revoked: boolean;
};
13 changes: 13 additions & 0 deletions src/routes/(tokenAuth)/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { redirect } from '@sveltejs/kit';
import type { LayoutServerLoad } from './$types';

export const load: LayoutServerLoad = async ({ cookies, url, locals }) => {
const accessToken = url.searchParams.get('accessToken') ?? cookies.get('accessToken');
if (accessToken == undefined) {
// No access token found. Go to the MTS login page, and redirect to the same page again
// SvelteKit seems to default it to HTTP during dev
const redirectUrl = url.href.replace('http:', 'https:');
throw redirect(307, `/login?redirectUrl=${redirectUrl}`);
}
locals.accessToken = accessToken;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@ import type { LayoutServerLoad } from './$types';
import { sampleCharities, type TCharity } from '$lib/api/charity';
import { API_BASE } from '$lib/api/mts';

export const load: LayoutServerLoad = async ({ fetch, cookies, url }) => {
const accessToken = url.searchParams.get('accessToken') ?? cookies.get('accessToken');
if (accessToken == undefined) {
// No access token found. Go to the MTS login page, and redirect to the same page again
// SvelteKit seems to default it to HTTP during dev
const redirectUrl = url.href.replace('http:', 'https:');
throw redirect(307, `/login?redirectUrl=${redirectUrl}`);
}
export const load: LayoutServerLoad = async ({ fetch, cookies, url, locals }) => {
const { accessToken } = locals;
const res = await fetch(API_BASE + '/rnip2/charges/charitycatalog', {
headers: {
Authorization: `Bearer ${accessToken}`,
Expand Down
30 changes: 30 additions & 0 deletions src/routes/(tokenAuth)/fines/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { redirect } from '@sveltejs/kit';
import type { LayoutServerLoad } from './$types';
import { API_BASE } from '$lib/api/mts';

export const load: LayoutServerLoad = async ({ fetch, cookies, url, locals }) => {
const { accessToken } = locals;
// Just to check that the token is still valid
const res = await fetch(API_BASE + '/rnip2/charges/request', {
method: 'POST',
body: JSON.stringify({
chargeType: 'FINES',
payerIdList: [],
}),
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
});
if (!res.ok) {
if (res.status === 401) {
// Token expired. Redirect to MTS login to renew
const redirectUrl = url.href.replace('http:', 'https:');
throw redirect(307, `/login?redirectUrl=${redirectUrl}`);
}
// Otherwise (some other error)
console.error(await res.text());
} else {
cookies.set('accessToken', accessToken, { path: '/' });
}
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script lang="ts">
import { getDoc } from '$lib/api/document';
import type { TFines } from '$lib/api/fines';
import type { TFine } from '$lib/api/fines';
import Calendar from '$lib/icons/Calendar.svelte';
import { goto } from '$app/navigation';
import { onMount } from 'svelte';

let fines: TFines = { chargeResponseList: [] };
let fines: TFine[] = [];

onMount(async () => {
const doc = await getDoc(Telegram.WebApp.initData);

Check failure on line 11 in src/routes/(tokenAuth)/fines/+page.svelte

View workflow job for this annotation

GitHub Actions / static_analysis (ubuntu-latest, 16)

'Telegram' is not defined
if (doc == null) {
await goto('/docs', { replaceState: true });
return;
Expand All @@ -16,18 +16,19 @@
const res = await fetch('/api/fines', {
method: 'POST',
body: JSON.stringify({
initData: Telegram.WebApp.initData,

Check failure on line 19 in src/routes/(tokenAuth)/fines/+page.svelte

View workflow job for this annotation

GitHub Actions / static_analysis (ubuntu-latest, 16)

'Telegram' is not defined
}),
headers: {
'content-type': 'application/json',
},
});
const data = await res.json();
if (!res.ok) {
// Data is an error message. Probably something with validating
alert('Error: ' + data.message);
const err = await res.json();
// Data is an error message. Either data not ready or initData not valid
alert('Error: ' + err.message);
return;
}
const data: { fines: TFine[] } = await res.json();
fines = data.fines;
});
</script>
Expand All @@ -41,14 +42,14 @@
<h1 class="fines__title">Fines</h1>
<a class="link" href="/docs">Edit docs</a>
</div>
{#each fines.chargeResponseList.map((fine) => fine) as { amountToPay, billDate, billFor }}
{#each fines.map((fine) => fine) as { amountToPay, billDate, billFor }}
<a class="fine" href="/fines/{billFor}">
<div class="fine__title">{billFor}</div>
<div class="fine__date-line">
<Calendar /><span class="fine__date">{billDate.split('T')[0]}</span>
</div>
<div class="fine__money">
{Intl.NumberFormat('ru', { style: 'currency', currency: 'RUB' }).format(amountToPay)}
{Intl.NumberFormat('ru', { style: 'currency', currency: 'RUB' }).format(amountToPay / 100)}
</div>
</a>
{/each}
Expand Down
46 changes: 42 additions & 4 deletions src/routes/api/fines/+server.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { sampleFines } from '$lib/api/fines';
import type { TFines } from '$lib/api/fines';
import { API_BASE } from '$lib/api/mts';
import { validateTelegramData } from '$lib/server/validateTelegramData';
import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const POST: RequestHandler = async ({ request, locals }) => {
export const POST: RequestHandler = async ({ fetch, request, locals, cookies }) => {
const { initData } = await request.json();

let chatId: number;
try {
const data = validateTelegramData(initData);
chatId = data.user!.id;

Check warning on line 13 in src/routes/api/fines/+server.ts

View workflow job for this annotation

GitHub Actions / static_analysis (ubuntu-latest, 16)

Forbidden non-null assertion
} catch {
throw error(400, {
message: 'Invalid initData received from client',
Expand All @@ -23,9 +24,46 @@
message: 'No documents found. Please add your document information first.',
});
}
// TODO: use the document to request fines from MTS backend
const { doc_type, doc_value } = result[0];

const accessToken = cookies.get('accessToken');
if (accessToken === undefined) {
throw error(401, {
message: 'No access token found in cookies',
});
}

const linkRes = await fetch(API_BASE + '/rnip2/charges/request', {
method: 'POST',
body: JSON.stringify({
chargeType: 'FINES',
payerIdList: [
{
idType: doc_type,
idNumber: doc_value,
},
],
}),
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
});
const requestPath = await linkRes.text();

const finesRes = await fetch(API_BASE + '/rnip2' + requestPath, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const fines: TFines = await finesRes.json();
if (fines.resultCode === '9996') {
throw error(503, {
message: 'The server is still processing your request, please try again later.',
});
}

return json({
fines: sampleFines,
fines: fines.chargeResponseList,
});
};
8 changes: 5 additions & 3 deletions src/routes/docs/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<script lang="ts">
import { DocType, getDoc, updateDoc, type Doc } from '$lib/api/document';
import { DocType, getDoc, updateDoc, docName, type Doc } from '$lib/api/document';
import { onMount } from 'svelte';
let type: string;
let value: string;
let serverDoc: Doc | null = null;

const docValues = Object.values(DocType) as DocType[];

onMount(async () => {
try {
serverDoc = await getDoc(Telegram.WebApp.initData);

Check failure on line 12 in src/routes/docs/+page.svelte

View workflow job for this annotation

GitHub Actions / static_analysis (ubuntu-latest, 16)

'Telegram' is not defined
if (serverDoc) {
({ type, value } = serverDoc);
}
Expand All @@ -17,7 +19,7 @@
});

async function save() {
serverDoc = await updateDoc(Telegram.WebApp.initData, type, value);

Check failure on line 22 in src/routes/docs/+page.svelte

View workflow job for this annotation

GitHub Actions / static_analysis (ubuntu-latest, 16)

'Telegram' is not defined
({ type, value } = serverDoc);

alert('Data saved successfully');
Expand All @@ -39,8 +41,8 @@
<label class="doc-type">
Document type
<select bind:value={type}>
{#each Object.entries(DocType) as [value, docName]}
<option {value}>{docName}</option>
{#each docValues as value}
<option {value}>{docName[value]}</option>
{/each}
</select>
</label>
Expand Down
Loading