feat: backend-supplied id cards on profile page

feat: SCIdCard thing
This commit is contained in:
2023-08-21 12:49:57 +02:00
parent 905ebf8c59
commit 1f62b5c5b0
30 changed files with 635 additions and 162 deletions

View File

@@ -33,6 +33,7 @@ export * from './things/diff.js';
export * from './things/dish.js';
export * from './things/favorite.js';
export * from './things/floor.js';
export * from './things/id-card.js';
export * from './things/message.js';
export * from './things/organization.js';
export * from './things/periodical.js';

View File

@@ -62,6 +62,7 @@ import {SCTicket, SCTicketMeta, SCTicketWithoutReferences} from './things/ticket
import {SCToDo, SCToDoMeta, SCToDoWithoutReferences} from './things/todo.js';
import {SCTour, SCTourMeta, SCTourWithoutReferences} from './things/tour.js';
import {SCVideo, SCVideoMeta, SCVideoWithoutReferences} from './things/video.js';
import {SCIdCard, SCIdCardMeta, SCIdCardWithoutReferences} from './things/id-card.js';
/**
* A map of things, from type to meta data
@@ -80,6 +81,7 @@ export const SCClasses: {[K in SCThingType]: object} = {
'dish': SCDishMeta,
'favorite': SCFavoriteMeta,
'floor': SCFloorMeta,
'id card': SCIdCardMeta,
'message': SCMessageMeta,
'organization': SCOrganizationMeta,
'periodical': SCPeriodicalMeta,
@@ -111,6 +113,7 @@ export type SCIndexableThings =
| SCDateSeries
| SCDish
| SCFloor
| SCIdCard
| SCMessage
| SCOrganization
| SCPeriodical
@@ -167,6 +170,8 @@ export type SCAssociatedThingWithoutReferences<THING extends SCThings> = THING e
? SCFavoriteWithoutReferences
: THING extends SCFloor
? SCFloorWithoutReferences
: THING extends SCIdCard
? SCIdCardWithoutReferences
: THING extends SCMessage
? SCMessageWithoutReferences
: THING extends SCOrganization
@@ -230,6 +235,8 @@ export type SCAssociatedThing<THING extends SCThings> = THING extends SCAssessme
? SCFavorite
: THING extends SCFloorWithoutReferences
? SCFloor
: THING extends SCIdCardWithoutReferences
? SCIdCard
: THING extends SCMessageWithoutReferences
? SCMessage
: THING extends SCOrganizationWithoutReferences

View File

@@ -21,6 +21,30 @@ import {SCISO8601Date} from '../../general/time.js';
*/
export type SCISO8601DateRange = SCRange<SCISO8601Date>;
/**
* Checks if a value is inside a range
* @param value the value to check
* @param range the range
*/
export function isInRange<T>(value: T, range: SCRange<T>): boolean {
return (
(range.lt == undefined ? (range.lte == undefined ? true : range.lte >= value) : range.lt > value) &&
(range.gt == undefined ? (range.gte == undefined ? true : range.gte <= value) : range.gt < value)
);
}
/**
* Format a range
* @example '0..4'
* @example '1=..=3'
* @example '0..=3'
*/
export function formatRange<T>(range: SCRange<T>): string {
return `${range.gt ?? range.gte}${range.gte == undefined ? '' : '='}..${range.lte == undefined ? '' : '='}${
range.lt ?? range.lte
}`;
}
/**
* Generic range type
*/

View File

@@ -38,6 +38,7 @@ export enum SCThingType {
Dish = 'dish',
Favorite = 'favorite',
Floor = 'floor',
IdCard = 'id card',
Message = 'message',
Organization = 'organization',
Person = 'person',

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2019-2022 Open StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SCMetaTranslations, SCTranslations} from '../general/i18n.js';
import {
SCThing,
SCThingMeta,
SCThingTranslatableProperties,
SCThingType,
SCThingWithoutReferences,
} from './abstract/thing.js';
import {SCISO8601DateRange} from './abstract/range.js';
/**
* An ID-Card without references
*/
export interface SCIdCardWithoutReferences extends SCThingWithoutReferences {
/**
* Validity range
*/
validity?: SCISO8601DateRange;
/**
* Type
*/
type: SCThingType.IdCard;
}
/**
* A message
* @validatable
* @indexable
*/
export interface SCIdCard extends SCIdCardWithoutReferences, SCThing {
/**
* Translated fields of a message
*/
translations?: SCTranslations<SCIdCardTranslatableProperties>;
/**
* Type
*/
type: SCThingType.IdCard;
}
/**
* Translatable properties of a message
*/
export interface SCIdCardTranslatableProperties extends SCThingTranslatableProperties {}
/**
* Meta information about messages
*/
export class SCIdCardMeta extends SCThingMeta implements SCMetaTranslations<SCIdCard> {
/**
* Translations of fields
*/
fieldTranslations = {
de: {
...new SCThingMeta().fieldTranslations.de,
validity: 'Gültigkeit',
},
en: {
...new SCThingMeta().fieldTranslations.en,
validity: 'validity',
},
};
/**
* Translations of values of fields
*/
fieldValueTranslations = {
de: {
...new SCThingMeta().fieldValueTranslations.de,
type: 'Ausweis',
},
en: {
...new SCThingMeta().fieldValueTranslations.en,
type: SCThingType.Message,
},
};
}

View File

@@ -0,0 +1,41 @@
import {expect} from 'chai';
import {formatRange, isInRange} from '../src/index.js';
import {SCRange} from '../lib/index.js';
const cases: Record<'accept' | 'reject', [number, SCRange<number>][]> = {
accept: [
[4, {gt: 3, lt: 5}],
[4, {gte: 4, lte: 4}],
[3, {gt: 2, lt: 4}],
[5, {gte: 3, lte: 5}],
[10, {gt: 5, lt: 15}],
[0, {gte: 0, lte: 10}],
],
reject: [
[4, {gt: 3, lt: 4}],
[4, {gte: 5, lte: 6}],
[2, {gt: 5, lt: 10}],
[6, {gte: 7, lte: 8}],
[-1, {gt: 0, lt: 5}],
[20, {gte: 10, lte: 15}],
],
};
describe('Range', () => {
for (const constructor of ['Number', 'Date'] as const) {
describe(`${constructor} range`, () => {
for (const [accept, [value, range]] of Object.entries(cases).flatMap(([accept, cases]) =>
cases.map(it => [accept, it] as const),
)) {
it(`should ${accept} ${value} in the range ${formatRange(range)}`, () => {
const result = isInRange(constructor === 'Number' ? value : new Date(value), range);
if (accept === 'accept') {
expect(result).to.be.true;
} else {
expect(result).to.be.false;
}
});
}
});
}
});