mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2025-12-27 08:36:14 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8da621558 | ||
|
|
6f12fbda94 | ||
|
|
cf83692e71 | ||
|
|
27417e80e1 | ||
|
|
bab675b806 | ||
|
|
d3790adbd8 | ||
|
|
d8aa023b28 | ||
|
|
4217e237fb | ||
|
|
c7e2584472 | ||
|
|
e30e04384f | ||
|
|
6fb9ccb821 | ||
|
|
9fb0a7c885 | ||
|
|
b5e0b76c24 | ||
|
|
a2f44762f9 | ||
|
|
d46abbe29b | ||
|
|
4986042428 | ||
|
|
3242411768 | ||
|
|
37e5f6c490 | ||
|
|
623ed613a9 | ||
|
|
fd994e2c08 | ||
|
|
8dc40dbb00 | ||
|
|
c4e30c5fdd | ||
|
|
81887315f8 | ||
|
|
55687daca9 | ||
|
|
2bf65a9086 | ||
|
|
d9347ece05 | ||
|
|
acdca2f554 | ||
|
|
67868e9eb8 | ||
|
|
bc00f62117 | ||
|
|
75e833d841 | ||
|
|
a97805172c | ||
|
|
c8bda2eae7 | ||
|
|
1e9f36c4be | ||
|
|
6da9d73477 | ||
|
|
bbe4fcac42 | ||
|
|
5d1e79d487 | ||
|
|
7532a9bb62 | ||
|
|
a4db76ec36 |
@@ -1,4 +1,3 @@
|
||||
# EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
@@ -7,11 +6,10 @@ root = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# We recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
29
.gitignore
vendored
29
.gitignore
vendored
@@ -20,7 +20,7 @@ coverage
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
@@ -29,14 +29,14 @@ bower_components
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
@@ -57,6 +57,29 @@ typings/
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
#DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
########## end of https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||
|
||||
# ignore ide files
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
@@ -28,6 +28,16 @@ audit:
|
||||
stage: test
|
||||
script:
|
||||
- npm audit
|
||||
allow_failure: true
|
||||
except:
|
||||
- schedules
|
||||
|
||||
scheduled-audit:
|
||||
stage: test
|
||||
script:
|
||||
- npm audit
|
||||
only:
|
||||
- schedules
|
||||
|
||||
test:
|
||||
dependencies:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Ignore all files/folders by default
|
||||
# See https://stackoverflow.com/a/29932318
|
||||
/*
|
||||
|
||||
# Execept this files/folders
|
||||
!docs
|
||||
# Except these files/folders
|
||||
!lib
|
||||
lib/tsconfig.tsbuildinfo
|
||||
!LICENSE
|
||||
!package.json
|
||||
!package-lock.json
|
||||
!README.md
|
||||
!src
|
||||
!test/resources/
|
||||
|
||||
62
CHANGELOG.md
62
CHANGELOG.md
@@ -1,3 +1,65 @@
|
||||
# [0.17.0](https://gitlab.com/openstapps/core/compare/v0.16.0...v0.17.0) (2019-04-16)
|
||||
|
||||
|
||||
|
||||
# [0.16.0](https://gitlab.com/openstapps/core/compare/v0.15.0...v0.16.0) (2019-04-15)
|
||||
|
||||
|
||||
|
||||
# [0.15.0](https://gitlab.com/openstapps/core/compare/v0.14.0...v0.15.0) (2019-04-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* change SCThingMeta getInstance() return value ([4986042](https://gitlab.com/openstapps/core/commit/4986042))
|
||||
* resolve issues with things that can be offered ([623ed61](https://gitlab.com/openstapps/core/commit/623ed61)), closes [#41](https://gitlab.com/openstapps/core/issues/41)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* provide context based search ([3242411](https://gitlab.com/openstapps/core/commit/3242411))
|
||||
|
||||
|
||||
|
||||
# [0.14.0](https://gitlab.com/openstapps/core/compare/v0.13.0...v0.14.0) (2019-04-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add model for plugin register route ([8188731](https://gitlab.com/openstapps/core/commit/8188731))
|
||||
|
||||
|
||||
|
||||
# [0.13.0](https://gitlab.com/openstapps/core/compare/v0.12.0...v0.13.0) (2019-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* correct isThing guard ([67868e9](https://gitlab.com/openstapps/core/commit/67868e9))
|
||||
* update tslint dependencies ([bbe4fca](https://gitlab.com/openstapps/core/commit/bbe4fca))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add conditional "maps" for associated types ([c8bda2e](https://gitlab.com/openstapps/core/commit/c8bda2e)), closes [#50](https://gitlab.com/openstapps/core/issues/50)
|
||||
* provide sample JSON files with the package ([5d1e79d](https://gitlab.com/openstapps/core/commit/5d1e79d)), closes [#46](https://gitlab.com/openstapps/core/issues/46)
|
||||
|
||||
|
||||
|
||||
# [0.12.0](https://gitlab.com/openstapps/core/compare/v0.11.0...v0.12.0) (2019-03-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add todo to SCThingsWithoutDiff and SCClasses ([9a49442](https://gitlab.com/openstapps/core/commit/9a49442)), closes [#39](https://gitlab.com/openstapps/core/issues/39)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add SCThingTranslator class. move functionality accordingly ([90e3d22](https://gitlab.com/openstapps/core/commit/90e3d22))
|
||||
|
||||
|
||||
|
||||
# [0.11.0](https://gitlab.com/openstapps/core/compare/v0.10.0...v0.11.0) (2019-02-21)
|
||||
|
||||
|
||||
|
||||
3221
package-lock.json
generated
3221
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
43
package.json
43
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openstapps/core",
|
||||
"version": "0.12.0",
|
||||
"version": "0.18.0",
|
||||
"description": "StAppsCore - Generalized model of data",
|
||||
"keywords": [
|
||||
"Model",
|
||||
@@ -14,10 +14,10 @@
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "npm run tslint && npm run compile && npm run pack && npm run schema && npm run documentation",
|
||||
"build": "npm run tslint && npm run compile && npm run pack && npm run schema",
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md && git commit -m 'docs: update changelog'",
|
||||
"check-configuration": "openstapps-configuration",
|
||||
"compile": "tsc",
|
||||
"compile": "rimraf lib && tsc",
|
||||
"documentation": "typedoc --name \"@openstapps/core\" --includeDeclarations --mode modules --out docs --readme README.md --listInvalidSymbolLinks lib",
|
||||
"pack": "openstapps-core-tools pack",
|
||||
"prepublishOnly": "npm ci && npm run build",
|
||||
@@ -25,43 +25,44 @@
|
||||
"test": "nyc mocha --require ts-node/register --ui mocha-typescript test/*.spec.ts",
|
||||
"tslint": "tslint 'src/**/*.ts'"
|
||||
},
|
||||
"author": "Karl-Philipp Wulfert <krlwlfrt@gmail.com",
|
||||
"author": "Karl-Philipp Wulfert <krlwlfrt@gmail.com>",
|
||||
"contributors": [
|
||||
"Anselm Stordeur <anselmstordeur@gmail.com>",
|
||||
"Jovan Krunic <jovan.krunic@gmail.com>",
|
||||
"Jovan Krunić <jovan.krunic@gmail.com>",
|
||||
"Andreas Lehmann",
|
||||
"Sebastian Lange",
|
||||
"Rainer Killinger",
|
||||
"Imran Hossain"
|
||||
"Imran Hossain",
|
||||
"Michel Jonathan Schmitz",
|
||||
"Wieland Schöbl"
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/geojson": "1.0.6",
|
||||
"@types/json-patch": "0.0.30",
|
||||
"fast-clone": "1.5.13",
|
||||
"json-patch": "0.7.0",
|
||||
"jsonschema": "1.2.4",
|
||||
"ts-optchain": "0.1.2"
|
||||
"ts-optchain": "0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openstapps/configuration": "0.7.0",
|
||||
"@openstapps/core-tools": "0.2.1",
|
||||
"@openstapps/logger": "0.0.3",
|
||||
"@krlwlfrt/async-pool": "0.1.0",
|
||||
"@openstapps/configuration": "0.12.0",
|
||||
"@openstapps/core-tools": "0.6.0",
|
||||
"@openstapps/logger": "0.0.5",
|
||||
"@types/chai": "4.1.7",
|
||||
"@types/humanize-string": "1.0.0",
|
||||
"@types/node": "11.9.4",
|
||||
"@types/node": "10.14.4",
|
||||
"@types/rimraf": "2.0.2",
|
||||
"async-pool-native": "0.1.0",
|
||||
"chai": "4.2.0",
|
||||
"commander": "2.19.0",
|
||||
"conventional-changelog-cli": "2.0.11",
|
||||
"humanize-string": "1.0.2",
|
||||
"mocha": "5.2.0",
|
||||
"commander": "2.20.0",
|
||||
"conventional-changelog-cli": "2.0.12",
|
||||
"mocha": "6.1.4",
|
||||
"mocha-typescript": "1.1.17",
|
||||
"nyc": "13.3.0",
|
||||
"nyc": "14.0.0",
|
||||
"rimraf": "2.6.3",
|
||||
"ts-node": "8.0.2",
|
||||
"tslint": "5.12.1",
|
||||
"ts-node": "8.1.0",
|
||||
"tslint": "5.15.0",
|
||||
"typedoc": "0.14.2",
|
||||
"typescript": "3.3.3"
|
||||
"typescript": "3.4.3"
|
||||
},
|
||||
"nyc": {
|
||||
"check-coverage": true,
|
||||
|
||||
@@ -13,29 +13,30 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {SCThingType} from './Thing';
|
||||
import {SCAcademicEvent, SCAcademicEventMeta} from './things/AcademicEvent';
|
||||
import {SCArticle, SCArticleMeta} from './things/Article';
|
||||
import {SCBook, SCBookMeta} from './things/Book';
|
||||
import {SCBuilding, SCBuildingMeta} from './things/Building';
|
||||
import {SCCatalog, SCCatalogMeta} from './things/Catalog';
|
||||
import {SCCourseOfStudies, SCCourseOfStudiesMeta} from './things/CourseOfStudies';
|
||||
import {SCDateSeries, SCDateSeriesMeta} from './things/DateSeries';
|
||||
import {SCDiff, SCDiffMeta} from './things/Diff';
|
||||
import {SCDish, SCDishMeta} from './things/Dish';
|
||||
import {SCFavorite, SCFavoriteMeta} from './things/Favorite';
|
||||
import {SCFloor, SCFloorMeta} from './things/Floor';
|
||||
import {SCMessage, SCMessageMeta} from './things/Message';
|
||||
import {SCOrganization, SCOrganizationMeta} from './things/Organization';
|
||||
import {SCPerson, SCPersonMeta} from './things/Person';
|
||||
import {SCPointOfInterest, SCPointOfInterestMeta} from './things/PointOfInterest';
|
||||
import {SCRoom, SCRoomMeta} from './things/Room';
|
||||
import {SCSemester, SCSemesterMeta} from './things/Semester';
|
||||
import {SCSetting, SCSettingMeta} from './things/Setting';
|
||||
import {SCSportCourse, SCSportCourseMeta} from './things/SportCourse';
|
||||
import {SCTicket, SCTicketMeta} from './things/Ticket';
|
||||
import {SCToDo, SCToDoMeta} from './things/ToDo';
|
||||
import {SCTour, SCTourMeta} from './things/Tour';
|
||||
import {SCVideo, SCVideoMeta} from './things/Video';
|
||||
import {SCAcademicEvent, SCAcademicEventMeta, SCAcademicEventWithoutReferences} from './things/AcademicEvent';
|
||||
import {SCArticle, SCArticleMeta, SCArticleWithoutReferences} from './things/Article';
|
||||
import {SCBook, SCBookMeta, SCBookWithoutReferences} from './things/Book';
|
||||
import {SCBuilding, SCBuildingMeta, SCBuildingWithoutReferences} from './things/Building';
|
||||
import {SCCatalog, SCCatalogMeta, SCCatalogWithoutReferences} from './things/Catalog';
|
||||
import {SCCourseOfStudies, SCCourseOfStudiesMeta, SCCourseOfStudiesWithoutReferences} from './things/CourseOfStudies';
|
||||
import {SCDateSeries, SCDateSeriesMeta, SCDateSeriesWithoutReferences} from './things/DateSeries';
|
||||
import {SCDiff, SCDiffMeta, SCDiffWithoutReferences} from './things/Diff';
|
||||
import {SCDish, SCDishMeta, SCDishWithoutReferences} from './things/Dish';
|
||||
import {SCFavorite, SCFavoriteMeta, SCFavoriteWithoutReferences} from './things/Favorite';
|
||||
import {SCFloor, SCFloorMeta, SCFloorWithoutReferences} from './things/Floor';
|
||||
import {SCMessage, SCMessageMeta, SCMessageWithoutReferences} from './things/Message';
|
||||
import {SCOrganization, SCOrganizationMeta, SCOrganizationWithoutReferences} from './things/Organization';
|
||||
import {SCPerson, SCPersonMeta, SCPersonWithoutReferences} from './things/Person';
|
||||
import {SCPointOfInterest, SCPointOfInterestMeta, SCPointOfInterestWithoutReferences} from './things/PointOfInterest';
|
||||
import {SCRoom, SCRoomMeta, SCRoomWithoutReferences} from './things/Room';
|
||||
import {SCSemester, SCSemesterMeta, SCSemesterWithoutReferences} from './things/Semester';
|
||||
import {SCSetting, SCSettingMeta, SCSettingWithoutReferences} from './things/Setting';
|
||||
import {SCSportCourse, SCSportCourseMeta, SCSportCourseWithoutReferences} from './things/SportCourse';
|
||||
import {SCStudyModule, SCStudyModuleMeta, SCStudyModuleWithoutReferences} from './things/StudyModule';
|
||||
import {SCTicket, SCTicketMeta, SCTicketWithoutReferences} from './things/Ticket';
|
||||
import {SCToDo, SCToDoMeta, SCToDoWithoutReferences} from './things/ToDo';
|
||||
import {SCTour, SCTourMeta, SCTourWithoutReferences} from './things/Tour';
|
||||
import {SCVideo, SCVideoMeta, SCVideoWithoutReferences} from './things/Video';
|
||||
|
||||
/* tslint:disable:variable-name */
|
||||
/**
|
||||
@@ -62,6 +63,7 @@ export const SCClasses: { [K in SCThingType]: any } = {
|
||||
'semester': SCSemesterMeta,
|
||||
'setting': SCSettingMeta,
|
||||
'sport course': SCSportCourseMeta,
|
||||
'study module': SCStudyModuleMeta,
|
||||
'ticket': SCTicketMeta,
|
||||
'todo': SCToDoMeta,
|
||||
'tour': SCTourMeta,
|
||||
@@ -87,6 +89,7 @@ export type SCThingsWithoutDiff =
|
||||
| SCSemester
|
||||
| SCSetting
|
||||
| SCSportCourse
|
||||
| SCStudyModule
|
||||
| SCTicket
|
||||
| SCToDo
|
||||
| SCTour
|
||||
@@ -103,3 +106,63 @@ export type SCThings =
|
||||
* A field of a thing
|
||||
*/
|
||||
export type SCThingsField = keyof SCThings | string;
|
||||
|
||||
/**
|
||||
* Thing without references for a thing
|
||||
*/
|
||||
export type SCAssociatedThingWithoutReferences<THING extends SCThings> =
|
||||
THING extends SCAcademicEvent ? SCAcademicEventWithoutReferences :
|
||||
THING extends SCArticle ? SCArticleWithoutReferences :
|
||||
THING extends SCBook ? SCBookWithoutReferences :
|
||||
THING extends SCBuilding ? SCBuildingWithoutReferences :
|
||||
THING extends SCCatalog ? SCCatalogWithoutReferences :
|
||||
THING extends SCCourseOfStudies ? SCCourseOfStudiesWithoutReferences :
|
||||
THING extends SCDateSeries ? SCDateSeriesWithoutReferences :
|
||||
THING extends SCDiff ? SCDiffWithoutReferences :
|
||||
THING extends SCDish ? SCDishWithoutReferences :
|
||||
THING extends SCFavorite ? SCFavoriteWithoutReferences :
|
||||
THING extends SCFloor ? SCFloorWithoutReferences :
|
||||
THING extends SCMessage ? SCMessageWithoutReferences :
|
||||
THING extends SCOrganization ? SCOrganizationWithoutReferences :
|
||||
THING extends SCPerson ? SCPersonWithoutReferences :
|
||||
THING extends SCPointOfInterest ? SCPointOfInterestWithoutReferences :
|
||||
THING extends SCRoom ? SCRoomWithoutReferences :
|
||||
THING extends SCSemester ? SCSemesterWithoutReferences :
|
||||
THING extends SCSetting ? SCSettingWithoutReferences :
|
||||
THING extends SCSportCourse ? SCSportCourseWithoutReferences :
|
||||
THING extends SCStudyModule ? SCStudyModuleWithoutReferences :
|
||||
THING extends SCTicket ? SCTicketWithoutReferences :
|
||||
THING extends SCToDo ? SCToDoWithoutReferences :
|
||||
THING extends SCTour ? SCTourWithoutReferences :
|
||||
THING extends SCVideo ? SCVideoWithoutReferences :
|
||||
never;
|
||||
|
||||
/**
|
||||
* Thing for a thing without references
|
||||
*/
|
||||
export type SCAssociatedThing<THING extends SCThings> =
|
||||
THING extends SCAcademicEventWithoutReferences ? SCAcademicEvent :
|
||||
THING extends SCArticleWithoutReferences ? SCArticle :
|
||||
THING extends SCBookWithoutReferences ? SCBook :
|
||||
THING extends SCBuildingWithoutReferences ? SCBuilding :
|
||||
THING extends SCCatalogWithoutReferences ? SCCatalog :
|
||||
THING extends SCCourseOfStudiesWithoutReferences ? SCCourseOfStudies :
|
||||
THING extends SCDateSeriesWithoutReferences ? SCDateSeries :
|
||||
THING extends SCDiffWithoutReferences ? SCDiff :
|
||||
THING extends SCDishWithoutReferences ? SCDish :
|
||||
THING extends SCFavoriteWithoutReferences ? SCFavorite :
|
||||
THING extends SCFloorWithoutReferences ? SCFloor :
|
||||
THING extends SCMessageWithoutReferences ? SCMessage :
|
||||
THING extends SCOrganizationWithoutReferences ? SCOrganization :
|
||||
THING extends SCPersonWithoutReferences ? SCPerson :
|
||||
THING extends SCPointOfInterestWithoutReferences ? SCPointOfInterest :
|
||||
THING extends SCRoomWithoutReferences ? SCRoom :
|
||||
THING extends SCSemesterWithoutReferences ? SCSemester :
|
||||
THING extends SCSettingWithoutReferences ? SCSetting :
|
||||
THING extends SCSportCourseWithoutReferences ? SCSportCourse :
|
||||
THING extends SCStudyModuleWithoutReferences ? SCStudyModule :
|
||||
THING extends SCTicketWithoutReferences ? SCTicket :
|
||||
THING extends SCToDoWithoutReferences ? SCToDo :
|
||||
THING extends SCTourWithoutReferences ? SCTour :
|
||||
THING extends SCVideoWithoutReferences ? SCVideo :
|
||||
never;
|
||||
|
||||
@@ -41,6 +41,7 @@ export enum SCThingType {
|
||||
Semester = 'semester',
|
||||
Setting = 'setting',
|
||||
SportCourse = 'sport course',
|
||||
StudyModule = 'study module',
|
||||
Ticket = 'ticket',
|
||||
ToDo = 'todo',
|
||||
Tour = 'tour',
|
||||
@@ -222,7 +223,7 @@ export class SCThingMeta implements SCMetaTranslations<SCThing> {
|
||||
/**
|
||||
* Set type definiton for singleton instance
|
||||
*/
|
||||
protected static _instance: SCThingMeta;
|
||||
protected static _instance = new Map<string, unknown>();
|
||||
|
||||
/**
|
||||
* Translations of fields
|
||||
@@ -268,8 +269,10 @@ export class SCThingMeta implements SCMetaTranslations<SCThing> {
|
||||
* Function to retrieve typed singleton instance
|
||||
*/
|
||||
public static getInstance<T extends SCThingMeta>(): T {
|
||||
const typedThis = this as any as typeof SCThingMeta;
|
||||
return (typedThis._instance || (typedThis._instance = new this())) as T;
|
||||
if (!this._instance.has(this.name)) {
|
||||
this._instance.set(this.name, new this());
|
||||
}
|
||||
return this._instance.get(this.name) as T;
|
||||
}
|
||||
|
||||
protected constructor() {}
|
||||
|
||||
@@ -12,30 +12,33 @@
|
||||
* 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 {SCClasses, SCThingsField} from './Classes';
|
||||
import {SCClasses} from './Classes';
|
||||
import {SCThing, SCThingType} from './Thing';
|
||||
|
||||
import {isThing} from './types/Guards';
|
||||
import {SCTranslations} from './types/i18n';
|
||||
|
||||
import clone = require('fast-clone');
|
||||
import {Defined, OCType} from 'ts-optchain';
|
||||
|
||||
/**
|
||||
* SCThingTranslator class
|
||||
*/
|
||||
export class SCThingTranslator {
|
||||
/**
|
||||
* Property representing the translators base language.
|
||||
* This means every translation is given for this language.
|
||||
*/
|
||||
private baseLanguage: keyof SCTranslations<SCThing>;
|
||||
|
||||
/**
|
||||
* Property representing the translators target language
|
||||
*/
|
||||
private language: keyof SCTranslations<SCThing>;
|
||||
private _language: keyof SCTranslations<SCThing>;
|
||||
|
||||
/**
|
||||
* Property provinding a mapping from a SCThingType to its known own meta class.
|
||||
* Property representing the translators base language
|
||||
* This means every translation is given for this language
|
||||
*/
|
||||
private cache: LRUCache<SCThing>;
|
||||
|
||||
/**
|
||||
* Property providing a mapping from a SCThingType to its known own meta class
|
||||
*/
|
||||
private metaClasses: typeof SCClasses;
|
||||
|
||||
@@ -45,42 +48,44 @@ export class SCThingTranslator {
|
||||
* // returns translator instance for german
|
||||
* new SCThingTranslator('de');
|
||||
*/
|
||||
constructor(language: keyof SCTranslations<SCThing>, baseLanguage?: keyof SCTranslations<SCThing>) {
|
||||
this.baseLanguage = baseLanguage ? baseLanguage : 'en';
|
||||
this.language = language;
|
||||
constructor(language: keyof SCTranslations<SCThing>, cacheCapacity: number = 200) {
|
||||
this.cache = new LRUCache(cacheCapacity);
|
||||
this._language = language;
|
||||
this.metaClasses = SCClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for language property
|
||||
*/
|
||||
get language(): keyof SCTranslations<SCThing> {
|
||||
return this._language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for language property. Also flushes translation cache
|
||||
*
|
||||
* @param language The language the translator instance will use from now on
|
||||
*/
|
||||
set language(language: keyof SCTranslations<SCThing>) {
|
||||
if (language !== this._language) {
|
||||
this.cache.flush();
|
||||
}
|
||||
this._language = language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field value translation recursively
|
||||
*
|
||||
* @param firstObject Top level object that gets passed through the recursion
|
||||
* @param data The intermediate object / primitive returned by the Proxys get() method
|
||||
* @param keyPath The keypath that (in the end) leads to the translatable property (when added to firstObject)
|
||||
* @returns an OCType<T> object allowing for access to translations or a translated value(s)
|
||||
*/
|
||||
private deeptranslate<T, K extends SCThing>(firstObject: K, data?: T, keyPath?: string): OCType<T> {
|
||||
private deeptranslate<T>(data?: T): OCType<T> {
|
||||
const proxy = new Proxy(
|
||||
((defaultValue?: Defined<T>) => (data == null ? defaultValue : data)) as OCType<T>,
|
||||
{
|
||||
get: (target, key) => {
|
||||
const obj: any = target();
|
||||
const extendedKeyPath = [keyPath, key.toString()].filter((e) => e != null).join('.');
|
||||
let possiblePrimitive = obj[key];
|
||||
// check if obj[key] is an array that contains primitive type (arrays in SCThings are not mixing types)
|
||||
if (obj[key] instanceof Array && obj[key].length) {
|
||||
possiblePrimitive = obj[key][0];
|
||||
}
|
||||
if (typeof possiblePrimitive === 'string' ||
|
||||
typeof possiblePrimitive === 'number' ||
|
||||
typeof possiblePrimitive === 'boolean') {
|
||||
// returns final translation for primitive data types
|
||||
return this.deeptranslate(firstObject,
|
||||
this.getFieldValueTranslation(firstObject, extendedKeyPath),
|
||||
extendedKeyPath);
|
||||
}
|
||||
// recursion to get more calls to the Proxy handler 'get()' (key path not complete)
|
||||
return this.deeptranslate(firstObject, obj[key], extendedKeyPath);
|
||||
return this.deeptranslate(obj[key]);
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -98,19 +103,19 @@ export class SCThingTranslator {
|
||||
language: keyof SCTranslations<T>): object | undefined {
|
||||
const fieldTranslations = {};
|
||||
const metaClass = this.getMetaClassInstance(thingType);
|
||||
if (metaClass === undefined) {
|
||||
if (typeof metaClass === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Assigns every property in fieldTranslations to the known base language translation
|
||||
if (metaClass.fieldTranslations[this.baseLanguage] !== undefined) {
|
||||
Object.keys(metaClass.fieldTranslations[this.baseLanguage]).forEach((key) => {
|
||||
(fieldTranslations as any)[key] = metaClass.fieldTranslations[this.baseLanguage][key];
|
||||
if (typeof metaClass.fieldTranslations.en !== 'undefined') {
|
||||
Object.keys(metaClass.fieldTranslations.en).forEach((key) => {
|
||||
(fieldTranslations as any)[key] = metaClass.fieldTranslations.en[key];
|
||||
});
|
||||
}
|
||||
|
||||
// Assigns every property in fieldTranslations to the known translation in given language
|
||||
if (metaClass.fieldTranslations[language] !== undefined) {
|
||||
if (typeof metaClass.fieldTranslations[language] !== 'undefined') {
|
||||
Object.keys(metaClass.fieldTranslations[language]).forEach((key) => {
|
||||
(fieldTranslations as any)[key] = metaClass.fieldTranslations[language][key];
|
||||
});
|
||||
@@ -132,120 +137,34 @@ export class SCThingTranslator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns property value at a certain (key) path of an object.
|
||||
* @example
|
||||
* // returns value of dish.offers[0].inPlace.categories[1]
|
||||
* const dish: SCDish = {...};
|
||||
* this.valueFromPath(dish, 'offers[0].inPlace.categories[1]');
|
||||
* @param path Key path to evaluate
|
||||
* @param obj Object to evaluate the key path upon
|
||||
* @param separator Key path seperation element. Defaults to '.'
|
||||
* @returns Property value at at key path
|
||||
* Applies known field value translations of the given SCThings meta class to an instance
|
||||
* Translated values overwrite current values inplace (destructive)
|
||||
*
|
||||
* @param language The language the thing is translated to
|
||||
* @param thing The thing that will be translated
|
||||
* @returns The thing with translated meta field values
|
||||
*/
|
||||
private valueFromPath<T extends SCThing>(path: string, obj: T, separator = '.') {
|
||||
path = path.replace(/\[/g, '.');
|
||||
path = path.replace(/\]/g, '.');
|
||||
path = path.replace(/\.\./g, '.');
|
||||
path = path.replace(/\.$/, '');
|
||||
const properties = path.split(separator);
|
||||
return properties.reduce((prev: any, curr: any) => prev && prev[curr], obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field value translation
|
||||
* @example
|
||||
* // returns translation of the property (if available) in the language defined when creating the translator object
|
||||
* const dish: SCDish = {...};
|
||||
* translator.translate(dish, 'offers[0].inPlace.categories[1]');
|
||||
* @param thing SCThing to get value translation for
|
||||
* @param field Field to get value translation for (keypath allowed)
|
||||
* @returns Translated value(s) or value(s) itself
|
||||
*/
|
||||
public getFieldValueTranslation<T extends SCThing>(thing: T,
|
||||
field: SCThingsField): string | string[] {
|
||||
let translationPath = 'translations.' + this.language + '.' + field;
|
||||
const regexTrimProperties = /.*(?:(\..*)(\[\d+\])|(\.[^\d]*$)|(\..*)(\.[\d]*$))/;
|
||||
|
||||
const pathMatch = field.match(regexTrimProperties);
|
||||
|
||||
// when translation is given in thing
|
||||
let translation = this.valueFromPath(translationPath, thing);
|
||||
if (translation) {
|
||||
return translation;
|
||||
} else if (pathMatch && pathMatch[1] && pathMatch[2] || pathMatch && pathMatch[4] && pathMatch[5]) {
|
||||
// accessing iteratable of nested thing
|
||||
const keyPath = (pathMatch[1] ? pathMatch[1] : pathMatch[4]) + (pathMatch[2] ? pathMatch[2] : pathMatch[5]);
|
||||
const redactedField = field.replace(keyPath, '');
|
||||
|
||||
// when translation is given in nested thing
|
||||
translationPath = `${redactedField}.translations.${this.language}${keyPath}`;
|
||||
translation = this.valueFromPath(translationPath, thing);
|
||||
if (translation) {
|
||||
return translation;
|
||||
}
|
||||
|
||||
// when translation is given in nested meta thing via iterateable index
|
||||
const nestedType = this.valueFromPath(field.replace(keyPath, '.type'), thing) as SCThingType;
|
||||
translationPath = `fieldValueTranslations.${this.language}${keyPath}`;
|
||||
translation = this.valueFromPath(translationPath.replace(
|
||||
/\[(?=[^\[]*$).*|(?=[\d+]*$).*/, '[' + this.valueFromPath(field, thing) + ']'),
|
||||
this.getMetaClassInstance(nestedType));
|
||||
if (translation) {
|
||||
return translation;
|
||||
}
|
||||
|
||||
} else if (pathMatch && pathMatch[3]) {
|
||||
// accessing meta or instance of nested thing primitive value depth > 0
|
||||
const keyPath = pathMatch[3];
|
||||
const redactedField = field.replace(pathMatch[3], '');
|
||||
|
||||
// when translation is given in nested thing
|
||||
translationPath = `${redactedField}.translations.${this.language}${keyPath}`;
|
||||
if (this.valueFromPath(translationPath, thing)) {
|
||||
return this.valueFromPath(translationPath, thing);
|
||||
}
|
||||
|
||||
// when translation is given in nested meta thing
|
||||
const nestedType = this.valueFromPath(field.replace(keyPath, '.type'), thing) as SCThingType;
|
||||
translationPath = `fieldValueTranslations.${this.language}${keyPath}`;
|
||||
translation = this.valueFromPath(translationPath, this.getMetaClassInstance(nestedType));
|
||||
if (translation instanceof Object) { // lookup translated keys in meta thing property
|
||||
const translations: string[] = [];
|
||||
this.valueFromPath(field, thing).forEach((key: string) => {
|
||||
translationPath = `fieldValueTranslations.${this.language}${keyPath}.${key}`;
|
||||
translations.push(this.valueFromPath(translationPath, this.getMetaClassInstance(nestedType)));
|
||||
});
|
||||
return translations;
|
||||
}
|
||||
if (!translation) { // translation not given, return as is
|
||||
return this.valueFromPath(field, thing) as string;
|
||||
}
|
||||
return translation;
|
||||
private replaceAvailableMetaFieldValueTranslations(instance: any,
|
||||
language: keyof SCTranslations<any>): any {
|
||||
const metaClass = this.getMetaClassInstance(instance.type);
|
||||
if (typeof metaClass === 'undefined') {
|
||||
return instance;
|
||||
}
|
||||
// accessing meta thing primitive value depth = 0
|
||||
translationPath = `fieldValueTranslations.${this.language}.${field}`;
|
||||
translation = this.valueFromPath(translationPath, this.getMetaClassInstance(thing.type));
|
||||
if (translation) {
|
||||
if (translation instanceof Object) { // lookup translated keys in meta thing property
|
||||
const translations: string[] = [];
|
||||
this.valueFromPath(field, thing).forEach((key: string) => {
|
||||
translationPath = `fieldValueTranslations.${this.language}.${field}.${key}`;
|
||||
translations.push(this.valueFromPath(translationPath, this.getMetaClassInstance(thing.type)));
|
||||
});
|
||||
return translations;
|
||||
}
|
||||
return translation;
|
||||
if (typeof metaClass.fieldValueTranslations[language] !== 'undefined') {
|
||||
Object.keys(metaClass.fieldValueTranslations[language]).forEach((key) => {
|
||||
if (metaClass.fieldValueTranslations[language][key] instanceof Object) {
|
||||
// Assigns known translations of subproperties to property in given language (e.g. categories)
|
||||
Object.keys((instance as any)[key]).forEach((subKey) => {
|
||||
(instance as any)[key][subKey] =
|
||||
metaClass.fieldValueTranslations[language][key][(instance as any)[key][subKey]];
|
||||
});
|
||||
} else {
|
||||
// Assigns property to known translation of fieldValueTranslations in given language
|
||||
(instance as any)[key] = metaClass.fieldValueTranslations[language][key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// accessing meta thing primitive via iteratable index value depth = 0
|
||||
translation = this.valueFromPath(translationPath.replace(
|
||||
/\[(?=[^\[]*$).*|(?=[\d+]*$).*/, '[' + this.valueFromPath(field, thing) + ']'),
|
||||
this.getMetaClassInstance(thing.type));
|
||||
if (translation) {
|
||||
return translation;
|
||||
}
|
||||
// last resort: return as is
|
||||
return this.valueFromPath(field, thing) as string;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,33 +180,27 @@ export class SCThingTranslator {
|
||||
* @param data Top level object that gets passed through the recursion
|
||||
* @returns an OCType<T> object allowing for access to translations or a translated value(s)
|
||||
*/
|
||||
public translate<T extends SCThing>(data?: T): OCType<T> {
|
||||
public translate<T extends SCThing>(data: T): OCType<T> {
|
||||
return new Proxy(
|
||||
((defaultValue?: Defined<T>) => (data == null ? defaultValue : data)) as OCType<T>,
|
||||
{
|
||||
get: (target, key) => {
|
||||
const obj: any = target();
|
||||
let translatable = obj[key];
|
||||
if (obj[key] instanceof Array && obj[key].length) {
|
||||
translatable = obj[key][0];
|
||||
if (typeof obj[key][0] === 'object' && !obj[key][0].origin) {
|
||||
translatable = obj[key][0][Object.keys(obj[key][0])[0]];
|
||||
}
|
||||
const objTranslatedFromCache = this.cache.get(data);
|
||||
if (typeof objTranslatedFromCache !== 'undefined') {
|
||||
return this.deeptranslate((objTranslatedFromCache as any)[key]);
|
||||
}
|
||||
if (typeof translatable === 'string') {
|
||||
// retrieve final translation
|
||||
return this.deeptranslate(data!, this.getFieldValueTranslation(data!, key.toString()), key.toString());
|
||||
}
|
||||
// recursion to get more calls to the Proxy handler 'get()' (key path not complete)
|
||||
return this.deeptranslate(data!, obj[key], key.toString());
|
||||
const objTranslated = this.translateWholeThingDestructively(clone(obj));
|
||||
this.cache.putObject(objTranslated);
|
||||
return this.deeptranslate(objTranslated[key]);
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a SCThingType this function returns an object with the same basic structure as the corresponding SCThing.
|
||||
* All the values will be set to the known translations of the property/key name.
|
||||
* Given a SCThingType this function returns an object with the same basic structure as the corresponding SCThing
|
||||
* All the values will be set to the known translations of the property/key name
|
||||
* @example
|
||||
* const translatedMetaDish = translator.translatedPropertyNames<SCCourseOfStudies>(SCThingType.CourseOfStudies);
|
||||
* @param language The language the object is translated to
|
||||
@@ -300,4 +213,129 @@ export class SCThingTranslator {
|
||||
// return {...{}, ...this.getAllMetaFieldTranslations(thing.type, targetLanguage) as T};
|
||||
return this.getAllMetaFieldTranslations(thing.type, targetLanguage) as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively translates the given object in-place
|
||||
* Translated values overwrite current values (destructive)
|
||||
*
|
||||
* @param language The language the thing is translated to
|
||||
* @param thing The thing that will be translated
|
||||
* @returns The thing translated
|
||||
*/
|
||||
public translateWholeThingDestructively(instance: any,
|
||||
language?: keyof SCTranslations<any>): any {
|
||||
const targetLanguage = (language) ? language : this.language;
|
||||
// Recursively call this function on all nested SCThings, arrays and objects
|
||||
Object.keys(instance).forEach((key) => {
|
||||
if (
|
||||
isThing((instance as any)[key]) ||
|
||||
instance[key] instanceof Array ||
|
||||
instance[key] instanceof Object) {
|
||||
instance[key] = this.translateWholeThingDestructively(instance[key], targetLanguage);
|
||||
}
|
||||
});
|
||||
|
||||
// Spread variable translations given by the connector into thing
|
||||
if (typeof instance.translations !== 'undefined') {
|
||||
if (typeof instance.translations![targetLanguage] !== 'undefined') {
|
||||
instance = {...instance, ...instance.translations![targetLanguage]} as typeof instance;
|
||||
}
|
||||
}
|
||||
// Spread known translations from meta classes into (partly) translated thing
|
||||
this.replaceAvailableMetaFieldValueTranslations(instance, targetLanguage);
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* LRUCache class
|
||||
* Small last recently used cache intended to get used by SCThingTranslator
|
||||
*/
|
||||
class LRUCache<T> {
|
||||
/**
|
||||
* Map property that manages cached content
|
||||
*/
|
||||
private entries: Map<string, T> = new Map<string, T>();
|
||||
|
||||
/**
|
||||
* Property representing cache maximum capacity
|
||||
*/
|
||||
private maxEntries: number;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @example
|
||||
* // returns LRUCache instance with a maximum capacity of 500
|
||||
* new LRUCache(500);
|
||||
*/
|
||||
constructor(maxEntries: number) {
|
||||
this.maxEntries = maxEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes cache / removes all entries
|
||||
*/
|
||||
public flush() {
|
||||
this.entries.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content from cache by key
|
||||
*/
|
||||
public get(somethingOrKey: string): T | undefined;
|
||||
|
||||
/**
|
||||
* Get content from cache by another objects uid
|
||||
*/
|
||||
public get<U extends SCThing>(something: U): T | undefined;
|
||||
|
||||
/**
|
||||
* Get content from cache by key or by another objects uid
|
||||
*
|
||||
* @param somethingOrKey The key which maps to the cached content or an object for which content has been cached
|
||||
* @returns If available the content connected to the key or somethingOrKey.uid property
|
||||
*/
|
||||
public get<U extends SCThing>(somethingOrKey: string | U): T | undefined {
|
||||
let key: string;
|
||||
if (typeof somethingOrKey === 'string') {
|
||||
key = somethingOrKey;
|
||||
} else if (isThing(somethingOrKey)) {
|
||||
key = somethingOrKey.uid;
|
||||
} else {
|
||||
throw new Error(`Passed argument ${somethingOrKey} cannot be key in LRUCache`);
|
||||
}
|
||||
|
||||
const entry = this.entries.get(key);
|
||||
if (entry) {
|
||||
// LRU behavior
|
||||
this.entries.delete(key);
|
||||
this.entries.set(key, entry);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Place content in cache by key
|
||||
*
|
||||
* @param key The key for which content should be cached
|
||||
* @param content The content that should be cached
|
||||
*/
|
||||
public put(key: string, content: T) {
|
||||
if (this.entries.size >= this.maxEntries) {
|
||||
// LRU behavior
|
||||
const keyToDelete = this.entries.keys().next().value;
|
||||
this.entries.delete(keyToDelete);
|
||||
}
|
||||
this.entries.set(key, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Place content in cache by another objects uid
|
||||
*
|
||||
* @param something The object that should be cached under something.uid
|
||||
*/
|
||||
public putObject<U extends SCThing>(something: U) {
|
||||
this.put(something.uid, (something as any) as T);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,19 @@ import {SCThing, SCThingUserOrigin} from '../Thing';
|
||||
/**
|
||||
* An encapsulation of the data (e.g. a thing) that is saved, which provides additional information.
|
||||
*/
|
||||
export interface SCSaveableThing<T extends SCThing> extends SCThing {
|
||||
/**
|
||||
* The contained data
|
||||
*/
|
||||
data: T;
|
||||
|
||||
export interface SCSaveableThingWithoutReferences extends SCThing {
|
||||
/**
|
||||
* Type of the origin
|
||||
*/
|
||||
origin: SCThingUserOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* An encapsulation of the data (e.g. a thing) that is saved, which provides additional information.
|
||||
*/
|
||||
export interface SCSaveableThing<T extends SCThing> extends SCSaveableThingWithoutReferences {
|
||||
/**
|
||||
* The contained data
|
||||
*/
|
||||
data: T;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 StApps
|
||||
* Copyright (C) 2018, 2019 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.
|
||||
@@ -16,8 +16,8 @@ import {SCThing, SCThingTranslatableProperties} from '../Thing';
|
||||
import {SCOrganizationWithoutReferences} from '../things/Organization';
|
||||
import {SCPersonWithoutReferences} from '../things/Person';
|
||||
import {SCTranslations} from '../types/i18n';
|
||||
import {SCInPlace} from '../types/Places';
|
||||
import {SCISO8601Date} from '../types/Time';
|
||||
import {SCInPlace} from './../types/Places';
|
||||
|
||||
/**
|
||||
* Default price without distinction
|
||||
@@ -50,7 +50,17 @@ export interface SCAcademicPriceGroup extends SCPriceGroup {
|
||||
}
|
||||
|
||||
/**
|
||||
* A thing without references that has a price tag
|
||||
* A thing without references that can be offered
|
||||
*/
|
||||
export interface SCThingThatCanBeOfferedWithoutReferences extends SCThing {
|
||||
/**
|
||||
* Translations of a thing that can be offered
|
||||
*/
|
||||
translations?: SCTranslations<SCThingThatCanBeOfferedTranslatableProperties>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A thing that can be offered
|
||||
*/
|
||||
export interface SCThingThatCanBeOffered<T extends SCPriceGroup>
|
||||
extends SCThing {
|
||||
@@ -58,11 +68,6 @@ export interface SCThingThatCanBeOffered<T extends SCPriceGroup>
|
||||
* List of offers for that thing
|
||||
*/
|
||||
offers?: Array<SCThingThatCanBeOfferedOffer<T>>;
|
||||
|
||||
/**
|
||||
* Translations of a thing that can be offered
|
||||
*/
|
||||
translations?: SCTranslations<SCThingThatCanBeOfferedTranslatableProperties>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,7 @@ export abstract class SCError implements SCErrorResponse {
|
||||
|
||||
/**
|
||||
* Instatiate an SCError
|
||||
*
|
||||
* @param name Name of the error
|
||||
* @param message Message of the error
|
||||
* @param statusCode HTTP status code to return this error with
|
||||
@@ -66,6 +67,7 @@ export class SCValidationErrorResponse extends SCError {
|
||||
|
||||
/**
|
||||
* Create a SCValidationErrorResponse
|
||||
*
|
||||
* @param errors List of validation errors
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
@@ -81,6 +83,7 @@ export class SCValidationErrorResponse extends SCError {
|
||||
export class SCUnsupportedMediaTypeErrorResponse extends SCError {
|
||||
/**
|
||||
* Create a SCUnsupportedMediaTypeErrorResponse
|
||||
*
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
constructor(stack?: boolean) {
|
||||
@@ -94,6 +97,7 @@ export class SCUnsupportedMediaTypeErrorResponse extends SCError {
|
||||
export class SCMethodNotAllowedErrorResponse extends SCError {
|
||||
/**
|
||||
* Create a SCMethodNotAllowedErrorResponse
|
||||
*
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
constructor(stack?: boolean) {
|
||||
@@ -120,6 +124,7 @@ export class SCRequestBodyTooLargeErrorResponse extends SCError {
|
||||
export class SCTooManyRequestsErrorResponse extends SCError {
|
||||
/**
|
||||
* Create a SCTooManyRequestsErrorResponse
|
||||
*
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
constructor(stack?: boolean) {
|
||||
@@ -133,6 +138,7 @@ export class SCTooManyRequestsErrorResponse extends SCError {
|
||||
export class SCNotFoundErrorResponse extends SCError {
|
||||
/**
|
||||
* Create a SCNotFoundErrorResponse
|
||||
*
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
constructor(stack?: boolean) {
|
||||
@@ -140,12 +146,80 @@ export class SCNotFoundErrorResponse extends SCError {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error that is returned when the request is in the right format, but contains parameters that are invalid or not
|
||||
* acceptable.
|
||||
*/
|
||||
export class SCParametersNotAcceptable extends SCError {
|
||||
/**
|
||||
* Create a ParametersNotAcceptable
|
||||
*
|
||||
* @param message contains more details to what you did wrong
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
constructor(message: string, stack?: boolean) {
|
||||
super('ParametersNotAcceptable', message, 406, stack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error that is returned when a plugin with the same name is already registered, to prevent two copies of a plugin
|
||||
* running at the same time.
|
||||
* This usually indicates that there is more than one instance a plugin running.
|
||||
*/
|
||||
export class SCPluginAlreadyRegisteredErrorResponse extends SCError {
|
||||
/**
|
||||
* Create a PluginAlreadyRegisteredError
|
||||
*
|
||||
* @param message contains potential differences in other parameters outside of the name
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
constructor(message: string, stack?: boolean) {
|
||||
super('PluginRegisteringFailedError', message, 409, stack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error that is returned whenever there is an unexpected error while creating a plugin
|
||||
*/
|
||||
export class SCPluginRegisteringFailedErrorResponse extends SCError {
|
||||
/**
|
||||
* Create a PluginRegisteringFailedError
|
||||
*
|
||||
* @param message Describes what went wrong wile registering the plugin
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
constructor(message: string, stack?: boolean) {
|
||||
super('PluginRegisteringFailedError', message, 500, stack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error that is returned whenever there is a plugin request that is supposed to register a route, that is already
|
||||
* registered
|
||||
* This usually indicates that two **different** plugins use the same route.
|
||||
*/
|
||||
export class SCPluginRouteAlreadyRegisteredErrorResponse extends SCError {
|
||||
/**
|
||||
* Create a PluginRouteAlreadyRegisteredError
|
||||
*
|
||||
* @param registeredName The name by the plugin that has already registered the route previously
|
||||
* @param registeredUrl The URL by the plugin that has already registered the route previously
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
constructor(registeredName: string, registeredUrl: string, stack?: boolean) {
|
||||
super('PluginRouteAlreadyRegisteredError',
|
||||
`Already registered by "${registeredName}" under URL "${registeredUrl}".`, 409, stack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error that is returned whenever there is a syntax error
|
||||
*/
|
||||
export class SCSyntaxErrorResponse extends SCError {
|
||||
/**
|
||||
* Create a SyntaxError
|
||||
*
|
||||
* @param message Describes the syntax error
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
*/
|
||||
@@ -165,6 +239,7 @@ export class SCInternalServerErrorResponse extends SCError {
|
||||
|
||||
/**
|
||||
* Create a SCInternalServerErrorResponse
|
||||
*
|
||||
* @param err Internal server error
|
||||
* @param stack Set to true if a stack trace should be created
|
||||
* and the internal server error should be displayed to the client
|
||||
|
||||
100
src/core/protocol/routes/plugin/PluginRegisterRequest.ts
Normal file
100
src/core/protocol/routes/plugin/PluginRegisterRequest.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 {Schema} from 'jsonschema';
|
||||
import {SCAbstractRoute, SCRouteHttpVerbs} from '../../../Route';
|
||||
import {
|
||||
SCInternalServerErrorResponse,
|
||||
SCMethodNotAllowedErrorResponse, SCParametersNotAcceptable,
|
||||
SCPluginAlreadyRegisteredErrorResponse,
|
||||
SCPluginRegisteringFailedErrorResponse,
|
||||
SCPluginRouteAlreadyRegisteredErrorResponse,
|
||||
SCRequestBodyTooLargeErrorResponse,
|
||||
SCSyntaxErrorResponse,
|
||||
} from '../../errors/ErrorResponse';
|
||||
|
||||
/**
|
||||
* Plugin register request
|
||||
*
|
||||
* @validatable
|
||||
*/
|
||||
export type SCPluginRegisterRequest = AddPlugin | RemovePlugin;
|
||||
interface AddPlugin {
|
||||
/**
|
||||
* The desired action, so whether the plugin should be added or removed
|
||||
*/
|
||||
action: 'add';
|
||||
|
||||
/**
|
||||
* The address of the plugin
|
||||
*/
|
||||
address: string;
|
||||
|
||||
/**
|
||||
* The name of the plugin
|
||||
* Just for debugging purposes, to more easily identify conflicts.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* How the requests of the plugin looks like, a JSON schema for validation
|
||||
*/
|
||||
pluginRequestSchema: Schema;
|
||||
|
||||
/**
|
||||
* How the responses of the plugin looks like, a JSON schema for validation
|
||||
*/
|
||||
pluginResponseSchema: Schema;
|
||||
|
||||
/**
|
||||
* The desired route, for example /feedback.
|
||||
*/
|
||||
route: string;
|
||||
}
|
||||
interface RemovePlugin {
|
||||
/**
|
||||
* The desired action, so whether the plugin should be added or removed
|
||||
*/
|
||||
action: 'remove';
|
||||
|
||||
/**
|
||||
* The route of the plugin you want to remove
|
||||
*/
|
||||
route: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to register plugins
|
||||
*/
|
||||
export class SCPluginRegisterRoute extends SCAbstractRoute {
|
||||
constructor() {
|
||||
super();
|
||||
this.errorNames = [
|
||||
SCInternalServerErrorResponse,
|
||||
SCMethodNotAllowedErrorResponse,
|
||||
SCParametersNotAcceptable,
|
||||
SCPluginAlreadyRegisteredErrorResponse,
|
||||
SCPluginRouteAlreadyRegisteredErrorResponse,
|
||||
SCPluginRegisteringFailedErrorResponse,
|
||||
SCPluginRouteAlreadyRegisteredErrorResponse,
|
||||
SCRequestBodyTooLargeErrorResponse,
|
||||
SCSyntaxErrorResponse,
|
||||
];
|
||||
this.method = SCRouteHttpVerbs.POST;
|
||||
this.requestBodyName = 'SCPluginRegisterRequest';
|
||||
this.responseBodyName = 'SCPluginRegisterResponse';
|
||||
this.statusCodeSuccess = 200;
|
||||
this.urlFragment = '/plugin/register';
|
||||
}
|
||||
}
|
||||
26
src/core/protocol/routes/plugin/PluginRegisterResponse.ts
Normal file
26
src/core/protocol/routes/plugin/PluginRegisterResponse.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Plugin register response
|
||||
*
|
||||
* @validatable
|
||||
*/
|
||||
export interface SCPluginRegisterResponse {
|
||||
/**
|
||||
* Whether the desired action succeeded or failed (true for success, false if an error occurred)
|
||||
*/
|
||||
success: boolean;
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {SCAbstractRoute, SCRouteHttpVerbs} from '../../../Route';
|
||||
import {SCSearchContext} from '../../../types/config/Backend';
|
||||
import {SCSearchFilter} from '../../../types/filters/Abstract';
|
||||
import {SCSearchSort} from '../../../types/sorts/Abstract';
|
||||
import {
|
||||
@@ -37,7 +38,12 @@ export interface SCSearchRequest extends SCSearchQuery {
|
||||
*/
|
||||
export interface SCSearchQuery {
|
||||
/**
|
||||
* A filter structure that combines any number of filters with boolean methods ('AND', 'OR', 'NOT')
|
||||
* The context name from where the search query was initiated
|
||||
*/
|
||||
context?: SCSearchContext;
|
||||
|
||||
/**
|
||||
* A filter structure that combines any number of filters with boolean methods ('AND', 'OR', 'NOT')
|
||||
*/
|
||||
filter?: SCSearchFilter;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 StApps
|
||||
* Copyright (C) 2018, 2019 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.
|
||||
@@ -13,9 +13,12 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {SCAcademicDegree, SCAcademicDegreeMeta} from '../base/AcademicDegree';
|
||||
import {SCAcademicPriceGroup,
|
||||
SCThingThatCanBeOffered,
|
||||
SCThingThatCanBeOfferedTranslatableProperties} from '../base/ThingThatCanBeOffered';
|
||||
import {
|
||||
SCAcademicPriceGroup,
|
||||
SCThingThatCanBeOffered,
|
||||
SCThingThatCanBeOfferedTranslatableProperties,
|
||||
SCThingThatCanBeOfferedWithoutReferences,
|
||||
} from '../base/ThingThatCanBeOffered';
|
||||
import {SCThingMeta, SCThingType} from '../Thing';
|
||||
import {SCLanguage, SCMetaTranslations, SCTranslations} from '../types/i18n';
|
||||
import {SCDateSeriesWithoutReferences} from './DateSeries';
|
||||
@@ -24,9 +27,8 @@ import {SCOrganization} from './Organization';
|
||||
/**
|
||||
* A course of studies without references
|
||||
*/
|
||||
export interface SCCourseOfStudiesWithoutReferences extends
|
||||
SCAcademicDegree,
|
||||
SCThingThatCanBeOffered<SCAcademicPriceGroup> {
|
||||
export interface SCCourseOfStudiesWithoutReferences extends SCAcademicDegree,
|
||||
SCThingThatCanBeOfferedWithoutReferences {
|
||||
/**
|
||||
* The main language in which the course of studies
|
||||
* is beeing offered
|
||||
@@ -64,14 +66,15 @@ export interface SCCourseOfStudiesWithoutReferences extends
|
||||
*
|
||||
* @validatable
|
||||
*/
|
||||
export interface SCCourseOfStudies extends SCCourseOfStudiesWithoutReferences {
|
||||
export interface SCCourseOfStudies extends SCCourseOfStudiesWithoutReferences,
|
||||
SCThingThatCanBeOffered<SCAcademicPriceGroup> {
|
||||
/**
|
||||
* The department that manages the course of studies
|
||||
*/
|
||||
department: SCOrganization;
|
||||
|
||||
/**
|
||||
* The secretary that administers requests and
|
||||
* The secretary that administers requests and
|
||||
* questions concerning the course of studies
|
||||
*/
|
||||
secretary: SCOrganization;
|
||||
@@ -81,6 +84,11 @@ export interface SCCourseOfStudies extends SCCourseOfStudiesWithoutReferences {
|
||||
*/
|
||||
startDates?: SCDateSeriesWithoutReferences[];
|
||||
|
||||
/**
|
||||
* Translated fields of a dish
|
||||
*/
|
||||
translations?: SCTranslations<SCCourseOfStudiesTranslatableProperties>;
|
||||
|
||||
/**
|
||||
* Type of the course of studies
|
||||
*/
|
||||
@@ -88,7 +96,7 @@ export interface SCCourseOfStudies extends SCCourseOfStudiesWithoutReferences {
|
||||
}
|
||||
|
||||
export interface SCCourseOfStudiesTranslatableProperties
|
||||
extends SCThingThatCanBeOfferedTranslatableProperties {
|
||||
extends SCThingThatCanBeOfferedTranslatableProperties {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,19 +108,19 @@ export class SCCourseOfStudiesMeta extends SCThingMeta implements SCMetaTranslat
|
||||
*/
|
||||
fieldTranslations = {
|
||||
de: {
|
||||
... SCAcademicDegreeMeta.getInstance().fieldTranslations.de,
|
||||
...SCAcademicDegreeMeta.getInstance().fieldTranslations.de,
|
||||
},
|
||||
en: {
|
||||
... SCAcademicDegreeMeta.getInstance().fieldTranslations.en,
|
||||
...SCAcademicDegreeMeta.getInstance().fieldTranslations.en,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Translations of values of fields
|
||||
*/
|
||||
fieldValueTranslations = {
|
||||
fieldValueTranslations = {
|
||||
de: {
|
||||
... SCAcademicDegreeMeta.getInstance().fieldValueTranslations.de,
|
||||
...SCAcademicDegreeMeta.getInstance().fieldValueTranslations.de,
|
||||
modes: {
|
||||
combination: 'Kombinationsstudiengang',
|
||||
dual: 'Dualer Studiengang',
|
||||
@@ -122,7 +130,7 @@ export class SCCourseOfStudiesMeta extends SCThingMeta implements SCMetaTranslat
|
||||
type: 'Studiengang',
|
||||
},
|
||||
en: {
|
||||
... SCAcademicDegreeMeta.getInstance().fieldValueTranslations.en,
|
||||
...SCAcademicDegreeMeta.getInstance().fieldValueTranslations.en,
|
||||
academicDegree: 'Hochschulabschluss',
|
||||
department: 'Fachbereich',
|
||||
major: 'Studienfach',
|
||||
@@ -136,13 +144,13 @@ export class SCCourseOfStudiesMeta extends SCThingMeta implements SCMetaTranslat
|
||||
/**
|
||||
* Types of (german) course of studies modes
|
||||
*/
|
||||
export type SCCourseOfStudiesMode = 'combination' |
|
||||
'dual' |
|
||||
'double-degree' |
|
||||
'standard' ;
|
||||
export type SCCourseOfStudiesMode = 'combination'
|
||||
| 'dual'
|
||||
| 'double-degree'
|
||||
| 'standard' ;
|
||||
|
||||
/**
|
||||
* Types of (german) course of studies time modes
|
||||
*/
|
||||
export type SCCourseOfStudiesTimeMode = 'fulltime' |
|
||||
'parttime' ;
|
||||
export type SCCourseOfStudiesTimeMode = 'fulltime'
|
||||
| 'parttime' ;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 StApps
|
||||
* Copyright (C) 2018, 2019 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.
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
SCAcademicPriceGroup,
|
||||
SCThingThatCanBeOffered,
|
||||
SCThingThatCanBeOfferedTranslatableProperties,
|
||||
SCThingThatCanBeOfferedWithoutReferences,
|
||||
} from '../base/ThingThatCanBeOffered';
|
||||
import {SCThingMeta, SCThingType} from '../Thing';
|
||||
import {SCMetaTranslations, SCTranslations} from '../types/i18n';
|
||||
@@ -38,8 +39,7 @@ export interface SCSportCoursePriceGroup extends SCAcademicPriceGroup {
|
||||
/**
|
||||
* A date without references
|
||||
*/
|
||||
export interface SCDateSeriesWithoutReferences
|
||||
extends SCThingThatCanBeOffered<SCSportCoursePriceGroup> {
|
||||
export interface SCDateSeriesWithoutReferences extends SCThingThatCanBeOfferedWithoutReferences {
|
||||
/**
|
||||
* Dates of the date series that are initially planned to be held
|
||||
*/
|
||||
@@ -76,7 +76,9 @@ export interface SCDateSeriesWithoutReferences
|
||||
*
|
||||
* @validatable
|
||||
*/
|
||||
export interface SCDateSeries extends SCDateSeriesWithoutReferences, SCThingInPlace {
|
||||
export interface SCDateSeries extends SCDateSeriesWithoutReferences,
|
||||
SCThingInPlace,
|
||||
SCThingThatCanBeOffered<SCSportCoursePriceGroup> {
|
||||
/**
|
||||
* Event to which the date series belongs
|
||||
*/
|
||||
@@ -108,26 +110,26 @@ export class SCDateSeriesMeta extends SCThingMeta implements SCMetaTranslations<
|
||||
*/
|
||||
fieldTranslations = {
|
||||
de: {
|
||||
... SCThingInPlaceMeta.getInstance().fieldTranslations.de,
|
||||
...SCThingInPlaceMeta.getInstance().fieldTranslations.de,
|
||||
},
|
||||
en: {
|
||||
... SCThingInPlaceMeta.getInstance().fieldTranslations.en,
|
||||
...SCThingInPlaceMeta.getInstance().fieldTranslations.en,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Translations of values of fields
|
||||
*/
|
||||
fieldValueTranslations = {
|
||||
fieldValueTranslations = {
|
||||
de: {
|
||||
... SCThingInPlaceMeta.getInstance().fieldValueTranslations.de,
|
||||
...SCThingInPlaceMeta.getInstance().fieldValueTranslations.de,
|
||||
dates: 'Einzeltermine',
|
||||
duration: 'Dauer',
|
||||
frequency: 'Wiederholung',
|
||||
type: 'Wiederholungreihe',
|
||||
},
|
||||
en: {
|
||||
... SCThingInPlaceMeta.getInstance().fieldValueTranslations.en,
|
||||
...SCThingInPlaceMeta.getInstance().fieldValueTranslations.en,
|
||||
type: SCThingType.DateSeries,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -64,11 +64,6 @@ export interface SCDiff extends SCDiffWithoutReferences {
|
||||
* Meta information about a diff
|
||||
*/
|
||||
export class SCDiffMeta extends SCThingMeta implements SCMetaTranslations<SCDiff> {
|
||||
/**
|
||||
* Set type definiton for singleton instance
|
||||
*/
|
||||
protected static _instance: SCThingMeta;
|
||||
|
||||
/**
|
||||
* Translations of fields
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 StApps
|
||||
* Copyright (C) 2018, 2019 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.
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
SCAcademicPriceGroup,
|
||||
SCThingThatCanBeOffered,
|
||||
SCThingThatCanBeOfferedTranslatableProperties,
|
||||
SCThingThatCanBeOfferedWithoutReferences,
|
||||
} from '../base/ThingThatCanBeOffered';
|
||||
import {
|
||||
SCThingWithCategoriesSpecificValues,
|
||||
@@ -29,12 +30,8 @@ import {SCMetaTranslations, SCTranslations} from '../types/i18n';
|
||||
/**
|
||||
* A dish without references
|
||||
*/
|
||||
export interface SCDishWithoutReferences
|
||||
extends SCThingWithCategoriesWithoutReferences<
|
||||
SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues
|
||||
>,
|
||||
SCThingThatCanBeOffered<SCAcademicPriceGroup> {
|
||||
export interface SCDishWithoutReferences extends SCThingThatCanBeOfferedWithoutReferences,
|
||||
SCThingWithCategoriesWithoutReferences<SCDishCategories, SCThingWithCategoriesSpecificValues> {
|
||||
/**
|
||||
* Additives of the dish
|
||||
*/
|
||||
@@ -71,7 +68,8 @@ export interface SCDishWithoutReferences
|
||||
*
|
||||
* @validatable
|
||||
*/
|
||||
export interface SCDish extends SCDishWithoutReferences {
|
||||
export interface SCDish extends SCDishWithoutReferences,
|
||||
SCThingThatCanBeOffered<SCAcademicPriceGroup> {
|
||||
/**
|
||||
* Dishes ("Beilagen") that are served with the dish (if only certain supplement dishes can be taken with a dish)
|
||||
*/
|
||||
@@ -173,22 +171,22 @@ export class SCDishMeta extends SCThingMeta implements SCMetaTranslations<SCDish
|
||||
*/
|
||||
fieldTranslations = {
|
||||
de: {
|
||||
... SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldTranslations.de,
|
||||
...SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldTranslations.de,
|
||||
},
|
||||
en: {
|
||||
... SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldTranslations.en,
|
||||
...SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldTranslations.en,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Translations of values of fields
|
||||
*/
|
||||
fieldValueTranslations = {
|
||||
fieldValueTranslations = {
|
||||
de: {
|
||||
... SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldValueTranslations.de,
|
||||
...SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldValueTranslations.de,
|
||||
categories: {
|
||||
appetizer: 'Vorspeise',
|
||||
dessert: 'Nachtisch',
|
||||
@@ -200,8 +198,8 @@ export class SCDishMeta extends SCThingMeta implements SCMetaTranslations<SCDish
|
||||
type: 'Essen',
|
||||
},
|
||||
en: {
|
||||
... SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldValueTranslations.en,
|
||||
...SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCDishCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldValueTranslations.en,
|
||||
type: SCThingType.Dish,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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 {SCSaveableThing} from '../base/SaveableThing';
|
||||
import {SCSaveableThing, SCSaveableThingWithoutReferences} from '../base/SaveableThing';
|
||||
import {SCThingMeta, SCThingType} from '../Thing';
|
||||
import {SCAcademicEventWithoutReferences} from './AcademicEvent';
|
||||
import {SCArticleWithoutReferences} from './Article';
|
||||
@@ -37,6 +37,13 @@ export type SCFavoriteDataTypes = SCAcademicEventWithoutReferences
|
||||
| SCSportCourseWithoutReferences
|
||||
| SCToDoWithoutReferences;
|
||||
|
||||
/**
|
||||
* A favorite without references
|
||||
*/
|
||||
export interface SCFavoriteWithoutReferences extends SCSaveableThingWithoutReferences {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A favorite
|
||||
*
|
||||
|
||||
@@ -28,11 +28,14 @@ export type SCSettingCategories = string;
|
||||
*/
|
||||
export interface SCSettingWithoutReferences
|
||||
extends SCThingWithCategoriesWithoutReferences<SCSettingCategories, SCThingWithCategoriesSpecificValues> {
|
||||
|
||||
/**
|
||||
* The type of input/value this setting is carrying
|
||||
* The default value of a setting
|
||||
*/
|
||||
input: SCSettingInputType;
|
||||
defaultValue: SCSettingValue | SCSettingValues;
|
||||
/**
|
||||
* The input type of this setting
|
||||
*/
|
||||
inputType: SCSettingInputType;
|
||||
/**
|
||||
* The order number this setting should show up in its category list
|
||||
*/
|
||||
@@ -45,16 +48,26 @@ export interface SCSettingWithoutReferences
|
||||
* The type of this model
|
||||
*/
|
||||
type: SCThingType.Setting;
|
||||
/**
|
||||
* The key of a value of a setting
|
||||
*/
|
||||
value?: SCSettingValue | SCSettingValues;
|
||||
/**
|
||||
* The possible values of a setting
|
||||
*/
|
||||
values?: SCSettingValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* The types of input/value a setting object can carry
|
||||
*/
|
||||
export type SCSettingInputType = SCSettingSingleChoice
|
||||
| SCSettingMultipleChoice
|
||||
| SCSettingNumber
|
||||
| SCSettingText
|
||||
| SCSettingPassword;
|
||||
export enum SCSettingInputType {
|
||||
SingleChoice = 'single choice',
|
||||
MultipleChoice = 'multiple choice',
|
||||
Number = 'number',
|
||||
Text = 'text',
|
||||
Password = 'password',
|
||||
}
|
||||
|
||||
/**
|
||||
* A setting with references
|
||||
@@ -69,58 +82,23 @@ export interface SCSetting extends SCSettingWithoutReferences {
|
||||
}
|
||||
|
||||
/**
|
||||
* Input type with single choice as value
|
||||
* The type a value of a setting can have
|
||||
*/
|
||||
export interface SCSettingSingleChoice {
|
||||
defaultValue: SCSettingValue;
|
||||
inputType: 'singleChoice';
|
||||
value?: SCSettingValue;
|
||||
values: SCSettingValue[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Input type with multiple choice as value
|
||||
*/
|
||||
export interface SCSettingMultipleChoice {
|
||||
defaultValue: SCSettingValue[];
|
||||
inputType: 'multipleChoice';
|
||||
value?: SCSettingValue[];
|
||||
values: SCSettingValue[];
|
||||
}
|
||||
|
||||
export type SCSettingValue = string | number | boolean;
|
||||
|
||||
/**
|
||||
* Input type with number as value
|
||||
* The type of multiple values a setting can have
|
||||
*/
|
||||
export interface SCSettingNumber {
|
||||
defaultValue: number;
|
||||
inputType: 'number';
|
||||
value?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input type with text as value
|
||||
*/
|
||||
export interface SCSettingText {
|
||||
defaultValue: string;
|
||||
inputType: 'text';
|
||||
value?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input type with secret text (eq. password) as value
|
||||
*/
|
||||
export interface SCSettingPassword {
|
||||
defaultValue: string;
|
||||
inputType: 'password';
|
||||
value?: string;
|
||||
}
|
||||
export type SCSettingValues = SCSettingValue[];
|
||||
|
||||
/**
|
||||
* Translatable properties of a setting
|
||||
*/
|
||||
export interface SCSettingValueTranslatableProperties extends SCThingWithCategoriesTranslatableProperties {
|
||||
/**
|
||||
* The translations of the possible values of a setting
|
||||
*/
|
||||
values?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,11 +113,17 @@ export class SCSettingMeta extends SCThingMeta implements SCMetaTranslations<SCS
|
||||
// tslint:disable-next-line:max-line-length
|
||||
... SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCSettingCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldTranslations.de,
|
||||
defaultValue: 'Standard Wert',
|
||||
inputType: 'Eingabetyp',
|
||||
value: 'Wert',
|
||||
values: 'Werte',
|
||||
},
|
||||
en: {
|
||||
// tslint:disable-next-line:max-line-length
|
||||
... SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCSettingCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldTranslations.en,
|
||||
defaultValue: 'default value',
|
||||
inputType: 'input type',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -151,6 +135,13 @@ export class SCSettingMeta extends SCThingMeta implements SCMetaTranslations<SCS
|
||||
// tslint:disable-next-line:max-line-length
|
||||
... SCThingWithCategoriesWithoutReferencesMeta.getInstance<SCSettingCategories,
|
||||
SCThingWithCategoriesSpecificValues>().fieldValueTranslations.de,
|
||||
inputType: {
|
||||
'multiple choice': 'mehrfach Auswahl',
|
||||
number: 'Zahl',
|
||||
password: 'Passwort',
|
||||
'single choice': 'einfache Auswahl',
|
||||
text: 'Text',
|
||||
},
|
||||
type: 'Einstellung',
|
||||
},
|
||||
en: {
|
||||
|
||||
171
src/core/things/StudyModule.ts
Normal file
171
src/core/things/StudyModule.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 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 {SCAcademicPriceGroup,
|
||||
SCThingThatCanBeOffered,
|
||||
SCThingThatCanBeOfferedTranslatableProperties} from '../base/ThingThatCanBeOffered';
|
||||
import {SCThingMeta, SCThingType} from '../Thing';
|
||||
import {SCLanguage, SCMetaTranslations, SCTranslations} from '../types/i18n';
|
||||
import {SCMap} from '../types/Map';
|
||||
import {SCAcademicEventWithoutReferences} from './AcademicEvent';
|
||||
import {SCOrganizationWithoutReferences} from './Organization';
|
||||
import {SCPersonWithoutReferences} from './Person';
|
||||
|
||||
/**
|
||||
* A study module without references
|
||||
*/
|
||||
export interface SCStudyModuleWithoutReferences extends
|
||||
SCThingThatCanBeOffered<SCAcademicPriceGroup> {
|
||||
|
||||
/**
|
||||
* ECTS points (European Credit Transfer System)
|
||||
*/
|
||||
ects: number;
|
||||
|
||||
/**
|
||||
* The language in which the study module is offered
|
||||
*/
|
||||
language: SCLanguage;
|
||||
|
||||
/**
|
||||
* Majors that this study module is meant for
|
||||
*/
|
||||
majors: string[];
|
||||
|
||||
/**
|
||||
* Represents the modules necessity for each given major (of the major property)
|
||||
*/
|
||||
necessity: SCMap<SCStudyModuleNecessity>;
|
||||
|
||||
/**
|
||||
* Translated fields of a study module
|
||||
*/
|
||||
translations?: SCTranslations<SCStudyModuleTranslatableProperties>;
|
||||
|
||||
/**
|
||||
* Type of the study module
|
||||
*/
|
||||
type: SCThingType.StudyModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* A study module
|
||||
*
|
||||
* @validatable
|
||||
*/
|
||||
export interface SCStudyModule extends SCStudyModuleWithoutReferences {
|
||||
/**
|
||||
* Academic events that make up a study module
|
||||
*/
|
||||
academicEvents: SCAcademicEventWithoutReferences[];
|
||||
|
||||
/**
|
||||
* The faculty that manages and curates the study module
|
||||
*/
|
||||
faculty: SCOrganizationWithoutReferences;
|
||||
|
||||
/**
|
||||
* Study modules needed for each others fulfillment
|
||||
*/
|
||||
partnerModules?: SCStudyModuleWithoutReferences[];
|
||||
|
||||
/**
|
||||
* Study modules required beforehand
|
||||
*/
|
||||
requiredModules?: SCStudyModuleWithoutReferences[];
|
||||
|
||||
/**
|
||||
* The secretary that administers requests and
|
||||
* questions concerning the study module by eg. students
|
||||
*/
|
||||
secretary: SCOrganizationWithoutReferences | SCPersonWithoutReferences;
|
||||
}
|
||||
|
||||
export interface SCStudyModuleTranslatableProperties
|
||||
extends SCThingThatCanBeOfferedTranslatableProperties {
|
||||
/**
|
||||
* Translations of the majors that this study module is meant for
|
||||
*/
|
||||
majors?: string[];
|
||||
|
||||
/**
|
||||
* Translations of the modules necessity for each given major (of the major property)
|
||||
*/
|
||||
necessity: SCMap<SCStudyModuleNecessity>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a modules necessity (in a major) as it may be required, optional or
|
||||
* is in a pool of n optional modules were m out of them have to be taken/completed.
|
||||
* Hence the elective option.
|
||||
*/
|
||||
export enum SCStudyModuleNecessity {
|
||||
Required = 'required',
|
||||
Elective = 'elective',
|
||||
Optional = 'optional',
|
||||
}
|
||||
|
||||
/**
|
||||
* Study module meta data
|
||||
*/
|
||||
export class SCStudyModuleMeta extends SCThingMeta implements SCMetaTranslations<SCStudyModule> {
|
||||
/**
|
||||
* Translations of fields
|
||||
*/
|
||||
fieldTranslations = {
|
||||
de: {
|
||||
... SCThingMeta.getInstance().fieldTranslations.de,
|
||||
academicEvents: 'Veranstaltungen',
|
||||
ects: 'ECTS-Punkte',
|
||||
faculty: 'Fachbereich',
|
||||
language: 'Unterrichtssprache',
|
||||
majors: 'Fachrichtungen',
|
||||
necessity: 'Erforderlichkeit',
|
||||
partnerModules: 'Partnermodule',
|
||||
requiredModules: 'Benötigte Module',
|
||||
secretary: 'Sekretariat',
|
||||
},
|
||||
en: {
|
||||
... SCThingMeta.getInstance().fieldTranslations.en,
|
||||
academicEvents: 'academic events',
|
||||
ects: 'ECTS points',
|
||||
faculty: 'faculty',
|
||||
language: 'teaching language',
|
||||
majors: 'majors',
|
||||
necessity: 'necessity',
|
||||
partnerModules: 'partner modules',
|
||||
requiredModules: 'required modules',
|
||||
secretary: 'secretary',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Translations of values of fields
|
||||
*/
|
||||
fieldValueTranslations = {
|
||||
de: {
|
||||
... SCThingMeta.getInstance().fieldValueTranslations.de,
|
||||
necessity: {
|
||||
'elective' : 'Wahlfach',
|
||||
'optional' : 'optional',
|
||||
'required' : 'benötigt',
|
||||
},
|
||||
type: 'Studiengangmodul',
|
||||
},
|
||||
en: {
|
||||
... SCThingMeta.getInstance().fieldValueTranslations.en,
|
||||
type: SCThingType.StudyModule,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -24,7 +24,11 @@ import {SCThing, SCThingType} from '../Thing';
|
||||
* @param {any} something Something to check
|
||||
*/
|
||||
export function isThing(something: any): something is SCThing {
|
||||
return (something.type && something.type in SCThingType);
|
||||
return (
|
||||
typeof something === 'object'
|
||||
&& typeof something.type === 'string'
|
||||
&& Object.values(SCThingType).indexOf(something.type) >= 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,11 +72,10 @@ export function isSearchResponse(something: any): something is SCSearchResponse
|
||||
/**
|
||||
* Type guard to check if something is a multi search response
|
||||
*
|
||||
*
|
||||
* @param something Something to check
|
||||
*/
|
||||
export function isMultiSearchResponse(something: any): something is SCMultiSearchResponse {
|
||||
return Object.keys(something).reduce((previousOnesAreSearchResponses, key) => {
|
||||
return previousOnesAreSearchResponses && isSearchResponse(something[key]);
|
||||
}, true);
|
||||
}, true as boolean);
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
|
||||
/**
|
||||
* Capsulation for a map with a string as key with values of type `T`
|
||||
*
|
||||
*
|
||||
* !!! BEWARE !!!
|
||||
* Can't be refactored to a `Map<K, V>`, because it can't be serialized via JSON.stringify(map)
|
||||
*
|
||||
*
|
||||
* @typeparam T Can be any type.
|
||||
*/
|
||||
export interface SCMap<T> {
|
||||
@@ -27,3 +27,20 @@ export interface SCMap<T> {
|
||||
*/
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricted map with keys, limited to values of `U`, and corresponding values of type `T`
|
||||
*
|
||||
* !!! BEWARE !!!
|
||||
* Can't be refactored to a `Map<K, V>`, because it can't be serialized via JSON.stringify(map)
|
||||
* Also note, that this is a type not an interface
|
||||
*
|
||||
* @typeparam U Must be a type the `in` operator can be applied to and contains only strings or numbers
|
||||
* @typeparam T Can be any type
|
||||
*/
|
||||
export type SCRestrictedMap<U extends string | number, T> = {
|
||||
/**
|
||||
* One value for each key
|
||||
*/
|
||||
[key in U]: T
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import {SCThingType} from '../../Thing';
|
||||
import {SCSearchSortType} from '../sorts/Abstract';
|
||||
import {SCUuid} from '../UUID';
|
||||
import {SCMap} from './../Map';
|
||||
import {SCMap, SCRestrictedMap} from './../Map';
|
||||
import {SCMonitoringConfiguration} from './Monitoring';
|
||||
|
||||
/**
|
||||
@@ -72,7 +72,7 @@ export interface SCBackendConfigurationSortableField {
|
||||
|
||||
/**
|
||||
* A list of SC types on which this field exists
|
||||
*
|
||||
*
|
||||
* If no type is given it is assumed it exists on every type
|
||||
*/
|
||||
onlyOnTypes?: SCThingType[];
|
||||
@@ -84,10 +84,27 @@ export interface SCBackendConfigurationSortableField {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible context names to be used by the search request
|
||||
*/
|
||||
export type SCSearchContext =
|
||||
| 'default'
|
||||
| 'dining'
|
||||
| 'place';
|
||||
|
||||
/**
|
||||
* A boosting configuration for one context
|
||||
*/
|
||||
export type SCBackendConfigurationSearchBoostingContext =
|
||||
SCRestrictedMap<
|
||||
SCSearchContext,
|
||||
SCBackendConfigurationSearchBoostingType[]
|
||||
>;
|
||||
|
||||
/**
|
||||
* A boosting configuration for one SCType
|
||||
*/
|
||||
export interface SCBackendConfigurationSearchBoosting {
|
||||
export interface SCBackendConfigurationSearchBoostingType {
|
||||
|
||||
/**
|
||||
* The factor of which the scores matching this type should be multiplied by
|
||||
@@ -98,7 +115,7 @@ export interface SCBackendConfigurationSearchBoosting {
|
||||
* Outer-Map:
|
||||
* Fields of this type that should be boosted if they match a given value
|
||||
* For nest fields you can use the `.` as a separator. For example `academicTerms.acronym`
|
||||
*
|
||||
*
|
||||
* Inner-map:
|
||||
* Value of the field that should be boosted by the given number
|
||||
* For example `"SS 2019": 2`
|
||||
@@ -143,7 +160,7 @@ export interface SCBackendInternalConfiguration {
|
||||
* The resulting scores of matching objects can be boosted (multiplied by a number) to change the order in the
|
||||
* set of results
|
||||
*/
|
||||
boostings: SCBackendConfigurationSearchBoosting[];
|
||||
boostings: SCBackendConfigurationSearchBoostingContext;
|
||||
|
||||
/**
|
||||
* Configuration of the database
|
||||
|
||||
57
test/Guards.spec.ts
Normal file
57
test/Guards.spec.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2018, 2019 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 {expect} from 'chai';
|
||||
import {slow, suite, test, timeout} from 'mocha-typescript';
|
||||
import {SCThingOriginType, SCThingType} from '../src/core/Thing';
|
||||
import {SCDish} from '../src/core/things/Dish';
|
||||
import {isThing} from '../src/core/types/Guards';
|
||||
|
||||
@suite(timeout(10000), slow(5000))
|
||||
export class GuardsSpec {
|
||||
@test
|
||||
public isThing() {
|
||||
const notADish = {
|
||||
categories: [
|
||||
'appetizer',
|
||||
],
|
||||
name: 'foo',
|
||||
origin: {
|
||||
created: '',
|
||||
type: SCThingOriginType.User,
|
||||
},
|
||||
type: 'foobar',
|
||||
uid: 'bar',
|
||||
};
|
||||
|
||||
const dish: SCDish = {
|
||||
categories: [
|
||||
'appetizer',
|
||||
],
|
||||
name: 'foo',
|
||||
origin: {
|
||||
created: '',
|
||||
type: SCThingOriginType.User,
|
||||
},
|
||||
type: SCThingType.Dish,
|
||||
uid: 'bar',
|
||||
};
|
||||
|
||||
expect(isThing('foo')).to.be.equal(false);
|
||||
|
||||
expect(isThing(notADish)).to.be.equal(false);
|
||||
|
||||
expect(isThing(dish)).to.be.equal(true);
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,12 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import clone = require('fast-clone');
|
||||
import {slow, suite, test, timeout} from 'mocha-typescript';
|
||||
|
||||
import {SCThingOriginType, SCThingType} from '../src/core/Thing';
|
||||
import {SCBuildingWithoutReferences} from '../src/core/things/Building';
|
||||
import {SCDish, SCDishMeta} from '../src/core/things/Dish';
|
||||
import {SCPerson} from '../src/core/things/Person';
|
||||
import {SCThingTranslator} from '../src/core/Translator';
|
||||
|
||||
const building: SCBuildingWithoutReferences = {
|
||||
@@ -96,29 +97,15 @@ const dish: SCDish = {
|
||||
uid: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
};
|
||||
|
||||
const person: SCPerson = {
|
||||
familyName: 'base-familyName-name',
|
||||
givenName: 'base-givenName-name',
|
||||
homeLocations: [building, building, building],
|
||||
name : 'base-person-name',
|
||||
origin: {
|
||||
indexed: '1970',
|
||||
name: 'ding',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
type: SCThingType.Person,
|
||||
uid: '1234',
|
||||
};
|
||||
|
||||
const translator = new SCThingTranslator('de', 'en');
|
||||
const translator = new SCThingTranslator('de');
|
||||
// tslint:disable-next-line:no-eval
|
||||
const languageNonExistant = eval("'jp'");
|
||||
// this will simulate a translator always utilizing the base language translations
|
||||
const translatorWithFallback = new SCThingTranslator(languageNonExistant);
|
||||
|
||||
// tslint:disable:member-ordering TranslationSpec
|
||||
// tslint:disable:member-ordering TranslationSpecInplace
|
||||
@suite(timeout(10000), slow(5000))
|
||||
export class TranslationSpec {
|
||||
export class TranslationSpecInplace {
|
||||
|
||||
@test
|
||||
public directStringLiteralType() {
|
||||
@@ -231,134 +218,24 @@ export class TranslationSpec {
|
||||
expect(translator.translate(dish).offers[0].inPlace.categories[1234]('printer')).to.equal('printer');
|
||||
expect(translator.translate(dish).offers[0].inPlace.categories[1]('printer')).to.not.equal('printer');
|
||||
}
|
||||
}
|
||||
|
||||
// tslint:disable:member-ordering TranslationSpecByString
|
||||
@suite(timeout(10000), slow(5000))
|
||||
export class TranslationSpecByString {
|
||||
|
||||
@test
|
||||
public directStringLiteralType() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'type')).to.equal('Essen');
|
||||
public changingTranslatorLanguageFlushesItsLRUCache() {
|
||||
const translatorDE = new SCThingTranslator('de');
|
||||
expect(translatorDE.translate(dish).name()).to.equal('de-dish-name');
|
||||
translatorDE.language = 'en';
|
||||
expect(translatorDE.translate(dish).name()).to.equal('base-dish-name');
|
||||
}
|
||||
|
||||
@test
|
||||
public directStringProperty() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'name')).to.equal('de-dish-name');
|
||||
}
|
||||
|
||||
@test
|
||||
public directArrayOfString() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'characteristics')).to.deep
|
||||
.equal([{name: 'de-characteristic0'}, {name: 'de-characteristic1'}]);
|
||||
}
|
||||
|
||||
@test
|
||||
public directArrayOfStringSubscript() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'characteristics[1]'))
|
||||
.to.deep.equal({name: 'de-characteristic1'});
|
||||
}
|
||||
|
||||
@test
|
||||
public directMetaArrayOfString() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'categories')).to.deep.equal(['Hauptgericht', 'Nachtisch']);
|
||||
}
|
||||
|
||||
@test
|
||||
public directMetaArrayOfStringSubscript() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'categories[1]')).to.equal('Nachtisch');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedStringLiteralType() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'offers[0].inPlace.type')).to.equal('Gebäude');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedStringProperty() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'offers[0].inPlace.name')).to.equal('de-space-name');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfString() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'offers[0].inPlace.categories'))
|
||||
.to.deep.equal(['Büro', 'Bildung']);
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfStringSubscript() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'offers[0].inPlace.categories[1]')).to.equal('Bildung');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedArrayOfStringSubscript() {
|
||||
expect(translator.getFieldValueTranslation(dish, 'offers[0].inPlace.floors[1]')).to.equal('de-floor1');
|
||||
}
|
||||
|
||||
@test
|
||||
public directStringLiteralTypeFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'type')).to.equal('dish');
|
||||
}
|
||||
|
||||
@test
|
||||
public directStringPropertyFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'name')).to.equal('base-dish-name');
|
||||
}
|
||||
|
||||
@test
|
||||
public directArrayOfStringSubscriptFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'characteristics[1]'))
|
||||
.to.deep.equal({name: 'base-characteristic1'});
|
||||
}
|
||||
|
||||
@test
|
||||
public directMetaArrayOfStringFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'categories'))
|
||||
.to.deep.equal(['main dish', 'dessert']);
|
||||
}
|
||||
|
||||
@test
|
||||
public directMetaArrayOfStringSubscriptFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'categories[1]')).to.equal('dessert');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedStringLiteralTypeFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'offers[0].inPlace.type')).to.equal('building');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedStringPropertyFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'offers[0].inPlace.name')).to.equal('base-space-name');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfStringFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'offers[0].inPlace.categories'))
|
||||
.to.deep.equal(['office', 'education']);
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfStringSubscriptFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'offers[0].inPlace.categories[1]'))
|
||||
.to.equal('education');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedArrayOfStringSubscriptFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'offers[0].inPlace.floors[1]'))
|
||||
.to.equal('base-floor1');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedArrayOfStringSubscriptUncommonFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(dish, 'offers[0].inPlace.floors.1')).to.equal('base-floor1');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedNestedMetaArrayOfStringSubscriptUncommonFallback() {
|
||||
expect(translatorWithFallback.getFieldValueTranslation(person, 'homeLocations.1.categories.1'))
|
||||
.to.equal('education');
|
||||
public forceTranslatorLRUCacheToOverflow() {
|
||||
const translatorDE = new SCThingTranslator('de');
|
||||
// Make sure to add more elements to the translator cache than the maximum cache capacity. See Translator.ts
|
||||
for (let i = 0; i < 201; i++) {
|
||||
const anotherDish = Object.assign({}, dish);
|
||||
anotherDish.uid = String(i);
|
||||
expect(translatorDE.translate(anotherDish).name()).to.equal('de-dish-name');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +253,7 @@ export class MetaTranslationSpec {
|
||||
|
||||
@test
|
||||
public thingWithoutMetaClass() {
|
||||
const dishCopy = Object.assign({}, dish);
|
||||
const dishCopy = clone(dish);
|
||||
const typeNonExistant = eval("(x) => x + 'typeNonExistant';");
|
||||
// this will assign a non existant SCThingType to dishCopy
|
||||
dishCopy.type = typeNonExistant();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"instance": {
|
||||
"type": "academic event",
|
||||
"description": "Fortsetzung der Algebra I: Galoistheorie mit Anwendungen, ausgewählte Spezialthemen.",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "681a59a1-23c2-5d78-861a-8c86a3abf2b9",
|
||||
"name": "Algebra II",
|
||||
"categories": [
|
||||
"lecture"
|
||||
@@ -31,7 +31,7 @@
|
||||
"performers": [
|
||||
{
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "7f8ce700-2679-51a5-86b5-3dfba85a33ff",
|
||||
"givenName": "Peter",
|
||||
"familyName": "Bürgisser",
|
||||
"gender": "male",
|
||||
@@ -59,7 +59,7 @@
|
||||
"maintainer": {
|
||||
"type": "organization",
|
||||
"name": "tubIT",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "25f76840-db89-5da2-a8a2-75992f637613",
|
||||
"origin": {
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
"name": "Dummy",
|
||||
@@ -70,7 +70,7 @@
|
||||
"originalId": "foo bar",
|
||||
"responsibleEntity": {
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "7f8ce700-2679-51a5-86b5-3dfba85a33ff",
|
||||
"givenName": "Peter",
|
||||
"familyName": "Bürgisser",
|
||||
"gender": "male",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"instance": {
|
||||
"type": "academic event",
|
||||
"description": "Grundlagen, algebraische Grundbegriffe, Vektorräume, lineare Abbildungen und Gleichungen, Determinanten",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "b17eb963-42b5-5861-adce-2b7b2607ef0a",
|
||||
"name": "Lineare Algebra I für Mathematiker",
|
||||
"categories": [
|
||||
"lecture"
|
||||
@@ -31,7 +31,7 @@
|
||||
"performers": [
|
||||
{
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "fc8b10cf-10c0-5b92-b16e-92ff734676da",
|
||||
"givenName": "Jörg",
|
||||
"familyName": "Liesen",
|
||||
"gender": "male",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "academic event",
|
||||
"description": "Die Übung hat 2 SWS und wird auf 2 Gruppen verteilt.",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "7e2b64b0-925d-5f63-b464-a6e3e9492411",
|
||||
"name": "Algebra II",
|
||||
"categories": [
|
||||
"tutorial"
|
||||
@@ -31,7 +31,7 @@
|
||||
"performers": [
|
||||
{
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "97be73c0-5319-579a-a393-c4eeeacae58b",
|
||||
"givenName": "Paul",
|
||||
"familyName": "Breiding",
|
||||
"gender": "male",
|
||||
@@ -44,7 +44,7 @@
|
||||
},
|
||||
{
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "0db9b55a-4c27-5faf-9bf0-4b564be45a08",
|
||||
"givenName": "Pierre",
|
||||
"familyName": "Lairez",
|
||||
"gender": "male",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"instance": {
|
||||
"uid": "8d8bd89c-8429-5f81-b754-15a5be55e593",
|
||||
"type": "article",
|
||||
"categories": [
|
||||
"unipedia"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"instance": {
|
||||
"uid": "4f772b29-0b28-53a4-a8b9-206d9b425962",
|
||||
"type": "article",
|
||||
"categories": [
|
||||
"unipedia"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "book",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "a0520263-29ae-5357-a3ce-ba1902d121e0",
|
||||
"name": "Kundenorientierung durch Quality Function Deployment: Systematisches Entwickeln von Produkten und Dienstleistungen",
|
||||
"authors": [
|
||||
{
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "10dfe386-71b4-554a-beb1-2d38561e42f8",
|
||||
"name": "Jutta Saatweber",
|
||||
"givenName": "Jutta",
|
||||
"familyName": "Saatweber",
|
||||
@@ -22,7 +22,7 @@
|
||||
"publishers": [
|
||||
{
|
||||
"type": "organization",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "28df2bb9-c854-5898-b9d5-1abbd3524804",
|
||||
"name": "Symposion Publishing",
|
||||
"origin": {
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "book",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "db47f7f4-7699-5a37-afcc-24beaa998d36",
|
||||
"name": "Minimal Book",
|
||||
"authors": [
|
||||
{
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "10dfe386-71b4-554a-beb1-2d38561e42f8",
|
||||
"name": "Jutta Saatweber",
|
||||
"givenName": "Jutta",
|
||||
"familyName": "Saatweber",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"geo": {
|
||||
"point": {
|
||||
"type": "Point",
|
||||
@@ -150,7 +150,7 @@
|
||||
"alternateNames": [
|
||||
"MA"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "edfaba58-254f-5da0-82d6-3b46a76c48ce",
|
||||
"categories": [
|
||||
"education"
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "64bb29ed-21e5-50c7-9d7c-1dc4741001b9",
|
||||
"instance": {
|
||||
"uid": "c8dc1f7f-9e3e-5b1f-8c38-084f46413b87",
|
||||
"type": "catalog",
|
||||
"level": 1,
|
||||
"categories": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "5a1f4f51-2498-5af1-91cb-c939673cc69c",
|
||||
"instance": {
|
||||
"uid": "5a8bc725-8658-528f-b515-5f7cd6987169",
|
||||
"type": "catalog",
|
||||
"level": 3,
|
||||
"description": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"academicDegree": "bachelor",
|
||||
"academicDegreewithField": "Bachelor of Arts",
|
||||
"academicDegreewithFieldShort": "B.A.",
|
||||
@@ -12,7 +12,7 @@
|
||||
"type": "remote"
|
||||
},
|
||||
"type": "organization",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140"
|
||||
"uid": "b0f878fd-8fda-53b8-b065-a8d854c3d0d2"
|
||||
},
|
||||
"mainLanguage": {
|
||||
"code": "de",
|
||||
@@ -34,11 +34,11 @@
|
||||
"type": "remote"
|
||||
},
|
||||
"type": "organization",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140"
|
||||
"uid": "b0f878fd-8fda-53b8-b065-a8d854c3d0d2"
|
||||
},
|
||||
"timeMode": "parttime",
|
||||
"type": "course of studies",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140"
|
||||
"uid": "4c6f0a18-343d-5175-9fb1-62d28545c2aa"
|
||||
},
|
||||
"schema": "SCCourseOfStudies"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "date series",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "1b421872-1b4c-579b-ba03-688f943d59ad",
|
||||
"name": "Einführung in die Wirtschaftspolitik",
|
||||
"duration": "PT2H",
|
||||
"inPlace": {
|
||||
@@ -10,7 +10,7 @@
|
||||
"categories": [
|
||||
"education"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "5a4bbced-8e1f-5f29-a1d1-336e455ce7f9",
|
||||
"name": "H 0105",
|
||||
"geo": {
|
||||
"point": {
|
||||
@@ -33,7 +33,7 @@
|
||||
],
|
||||
"event": {
|
||||
"type": "academic event",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "dbb4e5e1-0789-59c1-9970-877430af56b3",
|
||||
"name": "Einführung in die Wirtschaftspolitik",
|
||||
"categories": [
|
||||
"written exam"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "date series",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "4ce41895-4b54-52db-b86f-7e6920b975c8",
|
||||
"name": "Distributed Algorithms",
|
||||
"duration": "PT4H",
|
||||
"inPlace": {
|
||||
@@ -19,7 +19,7 @@
|
||||
"categories": [
|
||||
"education"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "b535c86a-777b-54c3-b89a-cad528d0580f",
|
||||
"name": "EMH 225",
|
||||
"floor": "2",
|
||||
"origin": {
|
||||
@@ -34,7 +34,7 @@
|
||||
],
|
||||
"event": {
|
||||
"type": "academic event",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "e6fb74d4-c6d9-59bb-930f-e47eb6e39432",
|
||||
"name": "Distributed Algorithms",
|
||||
"categories": [
|
||||
"written exam"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "date series",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "e6462830-187a-50b1-bdb4-8f39e49a88b8",
|
||||
"name": "Dance course for beginners",
|
||||
"duration": "PT8H",
|
||||
"inPlace": {
|
||||
@@ -19,7 +19,7 @@
|
||||
"categories": [
|
||||
"student union"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "b535c86a-777b-54c3-b89a-cad528d0580f",
|
||||
"name": "EMH 225",
|
||||
"floor": "2",
|
||||
"origin": {
|
||||
@@ -34,7 +34,7 @@
|
||||
],
|
||||
"event": {
|
||||
"type": "academic event",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "4f86e8bb-ce73-520b-bfd9-e1ba9f754391",
|
||||
"name": "Dance course for beginners",
|
||||
"categories": [
|
||||
"special"
|
||||
@@ -50,7 +50,7 @@
|
||||
"name": "Dummy",
|
||||
"type": "remote"
|
||||
},
|
||||
"offers": [
|
||||
"offers": [
|
||||
{
|
||||
"availability": "in stock",
|
||||
"availabilityStarts": "2017-01-30T00:00:00.000Z",
|
||||
@@ -66,7 +66,7 @@
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
"name": "Dummy",
|
||||
"type": "remote"
|
||||
},
|
||||
},
|
||||
"type": "organization",
|
||||
"uid": "3b9b3df6-3a7a-58cc-922f-c7335c002634"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"instance": {
|
||||
"uid": "a5acde0d-18c4-5511-9f86-aabf2a530f91",
|
||||
"dateCreated": "2017-02-07T09:26:35.957Z",
|
||||
"name": "changed_testuid",
|
||||
"changes": [
|
||||
@@ -14,7 +14,7 @@
|
||||
"action": "changed",
|
||||
"type": "diff",
|
||||
"object": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "072db1e5-e479-5040-88e0-4a98d731e443",
|
||||
"name": "Name One",
|
||||
"type": "message",
|
||||
"message": "Message",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"instance": {
|
||||
"uid": "f71cc2c8-fef2-59ee-af0a-511cc75e7471",
|
||||
"dateCreated": "2017-03-07T09:26:35.957Z",
|
||||
"name": "changed_testuid",
|
||||
"changes": [
|
||||
@@ -14,7 +14,7 @@
|
||||
"action": "changed",
|
||||
"type": "diff",
|
||||
"object": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "072db1e5-e479-5040-88e0-4a98d731e443",
|
||||
"name": "Name One",
|
||||
"type": "message",
|
||||
"message": "Message",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "dish",
|
||||
"name": "Pizza mit Geflügelsalami und Champignons",
|
||||
"categories": [
|
||||
@@ -33,7 +33,7 @@
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
"name": "Dummy",
|
||||
"type": "remote"
|
||||
},
|
||||
},
|
||||
"type": "organization",
|
||||
"uid": "3b9b3df6-3a7a-58cc-922f-c7335c002634"
|
||||
},
|
||||
@@ -56,7 +56,7 @@
|
||||
"alternateNames": [
|
||||
"MensaHardenberg"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "72fbc8a3-ebd1-58f9-9526-ad65cba2e402",
|
||||
"address": {
|
||||
"addressCountry": "Germany",
|
||||
"addressLocality": "Berlin",
|
||||
@@ -72,7 +72,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "c9f32915-8ed5-5960-b850-3f7375a89922",
|
||||
"origin": {
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
"name": "Dummy",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "dish",
|
||||
"name": "Sahne-Bärlauchsauce",
|
||||
"description": "Nudelauswahl",
|
||||
@@ -20,7 +20,7 @@
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
"name": "Dummy",
|
||||
"type": "remote"
|
||||
},
|
||||
},
|
||||
"type": "organization",
|
||||
"uid": "3b9b3df6-3a7a-58cc-922f-c7335c002634"
|
||||
},
|
||||
@@ -46,7 +46,7 @@
|
||||
"alternateNames": [
|
||||
"MensaHardenberg"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "072db1e5-e479-5040-88e0-4a98d731e443",
|
||||
"address": {
|
||||
"addressCountry": "Germany",
|
||||
"addressLocality": "Berlin",
|
||||
@@ -75,7 +75,7 @@
|
||||
"Weizen",
|
||||
"Milch(Laktose; Milcheiweiß)"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "3222631f-82b3-5faf-a8e8-9c10719cc95b",
|
||||
"origin": {
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
"name": "Dummy",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"additives": [
|
||||
"1 = mit Farbstoff",
|
||||
"2 = konserviert",
|
||||
@@ -51,7 +51,7 @@
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
"name": "Dummy",
|
||||
"type": "remote"
|
||||
},
|
||||
},
|
||||
"type": "organization",
|
||||
"uid": "3b9b3df6-3a7a-58cc-922f-c7335c002634"
|
||||
}
|
||||
@@ -80,7 +80,7 @@
|
||||
"type": "dish",
|
||||
"uid": "db0caac1-062c-5333-9fcb-cfaf0ff7d799",
|
||||
"nutrition": {
|
||||
"calories": 106.00,
|
||||
"calories": 106,
|
||||
"fatContent": 5.4,
|
||||
"saturatedFatContent": 1.8,
|
||||
"carbohydrateContent": 6.8,
|
||||
@@ -113,7 +113,7 @@
|
||||
"type": "dish",
|
||||
"uid": "f702fd43-1551-53b2-b35a-b5916e1cf9a1",
|
||||
"nutrition": {
|
||||
"calories": 106.00,
|
||||
"calories": 106,
|
||||
"fatContent": 5.4,
|
||||
"saturatedFatContent": 1.8,
|
||||
"carbohydrateContent": 6.8,
|
||||
@@ -137,9 +137,9 @@
|
||||
}
|
||||
],
|
||||
"type": "dish",
|
||||
"uid": "3b9b3df6-3a7a-58cc-922f-c7335c002634",
|
||||
"uid": "1c99689c-c6ec-551f-8ad8-f13c5fa812c2",
|
||||
"nutrition": {
|
||||
"calories": 600.00,
|
||||
"calories": 600,
|
||||
"fatContent": 30.5,
|
||||
"saturatedFatContent": 9.9,
|
||||
"carbohydrateContent": 42.2,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "favorite",
|
||||
"name": "Favorite #1",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "3af3ccaa-f066-5eff-9a3d-a70567f3d70d",
|
||||
"data": {
|
||||
"type": "academic event",
|
||||
"description": "Grundlagen, algebraische Grundbegriffe, Vektorräume, lineare Abbildungen und Gleichungen, Determinanten",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "b17eb963-42b5-5861-adce-2b7b2607ef0a",
|
||||
"name": "Lineare Algebra I für Mathematiker",
|
||||
"categories": [
|
||||
"lecture"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"instance": {
|
||||
"uid": "0effdc13-d4af-5a63-a538-c4b2c080e253",
|
||||
"name": "MA E:0",
|
||||
"type": "floor",
|
||||
"inPlace": {
|
||||
@@ -157,7 +157,7 @@
|
||||
"alternateNames": [
|
||||
"MA"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "edfaba58-254f-5da0-82d6-3b46a76c48ce",
|
||||
"address": {
|
||||
"addressCountry": "Germany",
|
||||
"addressLocality": "Berlin",
|
||||
@@ -3386,7 +3386,7 @@
|
||||
"categories": [
|
||||
"education"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "593655b5-0fc9-59de-a82f-b8f5f908deef",
|
||||
"name": "MA 043",
|
||||
"floor": "0",
|
||||
"origin": {
|
||||
@@ -5534,7 +5534,7 @@
|
||||
"categories": [
|
||||
"learn"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "31b1ab4c-1803-51ed-8c66-59bfc97cd350",
|
||||
"name": "MA Foyer",
|
||||
"floor": "0",
|
||||
"origin": {
|
||||
@@ -6353,7 +6353,7 @@
|
||||
"categories": [
|
||||
"education"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "56ce0744-ae39-5209-b18f-d3a6edcb8f0a",
|
||||
"name": "MA 042",
|
||||
"floor": "0",
|
||||
"origin": {
|
||||
@@ -6468,7 +6468,7 @@
|
||||
"categories": [
|
||||
"education"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "96b7e555-1214-5ca8-8294-e8209ac04f5a",
|
||||
"name": "MA 041",
|
||||
"floor": "0",
|
||||
"origin": {
|
||||
@@ -6703,7 +6703,7 @@
|
||||
"categories": [
|
||||
"education"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "ed50a94d-eb06-5d07-8058-dfbdeb6c3a0b",
|
||||
"name": "MA 001",
|
||||
"floor": "0",
|
||||
"origin": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"instance": {
|
||||
"uid": "3c56f5c4-006f-580e-8aff-9a9315f3fd81",
|
||||
"name": "H_4",
|
||||
"type": "floor",
|
||||
"inPlace": {
|
||||
@@ -97,7 +97,7 @@
|
||||
"alternateNames": [
|
||||
"H"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "ebe95e80-f826-5a70-a844-436b561d5181",
|
||||
"address": {
|
||||
"addressCountry": "Germany",
|
||||
"addressLocality": "Berlin",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"instance": {
|
||||
"uid": "d6152601-0154-581a-8bb5-0d1643972a21",
|
||||
"name": "H_5",
|
||||
"type": "floor",
|
||||
"inPlace": {
|
||||
@@ -97,7 +97,7 @@
|
||||
"alternateNames": [
|
||||
"H"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "ebe95e80-f826-5a70-a844-436b561d5181",
|
||||
"address": {
|
||||
"addressCountry": "Germany",
|
||||
"addressLocality": "Berlin",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "message",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "4706ef24-b631-5c20-91d1-3c627decca5a",
|
||||
"image": "icon ion-android-hand stapps-color-red-dark",
|
||||
"name": "Lösung für das Problem des Zurücksetzens der StApps-App gefunden",
|
||||
"message": "Wie bereits berichtet, klagten User über das Löschen ihres Stundenplans beim Update von Version 0.8.0 auf 0.8.1. Wir haben eine Lösung für das Problem gefunden und testen diese ausführlich bis zum Ende dieser Woche. Wenn alles glatt verläuft, dann kommt am Wochenende die fehlerbereinige Version 0.8.2 heraus.\n\n*(25.Okt 2016)*",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
],
|
||||
"instance": {
|
||||
"type": "invalid-value-in-schema",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "cdb7059c-a1a2-5229-821d-434c345e2917",
|
||||
"image": "icon ion-android-hand stapps-color-red-dark",
|
||||
"name": "Lösung für das Problem des Zurücksetzens der StApps-App gefunden",
|
||||
"message": "Wie bereits berichtet, klagten User über das Löschen ihres Stundenplans beim Update von Version 0.8.0 auf 0.8.1. Wir haben eine Lösung für das Problem gefunden und testen diese ausführlich bis zum Ende dieser Woche. Wenn alles glatt verläuft, dann kommt am Wochenende die fehlerbereinige Version 0.8.2 heraus.\n\n*(25.Okt 2016)*",
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{
|
||||
"errorNames": ["additionalProperties"],
|
||||
"instance": {
|
||||
"errorNames": [
|
||||
"additionalProperties"
|
||||
],
|
||||
"instance": {
|
||||
"type": "message",
|
||||
"invalid-non-existing-key-in-schema": 1,
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "4706ef24-b631-5c20-91d1-3c627decca5a",
|
||||
"image": "icon ion-android-hand stapps-color-red-dark",
|
||||
"name": "Lösung für das Problem des Zurücksetzens der StApps-App gefunden",
|
||||
"message": "Wie bereits berichtet, klagten User über das Löschen ihres Stundenplans beim Update von Version 0.8.0 auf 0.8.1. Wir haben eine Lösung für das Problem gefunden und testen diese ausführlich bis zum Ende dieser Woche. Wenn alles glatt verläuft, dann kommt am Wochenende die fehlerbereinige Version 0.8.2 heraus.\n\n*(25.Okt 2016)*",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "organization",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "20e48393-0d2b-5bdc-9d92-5e0dc1e2860e",
|
||||
"name": "Technische Universität Berlin",
|
||||
"origin": {
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "97044080-fdf3-5ec0-8734-c412ac2dde03",
|
||||
"givenName": "Michael",
|
||||
"familyName": "Joswig",
|
||||
"gender": "male",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "person",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "eb516021-3b37-5358-baef-345a0e10da5b",
|
||||
"givenName": "Michael",
|
||||
"familyName": "Gradzielski",
|
||||
"gender": "male",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "person",
|
||||
"familyName": "Mustermann",
|
||||
"givenName": "Erika",
|
||||
@@ -14,7 +14,7 @@
|
||||
"Leitung, Projektkoordination - Abteilung Lehre und Qualitätssicherung"
|
||||
],
|
||||
"name": "Univ.-Prof'in Dr. Erika Mustermann",
|
||||
"uid": "b22306bf-cbf3-54df-91a1-c08d8fd42e13",
|
||||
"uid": "be34a419-e9e8-5de0-b998-dd1b19e7f451",
|
||||
"workLocations": [
|
||||
{
|
||||
"url": "http://www.fb03.uni-frankfurt.de/1234567",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "2e925b84-3c99-5df2-a289-62be7a4ae512",
|
||||
"instance": {
|
||||
"uid": "f5fe4d13-d56a-5770-b16e-78782841bf02",
|
||||
"name": "Validierer (UB)",
|
||||
"type": "point of interest",
|
||||
"categories": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "1cf75fa0-86dc-5704-8cb4-bd80cf02e640",
|
||||
"instance": {
|
||||
"uid": "5a5ca30a-1494-5707-9692-ff902e104c12",
|
||||
"name": "Drucker 1 (IG)",
|
||||
"type": "point of interest",
|
||||
"categories": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"geo": {
|
||||
"point": {
|
||||
"type": "Point",
|
||||
@@ -14,7 +14,7 @@
|
||||
"categories": [
|
||||
"cafe"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "b7206fb5-bd77-5572-928f-16aa70910f64",
|
||||
"alternateNames": [
|
||||
"MA Mathe Cafeteria"
|
||||
],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"geo": {
|
||||
"point": {
|
||||
"type": "Point",
|
||||
@@ -14,7 +14,7 @@
|
||||
"categories": [
|
||||
"library"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "6e5abbff-d995-507b-982b-e0d094da6606",
|
||||
"alternateNames": [
|
||||
"BIB"
|
||||
],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"geo": {
|
||||
"point": {
|
||||
"type": "Point",
|
||||
@@ -15,7 +15,7 @@
|
||||
"categories": [
|
||||
"learn"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "d33fa478-7e5d-5197-9f0e-091f7f8105df",
|
||||
"name": "MA Foyer",
|
||||
"inPlace": {
|
||||
"geo": {
|
||||
@@ -170,7 +170,7 @@
|
||||
"alternateNames": [
|
||||
"MA"
|
||||
],
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217140",
|
||||
"uid": "edfaba58-254f-5da0-82d6-3b46a76c48ce",
|
||||
"address": {
|
||||
"addressCountry": "Germany",
|
||||
"addressLocality": "Berlin",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "d7ce5623-ad47-5976-bdd3-7cf551729516",
|
||||
"instance": {
|
||||
"uid": "ea9db087-240b-5b10-a65b-9684d88a3e4e",
|
||||
"name": "Poolraum (HoF)",
|
||||
"type": "room",
|
||||
"categories": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"query": "*",
|
||||
"context": "default",
|
||||
"filter": {
|
||||
"arguments": {
|
||||
"filters": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "b621f5b5-dd5d-5730-9e2e-e4ba52011388",
|
||||
"instance": {
|
||||
"uid": "622b950b-a29c-593b-9059-aece622228a0",
|
||||
"type": "semester",
|
||||
"name": "Wintersemester 2017/2018",
|
||||
"acronym": "WS 2017/18",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "aacd5611-b5be-54ce-b39f-c52f7e9a631d",
|
||||
"instance": {
|
||||
"uid": "7cebbc3e-0a21-5371-ab0d-f7ba12f53dbd",
|
||||
"type": "semester",
|
||||
"name": "Sommersemester 2018",
|
||||
"acronym": "SS 2018",
|
||||
|
||||
@@ -5,15 +5,13 @@
|
||||
"privacy"
|
||||
],
|
||||
"description": "This is a Description",
|
||||
"input": {
|
||||
"defaultValue": "student",
|
||||
"inputType": "singleChoice",
|
||||
"values": [
|
||||
"student",
|
||||
"employee",
|
||||
"guest"
|
||||
]
|
||||
},
|
||||
"defaultValue": "student",
|
||||
"inputType": "single choice",
|
||||
"values": [
|
||||
"student",
|
||||
"employee",
|
||||
"guest"
|
||||
],
|
||||
"name": "group",
|
||||
"order": 0,
|
||||
"origin": {
|
||||
@@ -21,13 +19,8 @@
|
||||
"name": "Dummy",
|
||||
"type": "remote"
|
||||
},
|
||||
"translations": {
|
||||
"de": {
|
||||
"description": "Dies ist eine Beschreibung"
|
||||
}
|
||||
},
|
||||
"type": "setting",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217642"
|
||||
"uid": "c4ff2b08-be18-528e-9b09-cb8c1d18487b"
|
||||
},
|
||||
"schema": "SCSetting"
|
||||
}
|
||||
|
||||
@@ -5,20 +5,18 @@
|
||||
"privacy"
|
||||
],
|
||||
"description": "This is a Description",
|
||||
"input": {
|
||||
"defaultValue": [],
|
||||
"inputType": "multipleChoice",
|
||||
"values": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8
|
||||
]
|
||||
},
|
||||
"defaultValue": [],
|
||||
"inputType": "multiple choice",
|
||||
"values": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8
|
||||
],
|
||||
"name": "numbers",
|
||||
"order": 1,
|
||||
"origin": {
|
||||
@@ -26,18 +24,8 @@
|
||||
"name": "Dummy",
|
||||
"type": "remote"
|
||||
},
|
||||
"translations": {
|
||||
"de": {
|
||||
"description": "Dies ist eine Beschreibung",
|
||||
"name": "Nummern"
|
||||
},
|
||||
"en": {
|
||||
"description": "This is a Description",
|
||||
"name": "Numbers"
|
||||
}
|
||||
},
|
||||
"type": "setting",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217642"
|
||||
"uid": "9f0c362e-0b41-532f-9e8b-a0ac373fbede"
|
||||
},
|
||||
"schema": "SCSetting"
|
||||
}
|
||||
|
||||
47
test/resources/Setting.3.json
Normal file
47
test/resources/Setting.3.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"categories": [
|
||||
"profile"
|
||||
],
|
||||
"defaultValue": "en",
|
||||
"description": "The language this app is going to use.",
|
||||
"inputType": "single choice",
|
||||
"name": "language",
|
||||
"order": 0,
|
||||
"origin": {
|
||||
"indexed": "2018-09-11T12:30:00Z",
|
||||
"name": "Dummy",
|
||||
"type": "remote"
|
||||
},
|
||||
"translations": {
|
||||
"de": {
|
||||
"categories": ["Benutzer"],
|
||||
"description": "Die Sprache in der die App angezeigt wird.",
|
||||
"name": "Sprache",
|
||||
"values": [
|
||||
"English",
|
||||
"German"
|
||||
]
|
||||
},
|
||||
"en": {
|
||||
"categories": [
|
||||
"User"
|
||||
],
|
||||
"description": "The language this app is going to use.",
|
||||
"name": "Language",
|
||||
"values": [
|
||||
"english",
|
||||
"german"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "setting",
|
||||
"values": [
|
||||
"en",
|
||||
"de"
|
||||
],
|
||||
"uid": "184b717a-d020-46f5-995c-03023670cc62"
|
||||
},
|
||||
"schema": "SCSetting"
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "ticket",
|
||||
"name": "Ticket",
|
||||
"uid": "7257a1d7-47ac-4acc-a8cc-3f9ac6442e5d",
|
||||
"uid": "34fc6cd9-5bd1-5779-a75d-a25d01ad4dae",
|
||||
"currentTicketNumber": "250",
|
||||
"approxWaitingTime": "PT43S",
|
||||
"inPlace": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "7257a1d7-47ac-4acc-a8cc-3f9ac6442e5d",
|
||||
"instance": {
|
||||
"uid": "4f1c1810-1a9f-52cb-bfe9-65dcab5e889a",
|
||||
"type": "tour",
|
||||
"name": "Stundenplan erstellen",
|
||||
"description": "Veranstaltung suchen und zum Stundenplan hinzufügen",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"uid": "7257a1d7-47ac-4acc-a8cc-3f9ac6442e5d",
|
||||
"instance": {
|
||||
"uid": "665d834d-594a-5d72-be94-ff2892a6003c",
|
||||
"type": "tour",
|
||||
"name": "Favorisierte Essensorte",
|
||||
"description": "Essensorte favorisieren, um ihre Speisepläne als Widget auf der Startseite zu sehen",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "video",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217642",
|
||||
"uid": "e274cc82-f51c-566b-b8da-85763ff375e8",
|
||||
"url": "https://vimeo.com/1084537",
|
||||
"name": "Big Buck Bunny",
|
||||
"origin": {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"errorNames": [],
|
||||
"instance": {
|
||||
"instance": {
|
||||
"type": "video",
|
||||
"uid": "540862f3-ea30-5b8f-8678-56b4dc217642",
|
||||
"uid": "2def52c8-f901-5b30-96fc-ba570a038508",
|
||||
"url": "https://vimeo.com/1084537",
|
||||
"name": "Big Buck Bunny",
|
||||
"sources": [
|
||||
|
||||
Reference in New Issue
Block a user