mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-08 22:42:54 +00:00
feat: backend-supplied id cards on profile page
feat: SCIdCard thing
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -38,6 +38,7 @@ export enum SCThingType {
|
||||
Dish = 'dish',
|
||||
Favorite = 'favorite',
|
||||
Floor = 'floor',
|
||||
IdCard = 'id card',
|
||||
Message = 'message',
|
||||
Organization = 'organization',
|
||||
Person = 'person',
|
||||
|
||||
93
packages/core/src/things/id-card.ts
Normal file
93
packages/core/src/things/id-card.ts
Normal 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,
|
||||
},
|
||||
};
|
||||
}
|
||||
41
packages/core/test/range.spec.ts
Normal file
41
packages/core/test/range.spec.ts
Normal 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user