diff --git a/src/app/template/web/service.go b/src/app/template/web/service.go index 75240524e1ef9f76dfa0ce0e0934743f58a8f489..a56ab6bb88de25fb8d2395a9b2eacee98a848c52 100644 --- a/src/app/template/web/service.go +++ b/src/app/template/web/service.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "github.com/google/uuid" + "github.com/org-harmony/harmony/src/app/eiffel" "github.com/org-harmony/harmony/src/app/template" "github.com/org-harmony/harmony/src/app/user" "github.com/org-harmony/harmony/src/core/event" @@ -12,6 +13,7 @@ import ( "github.com/org-harmony/harmony/src/core/trace" "github.com/org-harmony/harmony/src/core/validation" "github.com/org-harmony/harmony/src/core/web" + "os" ) var ( @@ -21,6 +23,8 @@ var ( ErrResourceNotFound = errors.New("resource not found") // ErrUserNotPermitted is returned when the user is not permitted to access the requested resource, e.g. a template set. ErrUserNotPermitted = errors.New("user not permitted") + // ErrDefaultTemplateDoesNotExist is returned when the default template does not exist. + ErrDefaultTemplateDoesNotExist = errors.New("default template does not exist") ) // templateFormData is the data passed to the template form. It contains the template and information about the @@ -126,6 +130,65 @@ func CopyTemplate(ctx context.Context, tmpl *template.Template, tmplSetID, usrID return newTmpl, nil } +func ImportDefaultParisTemplates(ctx context.Context, tmplSetRepo template.SetRepository, tmplRepo template.Repository, usrID uuid.UUID) error { + defaultAK, err := os.ReadFile("templates/default/paris/ak.json") + if err != nil { + return ErrDefaultTemplateDoesNotExist + } + defaultESFA, err := os.ReadFile("templates/default/paris/esfa.json") + if err != nil { + return ErrDefaultTemplateDoesNotExist + } + defaultESQUA, err := os.ReadFile("templates/default/paris/esqua.json") + if err != nil { + return ErrDefaultTemplateDoesNotExist + } + defaultGlossar, err := os.ReadFile("templates/default/paris/glossar.json") + if err != nil { + return ErrDefaultTemplateDoesNotExist + } + + tmplSet, err := tmplSetRepo.Create(ctx, &template.SetToCreate{ + Name: "PARIS", + Version: "0.6.2", + CreatedBy: usrID, + Description: "Default PARIS templates. Change description and templates as needed.", + }) + if err != nil { + return web.ErrInternal + } + + _, err = tmplRepo.Create(ctx, &template.ToCreate{ + TemplateSet: tmplSet.ID, + Type: eiffel.BasicTemplateType, + Config: string(defaultAK), + CreatedBy: usrID, + }) + + _, err = tmplRepo.Create(ctx, &template.ToCreate{ + TemplateSet: tmplSet.ID, + Type: eiffel.BasicTemplateType, + Config: string(defaultESFA), + CreatedBy: usrID, + }) + + _, err = tmplRepo.Create(ctx, &template.ToCreate{ + TemplateSet: tmplSet.ID, + Type: eiffel.BasicTemplateType, + Config: string(defaultESQUA), + CreatedBy: usrID, + }) + + _, err = tmplRepo.Create(ctx, &template.ToCreate{ + TemplateSet: tmplSet.ID, + Type: eiffel.BasicTemplateType, + Config: string(defaultGlossar), + CreatedBy: usrID, + }) + + return nil +} + // templateSetInlineDelete reads the template set id from the request 'id' parameter and deletes the template set. // Errors are reported to the IO as inline errors. Errors are returned as internal errors safe to show to the user. func templateSetInlineDelete(io web.IO, repo template.SetRepository) error { diff --git a/src/app/template/web/web.go b/src/app/template/web/web.go index f87914d2e37b61fe1561d16e16eddbb7f3a0ce37..abc7c41e071ae17a80b38b0f64bc397d02f9dd78 100644 --- a/src/app/template/web/web.go +++ b/src/app/template/web/web.go @@ -40,6 +40,8 @@ func RegisterController(appCtx *hctx.AppCtx, webCtx *web.Ctx) { router.Get("/template-set/edit/{id}", templateSetEditFormController(appCtx, webCtx).ServeHTTP) router.Put("/template-set/{id}", templateSetEditController(appCtx, webCtx).ServeHTTP) router.Delete("/template-set/{id}", templateSetDeleteController(appCtx, webCtx).ServeHTTP) + // TODO generalize this + router.Post("/template-set/import/default-paris", templateSetImportDefaultParisController(appCtx, webCtx).ServeHTTP) router.Get("/template-set/{id}/list", templateListController(appCtx, webCtx).ServeHTTP) router.Get("/template-set/{id}/new", templateNewController(appCtx, webCtx).ServeHTTP) @@ -392,3 +394,24 @@ func templateCopyController(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler { return io.Render(web.NewFormData(formData, []string{"template.copy.success"}), "template.copy.modal", "template/_modal-copy.go.html") }) } + +func templateSetImportDefaultParisController(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler { + templateSetRepository := util.UnwrapType[template.SetRepository](appCtx.Repository(template.SetRepositoryName)) + templateRepository := util.UnwrapType[template.Repository](appCtx.Repository(template.RepositoryName)) + + return web.NewController(appCtx, webCtx, func(io web.IO) error { + ctx := io.Context() + + err := ImportDefaultParisTemplates(ctx, templateSetRepository, templateRepository, user.MustCtxUser(ctx).ID) + if err != nil { + return io.InlineError(err) + } + + templateSets, err := templateSetRepository.FindByCreatedBy(ctx, user.MustCtxUser(ctx).ID) + if err != nil { + return io.InlineError(web.ErrInternal, err) + } + + return io.Render(templateSets, "template.set.list", "template/_list-set.go.html") + }) +} diff --git a/templates/default/paris/ak.json b/templates/default/paris/ak.json new file mode 100644 index 0000000000000000000000000000000000000000..ec595ed31e54c10235653519e9ac4c9e325d82ce --- /dev/null +++ b/templates/default/paris/ak.json @@ -0,0 +1,146 @@ +{ + "id": "ak", + "type": "ebt", + "name": "Abnahme-/Akzeptanzkriterien", + "version": "0.1.0", + "authors": [ + "Jens Heise", + "Oliver Linssen" + ], + "license": "MIT", + "description": "Abnahme-/Abnahmekriterium bedeutet in PARIS ein Merkmal, mit dessen Hilfe entschieden wird, ob eine Anforderung erfüllt ist. Abnahmekriterien werden – insbesondere zu Beginn der Anforderungsanalyse – häufig formfrei formuliert.", + "rules": { + "prae-bedingung": { + "name": "Prä-Bedingung", + "type": "equalsAny", + "value": [ + "Ausgangssituation:", + "Angenommen", + "Angenommen,", + "Gegeben", + "Gegeben," + ], + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "small" + }, + "prae-bedingung-kurz": { + "name": "Prä-Ausgangssituation", + "type": "equals", + "value": "Ausgangssituation:", + "size": "small" + }, + "bedingung": { + "name": "Bedingung", + "type": "placeholder", + "hint": "Welche Situation liegt vor?", + "explanation": "Beschreibung der Situation vor dem Ereignis. Beispiel: Angenommen, der Anwender X hat ein Meeting für den Anwender X für den 1.3.201x von 13:00 bis 15:00 angelegt.", + "size": "large", + "optional": true, + "ignoreMissingWhenOptional": true + }, + "prae-ereignis": { + "name": "Prä-Ereignis", + "type": "equalsAny", + "value": [ + "Ereignis:", + "Wenn", + "Prüfe" + ], + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "small" + }, + "prae-ereignis-kurz": { + "name": "Prä-Ereignis", + "type": "equals", + "value": "Ereignis:", + "size": "small" + }, + "ereignis": { + "name": "Ereignis", + "type": "placeholder", + "hint": "Was soll passieren?", + "explanation": "Beschreibung Ereignis(se) bzw. Aktion(en). Beispiel: Wenn ein anderer Anwender Y für den Anwender X ein zweites Meeting für den 1.3.201x von 13:00 bis 15:00 anlegen will,", + "size": "large", + "optional": true, + "ignoreMissingWhenOptional": true + }, + "prae-ergebnis": { + "name": "Prä-Ergebnis", + "type": "equalsAny", + "value": [ + "Ergebnis:", + "Dann", + "dann" + ], + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "small" + }, + "prae-ergebnis-kurz": { + "name": "Prä-Ergebnis", + "type": "equals", + "value": "Erwartetes Ergebnis:", + "size": "small" + }, + "ergebnis": { + "name": "Ergebnis", + "type": "placeholder", + "hint": "Welches Ergebnis wird erwartet?", + "explanation": "Beschreibung Situation nach Ergebnis(sen). Beispiel: dann wird kein zweites Meeting angelegt,", + "size": "large" + }, + "begruendung": { + "name": "Begründung", + "type": "placeholder", + "hint": "Warum ist es so?", + "explanation": "Beschreibung der Begründung für das Ergebnis. Beispiel: weil ein Anwender immer nur in einem Meeting gleichzeitig anwesend sein kann.", + "size": "large", + "optional": true, + "ignoreMissingWhenOptional": true + }, + "punkt": { + "name": "Punkt", + "type": "equals", + "value": ".", + "size": "small", + "extra": { + "before": "", + "after": "" + } + } + }, + "variants": { + "akzeptanzkriterium": { + "name": "Abnahme-/Akzeptanzkriterium", + "description": "Ein Abnahme-/Akzeptanzkriterium ist ein Merkmal, mit dessen Hilfe entschieden wird, ob eine Anforderung erfüllt ist. Abnahmekriterien werden – insbesondere zu Beginn der Anforderungsanalyse – häufig formfrei formuliert.", + "example": "Angenommen, der Anwender X hat ein Meeting für den Anwender X für den 1.3.201x von 13:00 bis 15:00 angelegt. Wenn ein anderer Anwender Y für den Anwender X ein zweites Meeting für den 1.3.201x von 13:00 bis 15:00 anlegen will, dann wird kein zweites Meeting angelegt, weil ein Anwender immer nur in einem Meeting gleichzeitig anwesend sein kann.", + "rules": [ + "prae-bedingung", + "bedingung", + "prae-ereignis", + "ereignis", + "prae-ergebnis", + "ergebnis", + "begruendung", + "punkt" + ] + }, + "akzeptankriterium-vereinfacht-vollstaendig": { + "name": "Abnahme-/Akzeptanzkriterium (vereinfacht, vollständig)", + "description": "Ein Abnahme-/Akzeptanzkriterium ist ein Merkmal, mit dessen Hilfe entschieden wird, ob eine Anforderung erfüllt ist. Abnahmekriterien werden – insbesondere zu Beginn der Anforderungsanalyse – häufig formfrei formuliert.", + "example": "Angenommen, der Anwender X hat ein Meeting für den Anwender X für den 1.3.201x von 13:00 bis 15:00 angelegt. Wenn ein anderer Anwender Y für den Anwender X ein zweites Meeting für den 1.3.201x von 13:00 bis 15:00 anlegen will, dann wird kein zweites Meeting angelegt, weil ein Anwender immer nur in einem Meeting gleichzeitig anwesend sein kann.", + "rules": [ + "prae-bedingung-kurz", + "bedingung", + "prae-ereignis-kurz", + "ereignis", + "prae-ergebnis-kurz", + "ergebnis", + "begruendung", + "punkt" + ] + } + } +} \ No newline at end of file diff --git a/templates/default/paris/esfa.json b/templates/default/paris/esfa.json new file mode 100644 index 0000000000000000000000000000000000000000..c7e0b7d9f18e08d8c794213d19692453d9d6c1e0 --- /dev/null +++ b/templates/default/paris/esfa.json @@ -0,0 +1,237 @@ +{ + "id": "esfa", + "type": "ebt", + "name": "Erweiterte Schablone für funktionale Anforderungen (ESFA)", + "version": "0.1.0", + "authors": [ + "Jens Heise", + "Oliver Linssen" + ], + "license": "MIT", + "description": "Die erweiterte Schablone für funktionale Anforderungen (ESFA) dient der präzsien Beschreibung verschiedener Arten von funktionalen Anforderungen.", + "rules": { + "bedingung": { + "name": "Bedingung", + "type": "placeholder", + "hint": "Unter welcher Bedingung wird etwas getan?", + "explanation": "Beispiel: Am letzten Tag des Monats", + "size": "full" + }, + "modalitaet": { + "name": "Modalität", + "type": "equalsAny", + "hint": "Mit welcher Verbindlichkeit wird es getan?", + "explanation": "Beispiel: muss", + "value": [ + "muss", + "soll", + "sollte", + "kann", + "wird" + ], + "size": "medium" + }, + "small-modalitaet": { + "name": "Modalität", + "type": "equalsAny", + "hint": "Mit welcher Verbindlichkeit wird es getan?", + "explanation": "Beispiel: muss", + "value": [ + "muss", + "soll", + "sollte", + "kann", + "wird" + ], + "size": "small" + }, + "system": { + "name": "System", + "type": "placeholder", + "hint": "Wer tut es?", + "explanation": "Beispiel: das System Libri", + "size": "medium" + }, + "benutzer": { + "name": "Benutzer", + "type": "placeholder", + "hint": "Für wen wird es getan?", + "explanation": "Beispiel: dem Administrator", + "size": "medium" + }, + "ermoeglichen": { + "name": "Ermöglichen", + "type": "equals", + "value": "ermöglichen,", + "size": "medium" + }, + "in-der-lage-sein": { + "name": "In der Lage sein", + "type": "equals", + "value": "in der Lage sein,", + "size": "small" + }, + "selbstaendig": { + "name": "Selbständig", + "type": "equals", + "value": "selbständig", + "size": "small" + }, + "objektbeschreibung": { + "name": "Objektbeschreibung", + "type": "placeholder", + "hint": "Woran / Womit wird es getan?", + "explanation": "Beispiel: eine Auswertung der Verbrauchsdaten", + "optional": true, + "size": "large" + }, + "prozessbeschreibung": { + "name": "Prozessbeschreibung", + "type": "placeholder", + "hint": "Was wird getan?", + "explanation": "Beispiel: zu erzeugen", + "size": "small" + }, + "begruendung": { + "name": "Begründung", + "type": "placeholder", + "hint": "Warum wird es getan?", + "explanation": "Beispiel: weil dieser manuell nach Auffälligkeiten suchen will", + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "large" + }, + "punkt": { + "name": "Punkt", + "type": "equals", + "value": ".", + "size": "small", + "extra": { + "before": "", + "after": "" + } + } + }, + "variants": { + "benutzeranforderung-mit-bedingung": { + "name": "Benutzeranforderung mit Bedingung", + "description": "Eine funktionale Benutzeranforderung mit Bedingung", + "example": "Am letzten Tag des Monats muss das System Libri dem Administrator ermöglichen, eine Auswertung der Verbrauchsdaten zu erzeugen, weil dieser manuell nach Auffälligkeiten suchen will.", + "rules": [ + "bedingung", + "modalitaet", + "system", + "benutzer", + "ermoeglichen", + "objektbeschreibung", + "prozessbeschreibung", + "begruendung", + "punkt" + ] + }, + "benutzeranforderung-ohne-bedingung": { + "name": "Benutzeranforderung ohne Bedingung", + "description": "Eine funktionale Benutzeranforderung ohne Bedingung", + "example": "Das System Libri muss dem Administrator ermöglichen, eine Auswertung der Verbrauchsdaten zu erzeugen, weil dieser manuell nach Auffälligkeiten suchen will.", + "rules": [ + "system", + "modalitaet", + "benutzer", + "ermoeglichen", + "objektbeschreibung", + "prozessbeschreibung", + "begruendung", + "punkt" + ] + }, + "inter-system-anforderung-mit-bedingung": { + "name": "Inter-System-Anforderung mit Bedingung", + "description": "Eine Inter-System-Anforderung mit Bedingung", + "example": "Nachdem das System Libri die Auswertung der Verbrauchsdaten erzeugt hat, muss das System Rep2Print dem System Libri ermöglichen, die Auswertung 0234 zu drucken.", + "rules": [ + "bedingung", + "modalitaet", + "system", + "system", + "ermoeglichen", + "objektbeschreibung", + "prozessbeschreibung", + "begruendung", + "punkt" + ] + }, + "inter-system-anforderung-ohne-bedingung": { + "name": "Inter-System-Anforderung ohne Bedingung", + "description": "Eine Inter-System-Anforderung ohne Bedingung", + "example": "Das System Kaffee4All muss einem verbundenen Smartphone ermöglichen, den Befehl, einen Kaffee zuzubereiten, auszuführen.", + "rules": [ + "system", + "modalitaet", + "system", + "ermoeglichen", + "objektbeschreibung", + "prozessbeschreibung", + "begruendung", + "punkt" + ] + }, + "schnittstellenanforderung-mit-bedingung": { + "name": "Schnittstellenanforderung mit Bedingung", + "description": "Eine Schnittstellenanforderung mit Bedingung", + "example": "Wenn ein Kaffee mit Milch angefordert wird, muss das System Kaffee-Vollautomat in der Lage sein, dem Milchbehälter Milch zu entnehmen.", + "rules": [ + "bedingung", + "small-modalitaet", + "system", + "in-der-lage-sein", + "objektbeschreibung", + "prozessbeschreibung", + "begruendung", + "punkt" + ] + }, + "schnittstellenanforderung-ohne-bedingung": { + "name": "Schnittstellenanforderung ohne Bedingung", + "description": "Eine Schnittstellenanforderung ohne Bedingung", + "example": "Am letzten Tag des Monats muss das System in der Lage sein, eine Auswertung der Verbrauchsdaten zu erzeugen.", + "rules": [ + "system", + "small-modalitaet", + "in-der-lage-sein", + "objektbeschreibung", + "prozessbeschreibung", + "begruendung", + "punkt" + ] + }, + "selbstaendige-aktivitaet-mit-bedingung": { + "name": "Selbständige Aktivität mit Bedingung", + "description": "Eine selbständige Aktivität mit Bedingung", + "example": "Am letzten Tag des Monats muss das System Libri selbständig eine Auswertung der Verbrauchsdaten erzeugen.", + "rules": [ + "bedingung", + "small-modalitaet", + "system", + "selbstaendig", + "objektbeschreibung", + "prozessbeschreibung", + "begruendung", + "punkt" + ] + }, + "selbstaendige-aktivitaet-ohne-bedingung": { + "name": "Selbständige Aktivität ohne Bedingung", + "description": "Eine selbständige Aktivität ohne Bedingung", + "example": "Das System Libri muss selbständig eine Auswertung der Verbrauchsdaten erzeugen.", + "rules": [ + "system", + "small-modalitaet", + "selbstaendig", + "objektbeschreibung", + "prozessbeschreibung", + "begruendung", + "punkt" + ] + } + } +} \ No newline at end of file diff --git a/templates/default/paris/esqua.json b/templates/default/paris/esqua.json new file mode 100644 index 0000000000000000000000000000000000000000..f7c1e96eeeea73366e53a904237d52ec5610898b --- /dev/null +++ b/templates/default/paris/esqua.json @@ -0,0 +1,197 @@ +{ + "id": "esqua", + "type": "ebt", + "name": "Erweiterte Schablone für Qualitätsanforderungen (ESQUA)", + "version": "0.1.0", + "authors": [ + "Jens Heise", + "Oliver Linssen" + ], + "license": "MIT", + "description": "Qualitätsanforderung bedeutet in PARIS eine Anforderung, die sich auf ein Qualitätsmerkmal bezieht. Qualitätsanforderungen bestehen immer aus einem Qualitätsmerkmal und 1-n Qualitätskriterien.", + "rules": { + "bedingung": { + "name": "Bedingung", + "type": "placeholder", + "hint": "Unter welcher Bedingung?", + "explanation": "Beispiel: Wenn der Dienstvertrag mit einem Betreiber neu ausgeschrieben wird,", + "size": "large" + }, + "modalitaet": { + "name": "Modalität", + "type": "equalsAny", + "hint": "Mit welcher Verbindlichkeit?", + "explanation": "Beispiel: muss", + "value": [ + "muss", + "soll", + "sollte", + "kann", + "wird" + ], + "size": "small" + }, + "modalitaet-medium": { + "name": "Modalität", + "type": "equalsAny", + "hint": "Mit welcher Verbindlichkeit?", + "explanation": "Beispiel: muss", + "value": [ + "muss", + "soll", + "sollte", + "kann", + "wird" + ], + "size": "medium" + }, + "was-oder-wer": { + "name": "System/Stakeholder", + "type": "placeholder", + "hint": "Muss was oder wer?", + "explanation": "Beispiel: der Kantine", + "size": "medium" + }, + "was-oder-wer-full": { + "name": "System/Stakeholder", + "type": "placeholder", + "hint": "Muss was oder wer?", + "explanation": "Beispiel: die Kantine", + "size": "full" + }, + "qualitaetsmerkmal-besitzen": { + "name": "Das Qualitätsmerkmal besitzen", + "type": "equals", + "value": "das Qualitätsmerkmal besitzen", + "size": "medium" + }, + "qualitaetsmerkmal-besitzen-medium": { + "name": "Das Qualitätsmerkmal besitzen", + "type": "equals", + "value": "das Qualitätsmerkmal besitzen", + "size": "medium" + }, + "qualitaetsmerkmal": { + "name": "Qualitätsmerkmal", + "type": "placeholder", + "hint": "Welches qualitative Merkmal besitzen?", + "explanation": "Beispiel: das Qualitätsmerkmal besitzen, leistungsfähig zu sein,", + "size": "full" + }, + "begruendung": { + "name": "Begründung", + "type": "placeholder", + "hint": "Warum?", + "explanation": "Beispiel: weil die Mitarbeiter in Ihren Pausen keine Wartezeiten tolerieren", + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "large" + }, + "punkt": { + "name": "Punkt", + "type": "equals", + "value": ".", + "size": "small", + "extra": { + "before": "", + "after": "" + } + }, + "prae-qualitaetsindikator": { + "name": "Prä-Qualitätsindikator", + "type": "equals", + "value": "Qualitätsindikator:", + "size": "small" + }, + "qualitaetsindikator": { + "name": "Qualitätsindikator", + "type": "placeholder", + "hint": "Was ist ein Indikator?", + "explanation": "Maß, welches zur Bewertung der Qualität verwendet wird. Beispiel: Qualitätsindikator: Zeit, die man an der Essensausgabe wartet.", + "size": "large" + }, + "prae-messverfahren": { + "name": "Prä-Messverfahren", + "type": "equals", + "value": "Messverfahren:", + "size": "small" + }, + "messverfahren": { + "name": "Messverfahren", + "type": "placeholder", + "hint": "Wie würde man messen?", + "explanation": "Art der Messung. Beispiel: Messverfahren: Zufällige Zeitmessung zwischen 12:00 und 13:30 an der Ausgabe für Hauptgerichte. Die Zeitmessung beginnt, wenn sich der Kunde an der Schlange der Hauptausgabe anstellt. Die Zeitmessung endet, wenn der Zahlvorgang an der Kasse abgeschlossen ist.", + "size": "large" + }, + "prae-masseinheit": { + "name": "Prä-Maßeinheit", + "type": "equals", + "value": "Maßeinheit:", + "size": "small" + }, + "masseinheit": { + "name": "Maßeinheit", + "type": "placeholder", + "hint": "Welche Maßeinheit?", + "explanation": "Maßeinheit, die im Messverfahren verwendet wird. Beispiel: Maßeinheit: Sekunden.", + "size": "large" + }, + "prae-ziel": { + "name": "Prä-Ziel", + "type": "equals", + "value": "Ziel:", + "size": "small" + }, + "ziel": { + "name": "Ziel", + "type": "placeholder", + "hint": "Was muss erreicht werden?", + "explanation": "Welche/n Wert/e der Qualitätsindikator erreichen muss. Beispiel: Ziel: Voll erfüllt: x <= 360. Nicht erfüllt: x > 360.", + "size": "large" + } + }, + "variants": { + "qualitaetsmerkmal-mit-bedingung": { + "name": "Qualitätsmerkmal mit Bedingung", + "description": "Qualitätsmerkmal mit Bedingung", + "example": "Wenn der Dienstvertrag mit einem Betreiber neu ausgeschrieben wird, muss die Kantine das Qualitätsmerkmal besitzen, leistungsfähig zu sein, weil die Mitarbeiter in Ihren Pausen keine Wartezeiten tolerieren.", + "rules": [ + "bedingung", + "modalitaet", + "was-oder-wer", + "qualitaetsmerkmal-besitzen", + "qualitaetsmerkmal", + "begruendung", + "punkt" + ] + }, + "qualitaetsmerkmal-ohne-bedingung": { + "name": "Qualitätsmerkmal ohne Bedingung", + "description": "Qualitätsmerkmal ohne Bedingung", + "example": "Die Kantine muss das Qualitätsmerkmal besitzen, leistungsfähig zu sein.", + "rules": [ + "was-oder-wer-full", + "modalitaet-medium", + "qualitaetsmerkmal-besitzen-medium", + "qualitaetsmerkmal", + "begruendung", + "punkt" + ] + }, + "qualitaetskriterium": { + "name": "Qualitätskriterium", + "description": "Qualitätskriterium", + "example": "Qualitätsindikator: Zeit, die man an der Essensausgabe wartet. Messverfahren: Zufällige Zeitmessung zwischen 12:00 und 13:30 an der Ausgabe für Hauptgerichte. Die Zeitmessung beginnt, wenn sich der Kunde an der Schlange der Hauptausgabe anstellt. Die Zeitmessung endet, wenn der Zahlvorgang an der Kasse abgeschlossen ist. Maßeinheit: Sekunden. Ziel: Voll erfüllt: x <= 360. Nicht erfüllt: x > 360.", + "rules": [ + "prae-qualitaetsindikator", + "qualitaetsindikator", + "prae-messverfahren", + "messverfahren", + "prae-masseinheit", + "masseinheit", + "prae-ziel", + "ziel" + ] + } + } +} \ No newline at end of file diff --git a/templates/default/paris/glossar.json b/templates/default/paris/glossar.json new file mode 100644 index 0000000000000000000000000000000000000000..3a56fe2a1cb6345130b1275509c3a290bf8fc17b --- /dev/null +++ b/templates/default/paris/glossar.json @@ -0,0 +1,157 @@ +{ + "id": "glossar", + "type": "ebt", + "name": "Glossareintrag", + "version": "0.1.0", + "authors": [ + "Jens Heise", + "Oliver Linssen" + ], + "license": "MIT", + "description": "Glossareintrag bedeutet in PARIS eine Definition, mit der ein Begriff, eine Abkürzung oder ein Verb für einen bestimmten Geltungsbereich erklärt wird.", + "rules": { + "definiendum": { + "name": "Definiendum", + "type": "placeholder", + "hint": "Welcher Begriff?", + "explanation": "Ein zu erklärender Begriff, eine Abkürzung oder ein Verb. Beispiel: Kunde", + "size": "medium" + }, + "definiendum-vereinfacht": { + "name": "Definiendum", + "type": "placeholder", + "hint": "Welcher Begriff?", + "explanation": "Ein zu erklärender Begriff, eine Abkürzung oder ein Verb. Beispiel: Kunde (Synonyme: Ausleiher, Besucher, Leser) (engl. Reader)", + "size": "large" + }, + "synonyme": { + "name": "Synonyme", + "type": "placeholder", + "hint": "Mit welchen Synonymen?", + "explanation": "Synonyme für den zu erklärenden Begriff. Beispiel: (Synonyme: Ausleiher, Besucher, Leser)", + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "medium" + }, + "uebersetzung": { + "name": "Übersetzung", + "type": "placeholder", + "hint": "Mit welchen Übersetzungen?", + "explanation": "Übersetzung des zu erklärenden Begriffs. Beispiel: (engl. Reader)", + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "medium" + }, + "bedeutet": { + "name": "Bedeutet", + "type": "equals", + "value": "bedeutet", + "size": "small" + }, + "prae-bereich": { + "name": "Prä-Bereich", + "type": "equalsAny", + "value": [ + "im", + "in", + "in der" + ], + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "small" + }, + "bereich": { + "name": "Bereich", + "type": "placeholder", + "hint": "Wird für welchen Bereich?", + "explanation": "Bezug, auf den sich der zu erklärende Begriff bezieht. Beispiel: im System Libri", + "size": "small" + }, + "bereich-vereinfacht": { + "name": "Bereich", + "type": "placeholder", + "hint": "Wird für welchen Bereich?", + "explanation": "Bezug, auf den sich der zu erklärende Begriff bezieht. Beispiel: im System Libri", + "size": "medium" + }, + "prae-definiens": { + "name": "Prä-Definiens", + "type": "equalsAny", + "value": [ + "die Abkürzung", + "den Prozess" + ], + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "small" + }, + "definiens": { + "name": "Definiens", + "type": "placeholder", + "hint": "Wie definiert?", + "explanation": "Erklärung des zu erklärenden Begriffs. Beispiel: eine natürliche Person,", + "size": "medium" + }, + "spezifikation-definiens": { + "name": "Spezifikation des Definiens", + "type": "placeholder", + "hint": "Was bedeutet das?", + "explanation": "Spezifikation des Definiens. Beispiel: die berechtigt ist, Medien auszuleihen,", + "optional": true, + "size": "full" + }, + "begruendung": { + "name": "Begründung", + "type": "placeholder", + "hint": "Warum ist es so festgelegt?", + "explanation": "Begründung für die Definition. Beispiel: weil juristische Personen nicht zur Ausleihe zugelassen sind", + "optional": true, + "ignoreMissingWhenOptional": true, + "size": "large" + }, + "punkt": { + "name": "Punkt", + "type": "equals", + "value": ".", + "size": "small", + "extra": { + "before": "", + "after": "" + } + } + }, + "variants": { + "glossareintrag": { + "name": "Glossareintrag", + "description": "Glossareintrag definiert einen Begriff, eine Abkürzung oder ein Verb für einen bestimmten Geltungsbereich.", + "example": "Kunde (Synonyme: Ausleiher, Besucher, Leser) (engl. Reader) bedeutet im System Libri eine natürliche Person, die berechtigt ist, Medien auszuleihen, weil juristische Personen nicht zur Ausleihe zugelassen sind.", + "rules": [ + "definiendum", + "synonyme", + "uebersetzung", + "bedeutet", + "prae-bereich", + "bereich", + "prae-definiens", + "definiens", + "spezifikation-definiens", + "begruendung", + "punkt" + ] + }, + "glossareintrag-vereinfacht": { + "name": "Glossareintrag vereinfacht", + "description": "Glossareintrag vereinfacht definiert einen Begriff, eine Abkürzung oder ein Verb für einen bestimmten Geltungsbereich.", + "example": "Kunde (Synonyme: Ausleiher, Besucher, Leser) (engl. Reader) bedeutet im System Libri eine natürliche Person, die berechtigt ist, Medien auszuleihen, weil juristische Personen nicht zur Ausleihe zugelassen sind.", + "rules": [ + "definiendum-vereinfacht", + "bedeutet", + "bereich-vereinfacht", + "definiens", + "spezifikation-definiens", + "begruendung", + "punkt" + ] + } + } +} \ No newline at end of file diff --git a/templates/template/_list-set.go.html b/templates/template/_list-set.go.html index f74a4e607f76f8f40c47b79087a805c5389029e5..4acba001af0f98803f414745b4593da39e553975 100644 --- a/templates/template/_list-set.go.html +++ b/templates/template/_list-set.go.html @@ -6,6 +6,7 @@ </div> <div class="col"> <a href="/template-set/new" hx-boost="true" hx-target="body" class="btn btn-secondary">{{ "template.set.new" | t }}</a> + <button hx-post="/template-set/import/default-paris" hx-target=".template-set-list" hx-swap="outerHTML" class="btn btn-secondary mt-1">{{ "template.set.import.paris" | t }}</button> </div> <div class="col"> <button hx-get="/template-set/list" hx-target="body" class="btn btn-secondary"> diff --git a/translations/de.json b/translations/de.json index 06a4cb33ebdca83bca2034fcea160e73853e37ee..e82b2b6df619f113d7526d75b525020507bf7983 100644 --- a/translations/de.json +++ b/translations/de.json @@ -54,6 +54,9 @@ "confirm": "Speichern", "cancel": "Abbrechen", "updated": "Der Schablonensatz wurde aktualisiert." + }, + "import": { + "paris": "PARIS importieren" } }, "title": "Schablone", @@ -94,7 +97,8 @@ "actions": "Aktionen", "edit": "Bearbeiten", "delete": "Löschen" - } + }, + "missing-default-template": "Es wurde eine Standard-Schablone angefragt, die im System nicht gefunden werden konnte. Wahrscheinlich fehlen die notwendigen Dateien. Bitte kontaktieren Sie den Administrator." }, "eiffel": { "parser": { diff --git a/translations/en.json b/translations/en.json index 39457bf3658ee7119a334fea78369ade5d072295..13a55368b2d2065cade779ae23fe41bd91062197 100644 --- a/translations/en.json +++ b/translations/en.json @@ -54,6 +54,9 @@ "confirm": "Save", "cancel": "Cancel", "updated": "The template set has been updated." + }, + "import": { + "paris": "Import PARIS" } }, "title": "Template", @@ -94,7 +97,8 @@ "actions": "Actions", "edit": "Edit", "delete": "Delete" - } + }, + "missing-default-template": "A default template was requested that could not be found in the system. Probably the necessary files are missing. Please contact the administrator." }, "eiffel": { "parser": {