generated from cms/tibi-docs
Initial commit
This commit is contained in:
commit
8a0467f821
1
.basic-auth-code
Normal file
1
.basic-auth-code
Normal file
@ -0,0 +1 @@
|
|||||||
|
code:$apr1$AeePIAei$E9E6E6jtFFtwmtGhIEG.Y/
|
2
.basic-auth-web
Normal file
2
.basic-auth-web
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
code:$apr1$AeePIAei$E9E6E6jtFFtwmtGhIEG.Y/
|
||||||
|
web:$apr1$/zc/TBtD$ZGr3RqPiULYMD0kJUup5E0
|
151
.drone.yml.bak
Normal file
151
.drone.yml.bak
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: default
|
||||||
|
|
||||||
|
steps:
|
||||||
|
##############################
|
||||||
|
# Build and deploy docs
|
||||||
|
##############################
|
||||||
|
- name: build docs
|
||||||
|
image: node:18
|
||||||
|
pull: if-not-exists
|
||||||
|
environment:
|
||||||
|
FORCE_COLOR: "true"
|
||||||
|
commands:
|
||||||
|
- cd docs
|
||||||
|
- yarn install
|
||||||
|
- yarn docpress:build
|
||||||
|
when:
|
||||||
|
branch: [master]
|
||||||
|
event: [push]
|
||||||
|
|
||||||
|
- name: deploy docs
|
||||||
|
image: instrumentisto/rsync-ssh
|
||||||
|
pull: if-not-exists
|
||||||
|
environment:
|
||||||
|
RSYNC_HOST: ftp1.webmakers.de
|
||||||
|
RSYNC_PORT: 22222
|
||||||
|
RSYNC_USER: webmakers_tibi_docs_rsync_master
|
||||||
|
RSYNC_PASS:
|
||||||
|
from_secret: rsync_master
|
||||||
|
commands:
|
||||||
|
- cd docs
|
||||||
|
- >
|
||||||
|
rsync -rlcgD --perms -i -u -v --stats --progress
|
||||||
|
--delete
|
||||||
|
-e "sshpass -p $${RSYNC_PASS} ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p $${RSYNC_PORT}"
|
||||||
|
_docpress/
|
||||||
|
$${RSYNC_USER}@$${RSYNC_HOST}:./
|
||||||
|
when:
|
||||||
|
branch: [master]
|
||||||
|
event: [push]
|
||||||
|
|
||||||
|
##############################
|
||||||
|
# Demo project
|
||||||
|
##############################
|
||||||
|
- name: yarn install
|
||||||
|
image: node:18
|
||||||
|
pull: if-not-exists
|
||||||
|
environment:
|
||||||
|
FORCE_COLOR: "true"
|
||||||
|
commands:
|
||||||
|
- yarn install
|
||||||
|
|
||||||
|
- name: modify config
|
||||||
|
image: alpine/git
|
||||||
|
commands:
|
||||||
|
- sed -i 's#\(sentryEnvironment.*\)".*"#\1"${DRONE_BRANCH}"#g' frontend/src/config.ts
|
||||||
|
- sed -i 's#//\( sentry\\.init.*\)#\1#g' frontend/src/config.ts
|
||||||
|
- export $(cat .env | xargs)
|
||||||
|
- echo "PROJECT_RELEASE=$${RELEASE_PROJECT_SLUG}.r`git rev-list HEAD --count`-`git describe --all --long | sed 's+/+-+'`" >> .env
|
||||||
|
- export $(cat .env | xargs)
|
||||||
|
- cat .env
|
||||||
|
- sed -i 's#\(const release = \).*#\1"'$${PROJECT_RELEASE}'"#g' api/hooks/config-client.js
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
image: node:18
|
||||||
|
commands:
|
||||||
|
- yarn build
|
||||||
|
|
||||||
|
- name: build ssr
|
||||||
|
image: node:18
|
||||||
|
commands:
|
||||||
|
- yarn build:server
|
||||||
|
|
||||||
|
- name: build legacy
|
||||||
|
image: node:18
|
||||||
|
commands:
|
||||||
|
- yarn build:legacy
|
||||||
|
|
||||||
|
- name: modify html
|
||||||
|
image: bash
|
||||||
|
commands:
|
||||||
|
- bash scripts/preload-meta.sh frontend/spa.html
|
||||||
|
- bash scripts/preload-meta.sh frontend/spa.html > frontend/_spa.html
|
||||||
|
- cp frontend/_spa.html frontend/spa.html
|
||||||
|
- export stamp=`date +%s`
|
||||||
|
- echo $$stamp
|
||||||
|
- sed -i s/__TIMESTAMP__/$$stamp/g frontend/spa.html
|
||||||
|
#- sed -i s/__TIMESTAMP__/$$stamp/g frontend/serviceworker.js
|
||||||
|
#- cat frontend/serviceworker.js
|
||||||
|
- cp frontend/spa.html api/templates/spa.html
|
||||||
|
- cat frontend/spa.html
|
||||||
|
|
||||||
|
# staging
|
||||||
|
- name: copy api config to staging
|
||||||
|
image: instrumentisto/rsync-ssh
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
path: /data
|
||||||
|
commands:
|
||||||
|
- rsync -av api /data/
|
||||||
|
- mkdir -p /data/frontend/dist
|
||||||
|
- rsync -av frontend/dist/ /data/frontend/dist/
|
||||||
|
when:
|
||||||
|
branch: [dev]
|
||||||
|
event: [push]
|
||||||
|
|
||||||
|
- name: review in staging
|
||||||
|
image: docker/compose:1.22.0
|
||||||
|
commands:
|
||||||
|
- docker-compose -p ${DRONE_BRANCH}-${DRONE_REPO_NAME}-${DRONE_REPO_OWNER} up -d --build --remove-orphans
|
||||||
|
volumes:
|
||||||
|
- name: docker
|
||||||
|
path: /var/run/docker.sock
|
||||||
|
when:
|
||||||
|
branch: [dev]
|
||||||
|
event: [push]
|
||||||
|
|
||||||
|
# live
|
||||||
|
- name: deploy master
|
||||||
|
image: instrumentisto/rsync-ssh
|
||||||
|
environment:
|
||||||
|
RSYNC_USER: ""
|
||||||
|
RSYNC_PASS:
|
||||||
|
from_secret: rsync_master
|
||||||
|
# remove if user and pass is set
|
||||||
|
failure: ignore
|
||||||
|
commands:
|
||||||
|
- apk add --no-cache sshpass curl
|
||||||
|
- scripts/deploy.sh ftp1.webmakers.de $${RSYNC_USER} $${RSYNC_PASS}
|
||||||
|
# - curl -X POST "https://www....de/api/ssr?token=TowendQhi&clear=1"
|
||||||
|
when:
|
||||||
|
branch: [master]
|
||||||
|
event: [push]
|
||||||
|
|
||||||
|
# - name: upload sourcemaps for glitchtip
|
||||||
|
# image: node
|
||||||
|
# environment:
|
||||||
|
# GLITCHTIP_TOKEN:
|
||||||
|
# from_secret: glitchtip_token
|
||||||
|
# commands:
|
||||||
|
# - yarn upload:sourcemaps
|
||||||
|
|
||||||
|
########
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
host:
|
||||||
|
path: /data/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}/${DRONE_BRANCH}
|
||||||
|
- name: docker
|
||||||
|
host:
|
||||||
|
path: /var/run/docker.sock
|
7
.env
Normal file
7
.env
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
PROJECT_NAME=tibi-docs
|
||||||
|
TIBI_PREFIX=tibi
|
||||||
|
TIBI_NAMESPACE=tibi-docs
|
||||||
|
UID=100
|
||||||
|
GID=101
|
||||||
|
RELEASE_ORG_SLUG=webmakers-gmbh
|
||||||
|
RELEASE_PROJECT_SLUG=tibi-docs
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.yarn/cache/* filter=lfs diff=lfs merge=lfs -text
|
56
.gitea/workflows/deploy.yaml
Normal file
56
.gitea/workflows/deploy.yaml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
name: deploy to production
|
||||||
|
|
||||||
|
on: "push"
|
||||||
|
# push:
|
||||||
|
# branches:
|
||||||
|
# - master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
name: deploy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: gitbase.de/actions/ubuntu:latest
|
||||||
|
volumes:
|
||||||
|
- /data:/data
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
lfs: true
|
||||||
|
submodules: true
|
||||||
|
- run: |
|
||||||
|
git fetch --force --tags
|
||||||
|
|
||||||
|
# setup node 18
|
||||||
|
- name: setup node 18
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
|
||||||
|
- name: build docs
|
||||||
|
env:
|
||||||
|
FORCE_COLOR: "true"
|
||||||
|
run: |
|
||||||
|
node --version
|
||||||
|
cd docs
|
||||||
|
yarn install
|
||||||
|
yarn docpress:build
|
||||||
|
|
||||||
|
- name: deploy docs
|
||||||
|
# only if branch is master
|
||||||
|
if: github.ref == 'refs/heads/master'
|
||||||
|
env:
|
||||||
|
RSYNC_HOST: ftp1.webmakers.de
|
||||||
|
RSYNC_PORT: 22222
|
||||||
|
RSYNC_USER: webmakers_tibi_docs_rsync_master
|
||||||
|
RSYNC_PASS: ${{ secrets.rsync_master }}
|
||||||
|
run: |
|
||||||
|
cd docs
|
||||||
|
ls -la
|
||||||
|
|
||||||
|
rsync -rlcgD --perms -i -u -v --stats --progress \
|
||||||
|
--delete \
|
||||||
|
-e "sshpass -p ${RSYNC_PASS} ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p ${RSYNC_PORT}" \
|
||||||
|
_docpress/ \
|
||||||
|
${RSYNC_USER}@${RSYNC_HOST}:./ \
|
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
docs/_docpress
|
||||||
|
docs/node_modules
|
||||||
|
docs/.yarn/*
|
||||||
|
!docs/.yarn/patches
|
||||||
|
!docs/.yarn/plugins
|
||||||
|
!docs/.yarn/releases
|
||||||
|
!docs/.yarn/sdks
|
||||||
|
!docs/.yarn/versions
|
||||||
|
api/hooks/lib/app.server*
|
||||||
|
node_modules
|
||||||
|
media
|
||||||
|
tmp
|
||||||
|
_temp
|
||||||
|
frontend/dist
|
||||||
|
yarn-error.log
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/cache
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
15
.prettierrc
Normal file
15
.prettierrc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 120,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"singleQuote": false,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"semi": false,
|
||||||
|
"newline-before-return": true,
|
||||||
|
"no-duplicate-variable": [true, "check-parameters"],
|
||||||
|
"no-var-keyword": true,
|
||||||
|
"svelteSortOrder": "scripts-markup-styles",
|
||||||
|
"svelteStrictMode": true,
|
||||||
|
"svelteBracketNewLine": true,
|
||||||
|
"svelteAllowShorthand": true,
|
||||||
|
"svelteIndentScriptAndStyle": true
|
||||||
|
}
|
28
.vscode/settings.json
vendored
Normal file
28
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"editor.tabCompletion": "on",
|
||||||
|
"diffEditor.codeLens": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.formatOnPaste": true,
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"yaml.schemas": {
|
||||||
|
"./../../cms/tibi-types/schemas/api-config/config.json": "api/config.y*ml",
|
||||||
|
"./../../cms/tibi-types/schemas/api-config/collection.json": "api/collections/*.y*ml",
|
||||||
|
"./../../cms/tibi-types/schemas/api-config/field.json": "api/collections/fields/*.y*ml",
|
||||||
|
"./../../cms/tibi-types/schemas/api-config/fieldArray.json": "api/collections/fieldLists/*.y*ml",
|
||||||
|
"./../../cms/tibi-types/schemas/api-config/job.json": "api/jobs/*.y*ml",
|
||||||
|
"./../../cms/tibi-types/schemas/api-config/assets.json": "api/assets/*.y*ml",
|
||||||
|
"https://json.schemastore.org/github-workflow.json": "file:///WM_Dev/src/gitbase.de/cms/tibi-docs/.gitea/workflows/deploy.yaml"
|
||||||
|
},
|
||||||
|
"yaml.customTags": ["!include scalar"],
|
||||||
|
"filewatcher.commands": [
|
||||||
|
{
|
||||||
|
"match": "/api/.*(\\.ya?ml|js|env)$",
|
||||||
|
"isAsync": false,
|
||||||
|
"cmd": "docker compose -p tibi-docs restart tibiserver",
|
||||||
|
"event": "onFileChange"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"i18n-ally.localesPaths": ["frontend/locales"],
|
||||||
|
"i18n-ally.sourceLanguage": "de",
|
||||||
|
"i18n-ally.keystyle": "nested"
|
||||||
|
}
|
541
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
Normal file
541
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
Normal file
File diff suppressed because one or more lines are too long
801
.yarn/releases/yarn-3.2.4.cjs
vendored
Executable file
801
.yarn/releases/yarn-3.2.4.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
9
.yarnrc.yml
Normal file
9
.yarnrc.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
globalFolder: .yarn/global
|
||||||
|
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||||
|
spec: "@yarnpkg/plugin-interactive-tools"
|
||||||
|
|
||||||
|
yarnPath: .yarn/releases/yarn-3.2.4.cjs
|
49
Makefile
Normal file
49
Makefile
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
DOCKER_COMPOSE=docker compose -f docker-compose-local.yml
|
||||||
|
DOCKER_ALL_PROFILES=--profile docpress --profile tibi-dev --profile tibi --profile chisel
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
|
.PHONY: docker-up docker-up-tibi-dev docker-up-chisel docker-up-docpress docker-start docker-start-tibi-dev docker-down docker-ps docker-logs docker-pull yarn-upgrade fix-permissions
|
||||||
|
|
||||||
|
include ./.env
|
||||||
|
|
||||||
|
help: ## show this help
|
||||||
|
@echo MAKE TARGETS
|
||||||
|
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
docker-up: ## bring docker compose stack up in background
|
||||||
|
$(DOCKER_COMPOSE) --profile tibi up -d
|
||||||
|
|
||||||
|
docker-up-tibi-dev: ## bring docker compose stack up in background with tibi-dev
|
||||||
|
$(DOCKER_COMPOSE) --profile tibi-dev up -d
|
||||||
|
|
||||||
|
docker-up-chisel: ## bring up chisel tunnel
|
||||||
|
$(DOCKER_COMPOSE) --profile chisel up -d
|
||||||
|
|
||||||
|
docker-down: ## take docker compose stack down
|
||||||
|
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) down
|
||||||
|
|
||||||
|
docker-start: ## start docker compose stack in foreground and take it down after CTRL-C
|
||||||
|
$(DOCKER_COMPOSE) --profile tibi up; $(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) down
|
||||||
|
|
||||||
|
docker-start-tibi-dev: ## start docker compose stack in foreground and take it down after CTRL-C (with tibi-dev)
|
||||||
|
$(DOCKER_COMPOSE) --profile tibi-dev up; $(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) down
|
||||||
|
|
||||||
|
docker-ps: ## show container state
|
||||||
|
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) ps
|
||||||
|
|
||||||
|
docker-logs: ## show docker logs and follow
|
||||||
|
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) logs -f || true
|
||||||
|
|
||||||
|
docker-pull: ## pull docker images
|
||||||
|
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) pull
|
||||||
|
|
||||||
|
docker-%:
|
||||||
|
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) $*
|
||||||
|
|
||||||
|
yarn-upgrade: # interactive yarn upgrade
|
||||||
|
$(DOCKER_COMPOSE) run --rm yarnstart yarn upgrade-interactive
|
||||||
|
$(DOCKER_COMPOSE) restart yarnstart
|
||||||
|
|
||||||
|
fix-permissions: # set files/directories owner to UID:GID from .env
|
||||||
|
sudo chown -R $(UID):$(GID) ./
|
59
README.md
Normal file
59
README.md
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Tibi Docs und Demo Projekt
|
||||||
|
|
||||||
|
Diese Repo enthält die Dokumentation zum TibiCMS und eine Demo-Projekt welches die Dokumentation begleitet.
|
||||||
|
|
||||||
|
Das Demo-Projekt kann als Vorlage für neue Tibi-Projekte verwendet werden.
|
||||||
|
|
||||||
|
## neues Projekt - Checkliste
|
||||||
|
|
||||||
|
- [x] neues Projekt im gitbase.de anlegen (cms/tibi-docs) als Vorlage verwenden
|
||||||
|
- [ ] klonen
|
||||||
|
- [ ] bereinigen
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git filter-branch -f --index-filter 'git rm -rf --cached --ignore-unmatch .yarn/cache' HEAD
|
||||||
|
git filter-branch -f --index-filter 'git rm -rf --cached --ignore-unmatch docs' HEAD
|
||||||
|
git push --force
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] anpassen
|
||||||
|
|
||||||
|
- `.env`
|
||||||
|
- `docker-compose-local.yml` -> `name:`
|
||||||
|
- `api/...`
|
||||||
|
|
||||||
|
- [ ] upgraden
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir tmp
|
||||||
|
# evtl. zuvor: yarn install
|
||||||
|
make yarn-upgrade
|
||||||
|
make docker-pull
|
||||||
|
|
||||||
|
# falls Fehler auftreten, evtl. Berechtigungen fixen
|
||||||
|
make fix-permissions
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] los programmieren
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make docker-start
|
||||||
|
|
||||||
|
# bei erstem fehlerhaften Start, evtl. Berechtigungen fixen:
|
||||||
|
make fix-permissions
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Projekt in Tibi bekannt machen:
|
||||||
|
- <https://PROJEKTNAME-tibiadmin.code.testversion.online>
|
||||||
|
- Pfad der API-Konfig: `/data/api/config.yml`
|
||||||
|
- [ ] Website im Browser ansehen:
|
||||||
|
- <https://PROJEKTNAME.code.testversion.online>
|
||||||
|
- [ ] Testmails checken:
|
||||||
|
- <https://PROJEKTNAME-maildev.testversion.online>
|
||||||
|
|
||||||
|
- [ ] deploy
|
||||||
|
1. [ ] Subdomain im basispanel anlegen auf `../frontend/`
|
||||||
|
2. [ ] rsync-Account in basispanel anlegen auf `htdocs/`
|
||||||
|
3. [ ] Passwort in Secrets eintragen: <https://drone.gitbase.de>
|
||||||
|
4. [ ] `.drone.yml` anpassen
|
||||||
|
5. [ ] pushen
|
12
api/assets/demoassets.yml
Normal file
12
api/assets/demoassets.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Ordnerpfade, die über den tibi-server direkt erreichbar seien sollen,
|
||||||
|
# können über den "path" relativ zur "config.yml" definiert werden.
|
||||||
|
# Durch die "name"-Definition werden diese Pfade eindeutig unterschieden.
|
||||||
|
# Für folgende Beispielangaben bildet sich folgende URL:
|
||||||
|
#
|
||||||
|
# TIBI-SERVER-URL/api/v1/_/NAMESPACE/_/assets/_dist_/
|
||||||
|
#
|
||||||
|
# Jeder Zugriff wird intern umgeleitet auf ../frontend/_dist_/
|
||||||
|
# (relativ zur "config.yml").
|
||||||
|
# Es ist ausschließlich ein unbeschränkter Lesezugriff (GET-Methode) möglich.
|
||||||
|
name: _dist_
|
||||||
|
path: ../frontend/_dist_
|
215
api/collections/democol.yml
Normal file
215
api/collections/democol.yml
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
# Der Name der Kollektion wird in der Rest-API-URL verwendet, z.B.
|
||||||
|
# /_/demo/democol
|
||||||
|
name: democol
|
||||||
|
|
||||||
|
# Enthält die Kollektion Felder vom Typ "file", so werden die
|
||||||
|
# hochgeladenen Dateien unter dem Ordner abgelegt, der mit
|
||||||
|
# "uploadPath" bestimmt wird.
|
||||||
|
uploadPath: ../media/democol
|
||||||
|
|
||||||
|
# "fields" stellen die Eigentliche Struktur der Kollektion dar.
|
||||||
|
# "fields" ist als Array angelegt um eine Standard-Sortierung
|
||||||
|
# im tibi-admin vorzugeben.
|
||||||
|
fields:
|
||||||
|
# Das Einbinden von Feldern über extra Dateien bietet sich nur
|
||||||
|
# an, wenn das jeweilige Feld mehrfach von dieser oder anderen
|
||||||
|
# Kollektionen verwendet wird.
|
||||||
|
# Auf die möglichen Definitionen wird im Kapitel "fields"
|
||||||
|
# eingegangen.
|
||||||
|
- !include fields/title.yml
|
||||||
|
- !include fields/type.yml
|
||||||
|
- !include fields/date.yml
|
||||||
|
- !include fields/content.yml
|
||||||
|
- !include fields/info.yml
|
||||||
|
|
||||||
|
# Neben der Definition der Indexe innerhalbd des Feld-Objektes selbst,
|
||||||
|
# ist die Index-Definition global für die Kollektion auch hier möglich.
|
||||||
|
# Diese Definition ist z.B. für zusammengesetzte Index-Typen notwendig.
|
||||||
|
# Außerdem sind hier feinere Einstellungen für den Index möglich.
|
||||||
|
|
||||||
|
# Mehr dazu im "indexes" Kapitel
|
||||||
|
# indexes:
|
||||||
|
# - !include democol/textindex.yml
|
||||||
|
|
||||||
|
# Standardsprache für Text-Index in der Datenbank
|
||||||
|
defaultLanguage: de
|
||||||
|
|
||||||
|
# "hooks" definieren die Algorithmen, die Daten und Abläufe zu bestimmten
|
||||||
|
# HTTP-Methoden und Schritten der API manipulieren können.
|
||||||
|
hooks:
|
||||||
|
# Hooks für die Methode "get"
|
||||||
|
get:
|
||||||
|
# "read"-Schritt wird ausgeführt, bevor die Daten von der Datenbank
|
||||||
|
# gelesen werden.
|
||||||
|
read:
|
||||||
|
# "type" ist derzeit immer "javascript"
|
||||||
|
type: javascript
|
||||||
|
# "file" zeigt auf die Datei mit dem Javascript-Code relativ zum
|
||||||
|
# Ordner der "config.yml" Datei.
|
||||||
|
file: hooks/democol/get_read.js
|
||||||
|
# "return"-Schritt wird ausgeführt, bevor die gelesenen Daten über
|
||||||
|
# HTTP übertragen werden.
|
||||||
|
return:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/get_return.js
|
||||||
|
|
||||||
|
# Hooks für die Methode "post"
|
||||||
|
post:
|
||||||
|
# "bind" wird ausgeführt, bevor die übertragenen Daten in eine
|
||||||
|
# Objekt-Struktur umgewandelt werden.
|
||||||
|
# Der tibi-server erwarten nach diesem Schritt gültige JSON-Daten,
|
||||||
|
# d.h. sollte es möglich gemacht werden, dass andere Daten übertragen
|
||||||
|
# werden, sind diese in diesem Hook abzufangen und zu verarbeiten.
|
||||||
|
bind:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/post_bind.js
|
||||||
|
# "validate" wird ausgeführt, bevor die Daten validiert werden.
|
||||||
|
validate:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/post_validate.js
|
||||||
|
# "create" wird ausgeführt, bevor das Objekt/Dokument in der Datenbank
|
||||||
|
# angelegt wird.
|
||||||
|
create:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/post_create.js
|
||||||
|
# "return" wird ausgeführt, bevor die Serverantwort über HTTP
|
||||||
|
# übertragen wird.
|
||||||
|
return:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/post_return.js
|
||||||
|
|
||||||
|
# Hooks für die Methode "put"
|
||||||
|
put:
|
||||||
|
bind:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/put_bind.js
|
||||||
|
validate:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/put_validate.js
|
||||||
|
# "bind" und "validate" habe die gleiche Bedeutung wie Hooks der
|
||||||
|
# Methode "post".
|
||||||
|
# "update" wird ausgeführt bevor das Objekt in der Datenbank
|
||||||
|
# aktualisiert wird.
|
||||||
|
update:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/put_update.js
|
||||||
|
# "return" wird auch hier vor der Serverantwort ausgeführt.
|
||||||
|
return:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/put_return.js
|
||||||
|
|
||||||
|
# Hooks für die Methode "delete"
|
||||||
|
delete:
|
||||||
|
# Der "delete"-Hook wird vor dem eigentlichen Löschen ausgeführt
|
||||||
|
delete:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/delete_delete.js
|
||||||
|
# "return"-Hook kann ebenso hier die Serverantwort manipulieren
|
||||||
|
return:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/democol/delete_return.js
|
||||||
|
|
||||||
|
# Projektionen der Daten werden via GET-Parameter "projection=..."
|
||||||
|
# referenziert.
|
||||||
|
# "projections" is ein Objekt, dass die Namen der Projektionen
|
||||||
|
# als Key führt.
|
||||||
|
projections:
|
||||||
|
# "list" = Name der Projektion
|
||||||
|
list:
|
||||||
|
# "select" definiert als Keys die Felder, die beim Abruf
|
||||||
|
# dieser Projektion in den Ausgabe-Daten enthalten sind.
|
||||||
|
# Felder werden über die Punkt-Notation referenziert.
|
||||||
|
select:
|
||||||
|
title: 1
|
||||||
|
date: 1
|
||||||
|
# refenziert das "subField" "author" unterhalb von "meta"
|
||||||
|
meta.author: 1
|
||||||
|
details:
|
||||||
|
# Alternativ kann "select" auch Auschlussregeln definieren.
|
||||||
|
# Eine Mischung von Inkludieren und Auschluss ist NICHT
|
||||||
|
# möglich.
|
||||||
|
select:
|
||||||
|
comment: 0
|
||||||
|
full:
|
||||||
|
# Ein leeres "select" Objekt beschränkt die Ausgabe der
|
||||||
|
# Daten nicht und ist Standard, wenn der "projection="
|
||||||
|
# Parameter nicht verwendet wurde.
|
||||||
|
select:
|
||||||
|
|
||||||
|
# Allgeine Zugriffsregeln auf Kollektions-Ebene werden mit dem
|
||||||
|
# "permissions" Objekt festgelegt.
|
||||||
|
permissions:
|
||||||
|
# Unter "public" werden die Zugriffsrechte für die Öffentlichkeit
|
||||||
|
# definiert.
|
||||||
|
public:
|
||||||
|
# "methods" führt die HTTP-Methoden auf, die erlaubt sind
|
||||||
|
methods:
|
||||||
|
# "get: true" bedeutet hier, dass jeder die Daten lesen darf
|
||||||
|
get: true
|
||||||
|
# "post", also Einträge erstellen, "put" = Bearbeiten und
|
||||||
|
# "delete" = löschen darf die Öffentlichkeit nicht.
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
# Ist "validProjections" definiert, sind auch nur genau die
|
||||||
|
# aufgelisteten Projektionen erlaubt, welche zwingend mit dem
|
||||||
|
# GET-Parameter "projection=..." ausgewählt werden müssen.
|
||||||
|
validProjections:
|
||||||
|
- list
|
||||||
|
- details
|
||||||
|
|
||||||
|
# Der Key "user" steht für ALLE Benutzer die dem Projekt
|
||||||
|
# zugeordnet sind.
|
||||||
|
# D.h. eine feinere Abstufung auf Benutzerebene ist mit dem
|
||||||
|
# Key "user" allein nicht möglich.
|
||||||
|
# Für eine feinere Abstufung können nachgelagerte Hooks
|
||||||
|
# dienen oder die Verwendung von zugeordneten benutzerdefinierten
|
||||||
|
# "permissions" (siehe meta Objekt).
|
||||||
|
user:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
# Fehlt "validProjections", sind automatisch alle Projektionen
|
||||||
|
# erlaubt, wobei hier auch der GET-Parameter "projection="
|
||||||
|
# weggelassen werden darf und somit alle Felder in der Ausgabe
|
||||||
|
# zu finden sind.
|
||||||
|
|
||||||
|
# Folgende Brechtigung wird angewandt, wenn der Zugriff über
|
||||||
|
# den GET-Parameter "token=" oder die Header-Anweisung "token: "
|
||||||
|
# angefragt wird.
|
||||||
|
# "token" ist dabei die Markierung, dass es sich um einen Token
|
||||||
|
# handelt und "${TOKEN}" ist der benutzerdefinierte Token selbst.
|
||||||
|
# Dieser wird hier über eine Umgebungsvariable "TOKEN" injiziert,
|
||||||
|
# die in "config.yml.env" definiert werden kann mit "TOKEN=...".
|
||||||
|
token:${TOKEN}:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: true
|
||||||
|
put: true
|
||||||
|
delete: true
|
||||||
|
|
||||||
|
# Alle Berechtigungs-Namen, die nicht "public", "user" oder "token:..."
|
||||||
|
# heißen, sind benutzerdefinierte Berechtigungen, die Benutzern
|
||||||
|
# zugeordnet werden können.
|
||||||
|
# Eine mögliche Auflistung um Vorschläge im tibi-admin anzubieten,
|
||||||
|
# werden im Top-Level meta-Objekt der "config.yml" unter "permissions"
|
||||||
|
# definiert.
|
||||||
|
pages:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: true
|
||||||
|
put: true
|
||||||
|
delete: true
|
||||||
|
|
||||||
|
# "imageFilter" definieren Filter, die Bilder bearbeiten, wie
|
||||||
|
# z.B. Verkleinerung.
|
||||||
|
# Mögliche Angaben werden im seperaten Kapitel behandelt.
|
||||||
|
imageFilter: !include democol/imageFilter.yml
|
||||||
|
|
||||||
|
# Wie auch in der Top-Level-Konfig "config.yml" ist auch hier ein
|
||||||
|
# "meta" Objekt möglich und nötig für die Konfiguration des
|
||||||
|
# tibi-admin.
|
||||||
|
# Mögliche Angaben werden im seperaten Kapitel behandelt.
|
||||||
|
meta: !include democol/meta.yml
|
25
api/collections/democol/imageFilter.yml
Normal file
25
api/collections/democol/imageFilter.yml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Der Key des Objektes definiert den Namen des Filters.
|
||||||
|
# Jeder Filter ist eine Liste von Bildmanipulationen, die
|
||||||
|
# nacheinander angewandt werden.
|
||||||
|
# Die manipulierten Bilder werden gecachet. Ein nachträgliches
|
||||||
|
# Anpassen der Filter erfordert also das Löschen der gecachten
|
||||||
|
# Dateien welche sich jeweils neben den original Bilddateien
|
||||||
|
# im "uploadPath" der Kollektion befinden.
|
||||||
|
s:
|
||||||
|
- fit: true
|
||||||
|
height: 300
|
||||||
|
width: 300
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
m:
|
||||||
|
- fit: true
|
||||||
|
height: 600
|
||||||
|
width: 600
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
||||||
|
l:
|
||||||
|
- fit: true
|
||||||
|
height: 1200
|
||||||
|
width: 1200
|
||||||
|
resampling: lanczos
|
||||||
|
quality: 60
|
112
api/collections/democol/meta.yml
Normal file
112
api/collections/democol/meta.yml
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# Ein Label für tibi-admin wird mehrsprachig folgendermaßen definiert
|
||||||
|
label:
|
||||||
|
de: Demo-Kolletion
|
||||||
|
en: Demo-Collection
|
||||||
|
|
||||||
|
# Jede Kolletion kann ein eigenes Icon aus mdijs bekommen.
|
||||||
|
muiIcon: web
|
||||||
|
|
||||||
|
# Die Standardsortierung bei ersten Aufruf der Kollektion.
|
||||||
|
defaultSort:
|
||||||
|
# Nach welchem Feld soll sortiert werden?
|
||||||
|
field: updatedTime
|
||||||
|
# ASC für aufsteigend oder DESC für absteigend
|
||||||
|
order: DESC
|
||||||
|
|
||||||
|
# Ist ein Javascript Message-Object-Empfänger implementiert, der empfangene
|
||||||
|
# Daten als Vorschau rendern kann, so ist dieser hier zu definieren.
|
||||||
|
# Implementierungshinweise zu einem Solchen gibt es später.
|
||||||
|
previewUrl: https://demo.testversion.online/preview
|
||||||
|
|
||||||
|
# Aus den definierten "imageFilter"-Angaben kann ein Filter für die
|
||||||
|
# Ausgabe der Thunbnails in der Admin-Ansicht ausgewählt werden.
|
||||||
|
defaultImageFilter: s
|
||||||
|
|
||||||
|
# Jede Kollektion kann über media-Querys mit mehreren Ansichten veknüpft werden.
|
||||||
|
# Mögliche Ansichten und die dazugehörigen CSS-Queries sind hier zu defineren.
|
||||||
|
views:
|
||||||
|
# Natürlich können die Angaben auch ausgelagert und mehrfach verwendet werden.
|
||||||
|
# Die möglichen Angaben werden im Kapitel "views" gezeigt.
|
||||||
|
- !include simpleList.yml
|
||||||
|
- !include table.yml
|
||||||
|
|
||||||
|
# Wird eine Kollektion als eine Gesamtliste schnell unübersichtlich, hild die
|
||||||
|
# Definition von "subNavigation".
|
||||||
|
# Die meisten Angaben sind aus obiger Beschreibung den meta-Objektes bekannt.
|
||||||
|
# Es wird hier nur auf die zusätzlichen Angaben eingegangen.
|
||||||
|
subNavigation:
|
||||||
|
- # Jede Unternavigation braucht einen eindeutigen Namen um diese später
|
||||||
|
# in z.B. Javascript-Code wieder erkennen zu können.
|
||||||
|
name: pages
|
||||||
|
|
||||||
|
# Die Angabe des "label" ist optional. Wird sie nicht angegeben, wird
|
||||||
|
# wird diese Unternavigation nicht in der Navigation angezeigt.
|
||||||
|
# Ohne "label" kann die Unternavigation aber weiterhin für die Referenzierung
|
||||||
|
# z.B. in der Mediathek-Ansicht des ContentBuilders verwendet werden.
|
||||||
|
label:
|
||||||
|
de: Seiten
|
||||||
|
en: Pages
|
||||||
|
|
||||||
|
muiIcon: page-layout-body
|
||||||
|
|
||||||
|
defaultSort:
|
||||||
|
field: titel
|
||||||
|
order: ASC
|
||||||
|
|
||||||
|
# Standardmäßig wird man beim Klick auf einen Eintrag der Kollektion
|
||||||
|
# (z.B. Zeile in der Tabelle) direkt zum Editieren des Datensatzes weitergeleitet.
|
||||||
|
# Möchte man das nicht, so kann hier ein alternatives Verhalten definiert werden.
|
||||||
|
# Mögliche Werte sind:
|
||||||
|
# - "edit" (Standard)
|
||||||
|
# - "view" (Anzeigen des Datensatzes)
|
||||||
|
# - Objekt mit "eval"-Attribut
|
||||||
|
#
|
||||||
|
# Beim Objekt mit "eval"-Attribut wird der Code mit dem Javascript-Kontext für
|
||||||
|
# Kollektionen im tibi-admin ausgeführt. Das Ergebnis kann hierbei wieder "edit"
|
||||||
|
# oder "view" sein.
|
||||||
|
# Außerdem ist es möglich, eine eigene Funktion zu definieren, die den Datensatz
|
||||||
|
# als Parameter erhält. Diese Funktion wird dann für den jweiligen Datensatz
|
||||||
|
# ausgeführt, auf den geklickt wurde. Mehr dazu unter dem Widget "ContentBuilder".
|
||||||
|
defaultCallback: view
|
||||||
|
|
||||||
|
views:
|
||||||
|
- !include simpleList.yml
|
||||||
|
- !include table.yml
|
||||||
|
# Um mehr Übersicht zu bekommen können zum Einen andere "views" und "defaultSort"
|
||||||
|
# genutzt werden. Es kann aber auch eine Einschränkung der Daten über eine
|
||||||
|
# Vorfilterung via "filter" geben. "filter" ist ein Objekt mit MongoDB-Filterangaben.
|
||||||
|
# siehe: https://www.mongodb.com/docs/compass/current/query/filter/
|
||||||
|
filter:
|
||||||
|
type: page
|
||||||
|
|
||||||
|
- name: news
|
||||||
|
label:
|
||||||
|
de: Neuigkeiten
|
||||||
|
en: News
|
||||||
|
muiIcon: newspaper
|
||||||
|
defaultSort:
|
||||||
|
field: date
|
||||||
|
order: DESC
|
||||||
|
defaultCallback: edit
|
||||||
|
views:
|
||||||
|
- !include simpleList.yml
|
||||||
|
- !include table.yml
|
||||||
|
filter:
|
||||||
|
type: news
|
||||||
|
|
||||||
|
# Standardmäßig werden im Formular zu Eingabe der Daten alle Felder von "fields"
|
||||||
|
# untereinander angeordnet.
|
||||||
|
# Um diese Anordnung in Tabs zu strukturieren, ist die Verwendung von "tablist"
|
||||||
|
# vorgesehen.
|
||||||
|
# Die Definition befindet sich in einem gesonderten Kapitel
|
||||||
|
tablist: !include tablist.yml
|
||||||
|
|
||||||
|
# OpenAPI-Spezifikation für die API-Endpunkte der Kollektion
|
||||||
|
openapi:
|
||||||
|
get:
|
||||||
|
summary:
|
||||||
|
en: list all datasets of democol
|
||||||
|
de: listet alle Datensätze der Kollektion democol auf
|
||||||
|
description:
|
||||||
|
en: list all datasets of democol with pagination and/or filtering
|
||||||
|
de: listet alle Datensätze der Kollektion democol mit Paginierung und/oder Filterung
|
19
api/collections/democol/simpleList.yml
Normal file
19
api/collections/democol/simpleList.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# "type" legt den Typ des Views fest.
|
||||||
|
type: simpleList
|
||||||
|
# Die Auswahl erfolgt über folgende "mediaQuery".
|
||||||
|
# (hier also bis maximal 599px Fensterbreite)
|
||||||
|
mediaQuery: "(max-width:599px)"
|
||||||
|
|
||||||
|
# 3 Blöcke können in der simpleList verwendet werden.
|
||||||
|
# Haupttext "primaryText" und optional 2 weitere Angaben über
|
||||||
|
# "secondaryText" und "tertiaryText".
|
||||||
|
# Die Angabe des jeweiligen Feldes erfolgt als String oder
|
||||||
|
# Objekt mit der "source"-Eigenschaft.
|
||||||
|
# Das Feld selbst wird in Punkt-Notation angegeben.
|
||||||
|
# Die Darstellung selbst ist abhängig von der Feld-Konfiguration
|
||||||
|
# selbst, die unter fields in der Kollektions-Konfiguration
|
||||||
|
# stattfindet.
|
||||||
|
primaryText: title
|
||||||
|
secondaryText:
|
||||||
|
source: date
|
||||||
|
tertiaryText: meta.author
|
14
api/collections/democol/table.yml
Normal file
14
api/collections/democol/table.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
type: table
|
||||||
|
mediaQuery: "(min-width:600px)"
|
||||||
|
columns:
|
||||||
|
- source: updateTime
|
||||||
|
label:
|
||||||
|
de: letztes Update
|
||||||
|
en: last update
|
||||||
|
type: date
|
||||||
|
- source: title
|
||||||
|
filter: true
|
||||||
|
- source: date
|
||||||
|
filter: true
|
||||||
|
- source: type
|
||||||
|
filter: true
|
31
api/collections/democol/tablist.yml
Normal file
31
api/collections/democol/tablist.yml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Hier wird der initial zu öffnende Tab festgelegt.
|
||||||
|
# Ist dieser nicht festgelegt, wird automatisch der erste Tab
|
||||||
|
# aus der "tabs" Liste gewaählt.
|
||||||
|
activeTab: general
|
||||||
|
# "tabs" ist die eigentliche Liste
|
||||||
|
tabs:
|
||||||
|
- # Jeder Tab braucht einen Namen, über den er refereziert
|
||||||
|
# werden kann.
|
||||||
|
name: general
|
||||||
|
# Die übliche Labelangabe kann auch hier mehrpsrachig erfolgen.
|
||||||
|
label:
|
||||||
|
de: Allgemein
|
||||||
|
en: General
|
||||||
|
# Welche Felder dieser Tab anzeigen soll, wird über "subFields"
|
||||||
|
# beschrieben.
|
||||||
|
subFields:
|
||||||
|
- source: type
|
||||||
|
- source: title
|
||||||
|
- source: date
|
||||||
|
- name: content
|
||||||
|
label:
|
||||||
|
de: Inhalt
|
||||||
|
en: Content
|
||||||
|
subFields:
|
||||||
|
- source: content
|
||||||
|
- name: info
|
||||||
|
label:
|
||||||
|
de: Informationen
|
||||||
|
en: Information
|
||||||
|
subFields:
|
||||||
|
- source: info
|
0
api/collections/democol/textindex.yml
Normal file
0
api/collections/democol/textindex.yml
Normal file
117
api/collections/fields/content.yml
Normal file
117
api/collections/fields/content.yml
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# Der Name des Feldes ist natürlich beliebig wählbar.
|
||||||
|
name: content
|
||||||
|
|
||||||
|
# "string" als Datentyp ist zwingend.
|
||||||
|
type: string
|
||||||
|
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Inhalt
|
||||||
|
en: content
|
||||||
|
|
||||||
|
# Die Bezeichnung des ContentBuilder-Widgets ist "contentbuilder".
|
||||||
|
widget: contentbuilder
|
||||||
|
|
||||||
|
# Die Anzeige des ContentBuilder im tibi-admin geschieht innerhalb
|
||||||
|
# eines iframes. Das ist notwendig, da der ContentBuilder eigene
|
||||||
|
# Styles mitbringet, die sich nicht mit den Styles des tibi-admin
|
||||||
|
# vermischen sollten.
|
||||||
|
|
||||||
|
# Via "baseHref" wird der <base>-Tag im iframe gesetzt.
|
||||||
|
# somit können alle relativen Pfade im ContentBuilder (z.B. Bilder)
|
||||||
|
# aufgelöst werden.
|
||||||
|
# Wie man hier sieht, ist die Angabe via "eval" mittels möglich.
|
||||||
|
# Der Kontext ist auf Feldebene, wie bei "dependsOn" und "defaultValue".
|
||||||
|
# Alternativ kann die Angabe auch direkt als String erfolgend.
|
||||||
|
# Dann natürlich ohne die Evaluierung der Variable "$projectBase", wie hier.
|
||||||
|
baseHref:
|
||||||
|
eval: $projectBase
|
||||||
|
|
||||||
|
# Sollen weitere CSS-Datei in das iframe geladen werden, können diese
|
||||||
|
# hier aufgelistet werden.
|
||||||
|
# Die Angabe kann direkt als Array erfolgen oder via "eval", dessen
|
||||||
|
# Code das Array der Strings mit den Dateipfaden zurückgibt.
|
||||||
|
# Auch zu beachten ist hier die relative Angabe. Da "baseHref" gesetzt
|
||||||
|
# ist, wird der Pfad relativ zu dieser Projekt-Basis innerhalb des
|
||||||
|
# tibi-server aufgelöst.
|
||||||
|
# Die Auslieferung der CSS-Dateien direkt über den tibi-server kann
|
||||||
|
# nur funktionieren, wenn "_dist_" in der "assets" Konfiguration der
|
||||||
|
# "config.yml" definiert ist.
|
||||||
|
cssHref:
|
||||||
|
- _/assets/_dist_/index.css
|
||||||
|
|
||||||
|
# Um eine Kollektion stellvertretend als Mediathek anzubinden, sind die
|
||||||
|
# Angaben unter "imageSelect", "fileSelect" und "videoSelect" zu tätigen.
|
||||||
|
# "imageSelect" betrifft die Einbindung von Bildern, "fileSelect" die
|
||||||
|
# Einbindung von Dateien, "videoSelect" die Einbindung von Videos.
|
||||||
|
imageSelect:
|
||||||
|
|
||||||
|
# Die Angabe "collection" ist zwingend. Hier wird die Kollektion
|
||||||
|
# definiert, die als Sammlung für die Bilder/Datei dient.
|
||||||
|
# Der Aufbau der Kollektion ist dabei frei, solange ein Upload-Feld
|
||||||
|
# für die Dateien existiert, welches die URL zur Datei zurückgibt.
|
||||||
|
collection: medialib
|
||||||
|
|
||||||
|
# Optional kann ein Filter und View für die Einbindung der Bilder/Dateien
|
||||||
|
# definiert werden. Dies geschieht über einen "subNavigation"
|
||||||
|
# Eintrag innerhalb des "meta.subNavigation" Arrays, der Kollektion
|
||||||
|
# (hier bei "medialib").
|
||||||
|
# Die Angabe hier ist die auszuwählende Navigation per Index des Arrays.
|
||||||
|
subNavigation: 0
|
||||||
|
|
||||||
|
fileSelect:
|
||||||
|
collection: medialib
|
||||||
|
subNavigation: 0
|
||||||
|
videoSelect:
|
||||||
|
collection: medialib
|
||||||
|
subNavigation: 0
|
||||||
|
|
||||||
|
# "customTags" des ContentBuilder können verwendet werden um die Einbindung
|
||||||
|
# von Modulen ins HTML zu ermöglichen.
|
||||||
|
# Die folgende Auflistung ist dabei ein Beispiel für ein Modul.
|
||||||
|
customTags:
|
||||||
|
|
||||||
|
- # Der Platzhalter wird 1:1 ins HTML übernommen und ist dabei frei
|
||||||
|
# definierbar.
|
||||||
|
# Die eigentliche Funktion eines Modul-Systems muss dann später
|
||||||
|
# im Frontend implementiert werden.
|
||||||
|
placeholder: "<my-module class='tibi-module' title='Titel' description='Beschreibung'>Mein Modul</my-module>"
|
||||||
|
|
||||||
|
# Die Benennung für die UI des ContentBuilder geschieht über die
|
||||||
|
# "label" Angabe, die mehrsprachig erfolgen kann.
|
||||||
|
label:
|
||||||
|
de: "Mein Modul"
|
||||||
|
en: "My Module"
|
||||||
|
|
||||||
|
# Um direkt Style-Angaben in das iframe des ContentBuilder zu übernehmen,
|
||||||
|
# werden diese hier angegeben.
|
||||||
|
# Natürlich ist auch hier wieder die Angabe via "eval" möglich.
|
||||||
|
# Nachfolgendes Beispiel erzeugt im ContentBuilder eine deutliche Darstellung
|
||||||
|
# des eingebundenen Moduls.
|
||||||
|
style: |
|
||||||
|
/*css*/
|
||||||
|
.is-builder {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.tibi-module {
|
||||||
|
padding: 10px;
|
||||||
|
border: 3px dashed #c4c4c4;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.tibi-module::before {
|
||||||
|
content: "\1F5BD ";
|
||||||
|
font-size: 16px;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.tibi-module::after {
|
||||||
|
content: " title=\"" attr(title) "\" description=\"" attr(description) "\"";
|
||||||
|
font-size: 10px;
|
||||||
|
color: #555;
|
||||||
|
display: block;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
/*!css*/
|
57
api/collections/fields/date.yml
Normal file
57
api/collections/fields/date.yml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Der Name des Feldes wird in der Datenbank zum Objekt ebenso
|
||||||
|
# wie in der Ein- und Ausgabe über die API verwendet.
|
||||||
|
name: date
|
||||||
|
|
||||||
|
# Über "type" wird der Datentyp in der Datenbank festgelegt.
|
||||||
|
# Mögliche Typen sind weiter unten aufgelistet.
|
||||||
|
type: date
|
||||||
|
|
||||||
|
# Direkt am Feld kann eine Index-Definition erfolgen.
|
||||||
|
# Folgende mögliche Werte können ihn die Liste aufgenommen werden:
|
||||||
|
# "single" - Standard-Index für diese Feld
|
||||||
|
# "unique" - Das Feld muss einen eindeutigen Wert haben
|
||||||
|
# "text" - Alle "text"-Indexanganben aller Felder werden zu einem
|
||||||
|
# gemeinsamen Volltext-Index kombiniert
|
||||||
|
#
|
||||||
|
# Die Angabe des Volltextindex ist besser unter "collections.X.indexes"
|
||||||
|
# vorzunehmen.
|
||||||
|
index:
|
||||||
|
- single
|
||||||
|
|
||||||
|
# Jede Datenübertragung an des Server wird validiert, d.h. es werden
|
||||||
|
# keine Datentypen angenommen, die nicht zu "type" passen.
|
||||||
|
# Darüber hinaus kann via "validator" eine zusätzliche Validierung
|
||||||
|
# vorgenommen werden.
|
||||||
|
# Dazu gibt es ein extra Kapitel.
|
||||||
|
validator:
|
||||||
|
required: true
|
||||||
|
eval: new Date($this) > new Date()
|
||||||
|
|
||||||
|
# Und natürlich gibt es auch hier ein "meta" Objekt zur Steuerung
|
||||||
|
# des tibi-admin.
|
||||||
|
meta:
|
||||||
|
# Das "label" des Feldes wird als Label vor dem Widget verwendet.
|
||||||
|
label:
|
||||||
|
de: Titel
|
||||||
|
en: title
|
||||||
|
|
||||||
|
# Abgelkeitet vom "type" gibt es Standard-Widgets. für spezielle
|
||||||
|
# Aufgaben stehen aber eine Hand voll Widgets bereit, die später
|
||||||
|
# beschrieben werden.
|
||||||
|
widget: date
|
||||||
|
|
||||||
|
# Standardwerte für neue Enträge können entweder direkt angegeben
|
||||||
|
# werden oder via Javascript client-seitig generiert werden.
|
||||||
|
# In den Kontext injizierte Variablen werden später beschrieben.
|
||||||
|
defaultValue:
|
||||||
|
# Das Ergebnis von "eval" wird hier als Standardwert verwendet.
|
||||||
|
# (hier das aktuelle Datum)
|
||||||
|
eval: new Date()
|
||||||
|
|
||||||
|
# Sollen Felder abhängig von bestimmten Bedingungen ein- oder
|
||||||
|
# ausgeblendet werden, geschieht das über Anweisungen in "dependsOn".
|
||||||
|
dependsOn:
|
||||||
|
# Das Feld wird nur eingeblendet wenn der Wert von "type"
|
||||||
|
# (auf gleicher Ebene wie das Feld "date" selbst)
|
||||||
|
# gleich "news" ist.
|
||||||
|
eval: $parent?.type == "news"
|
32
api/collections/fields/info.yml
Normal file
32
api/collections/fields/info.yml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: info
|
||||||
|
type: object
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Info
|
||||||
|
en: Info
|
||||||
|
subFields:
|
||||||
|
- name: author
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Autor
|
||||||
|
en: Author
|
||||||
|
- name: tags
|
||||||
|
type: object[]
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Tags
|
||||||
|
en: Tags
|
||||||
|
subFields:
|
||||||
|
- name: name
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Name
|
||||||
|
en: Name
|
||||||
|
- name: color
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Farbe
|
||||||
|
en: Color
|
8
api/collections/fields/title.yml
Normal file
8
api/collections/fields/title.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
name: title
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Titel
|
||||||
|
en: Title
|
||||||
|
openapi:
|
||||||
|
example: Demo Titel
|
16
api/collections/fields/type.yml
Normal file
16
api/collections/fields/type.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
name: type
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Typ
|
||||||
|
en: Type
|
||||||
|
widget: select
|
||||||
|
choices:
|
||||||
|
- name:
|
||||||
|
de: Standardseite
|
||||||
|
en: Standard page
|
||||||
|
id: page
|
||||||
|
- name:
|
||||||
|
de: News
|
||||||
|
en: News
|
||||||
|
id: news
|
103
api/collections/medialib.yml
Normal file
103
api/collections/medialib.yml
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# Der Name der Kollektion ist beliebig, aber wird in unserem
|
||||||
|
# Beispiel vom ContentBuilder als "medialib" referenziert.
|
||||||
|
name: medialib
|
||||||
|
uploadPath: ../media/medialib
|
||||||
|
|
||||||
|
fields:
|
||||||
|
- !include fields/title.yml
|
||||||
|
|
||||||
|
# Ein Feld vom Typ "file" wird für die Mediathek natürlich
|
||||||
|
# benötigt.
|
||||||
|
- name: file
|
||||||
|
type: file
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Datei
|
||||||
|
en: File
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
public:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
user:
|
||||||
|
methods:
|
||||||
|
get: true
|
||||||
|
post: true
|
||||||
|
put: true
|
||||||
|
delete: true
|
||||||
|
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Medienbibliothek
|
||||||
|
en: Media Library
|
||||||
|
muiIcon: multimedia
|
||||||
|
defaultSort:
|
||||||
|
field: title
|
||||||
|
order: ASC
|
||||||
|
|
||||||
|
# "defaultImageFilter" dient auch hier nur zur Reduzierung der
|
||||||
|
# Bildgröße bei der Anzeige im tibi-admin (Listen).
|
||||||
|
# Die Bildgröße für die Einbindung ins erzeugte HTML des ContentBuilder
|
||||||
|
# hat hiermit nix zu tun.
|
||||||
|
defaultImageFilter: s
|
||||||
|
|
||||||
|
# Wird unter "image-/file-/videoSelect" im ContentBuilder Feld kein
|
||||||
|
# "subNavigation" Index definiert, werden auch folgende "views"
|
||||||
|
# verwendet.
|
||||||
|
views:
|
||||||
|
- type: table
|
||||||
|
mediaQuery: "(min-width: 0px)"
|
||||||
|
columns:
|
||||||
|
- source: updateTime
|
||||||
|
label: letztes Update
|
||||||
|
type: datetime
|
||||||
|
- source: title
|
||||||
|
filter: true
|
||||||
|
- source: file
|
||||||
|
|
||||||
|
# Wird ein "subNavigation" Index für "image-/file-/videoSelect" definiert,
|
||||||
|
# wird die entsprechende Navigation aus folgender Liste angesprochen.
|
||||||
|
# "0" ist dabei der Index für das erste Element dieser Liste.
|
||||||
|
subNavigation:
|
||||||
|
- # Der "name" der Navigation ist für die Mediathek nicht von Bedeutung,
|
||||||
|
# kann aber für "eval"-Code interessant sein.
|
||||||
|
name: modal
|
||||||
|
|
||||||
|
# Auf "label" wurde hier verzichtet, damit dieses Element nicht in der
|
||||||
|
# Hauptnavigation des tibi-admin auftaucht.
|
||||||
|
|
||||||
|
# Folgende Ansicht wird für unsere Auswahl der Datei im ContentBuilder
|
||||||
|
# angeboten.
|
||||||
|
views:
|
||||||
|
- type: table
|
||||||
|
mediaQuery: "(min-width: 0px)"
|
||||||
|
columns:
|
||||||
|
- source: title
|
||||||
|
filter: true
|
||||||
|
- source: file
|
||||||
|
|
||||||
|
# Damit der ContentBuilder weiß, welche Datei ausgewählt wurde, ist
|
||||||
|
# ist folgender "defaultCallback" notwendig.
|
||||||
|
# Die Funktion wird beim Klick auf die entsprechende Datei aufgerufen.
|
||||||
|
# Als Funktionsparameter steht der gesamte Datensatz der Auswahl zur
|
||||||
|
# Verfügung.
|
||||||
|
# Die Funktionen "parent.selectAsset" und "parent.focus" sind ContentBuilder
|
||||||
|
# spezifisch und schließen die Listenansicht direkt nach Übergabe der
|
||||||
|
# Datei-URL.
|
||||||
|
# Die URL setzt sich aus dem Pfad zur Datei und dem Filter "l" zusammen.
|
||||||
|
# Es wurde eine relative URL konstruiert, da das ContentBuilder-Widget
|
||||||
|
# mit "baseHref" zur Projekt-URL erstellt wird.
|
||||||
|
defaultCallback:
|
||||||
|
eval: |
|
||||||
|
//js
|
||||||
|
(entry) => {
|
||||||
|
parent.selectAsset("medialib/" + entry.id + "/" + entry.file?.src + "?filter=l")
|
||||||
|
parent.focus()
|
||||||
|
}
|
||||||
|
//!js
|
||||||
|
|
||||||
|
openapi:
|
||||||
|
disabled: true
|
62
api/collections/ssr.yml
Normal file
62
api/collections/ssr.yml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
########################################################################
|
||||||
|
# SSR Dummy collections
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
name: ssr
|
||||||
|
meta:
|
||||||
|
label: { de: "SSR Dummy", en: "ssr dummy" }
|
||||||
|
muiIcon: server
|
||||||
|
rowIdentTpl: { twig: "{{ id }}" }
|
||||||
|
views:
|
||||||
|
- type: simpleList
|
||||||
|
mediaQuery: "(max-width: 600px)"
|
||||||
|
primaryText: id
|
||||||
|
secondaryText: insertTime
|
||||||
|
tertiaryText: path
|
||||||
|
- type: table
|
||||||
|
columns:
|
||||||
|
- id
|
||||||
|
- insertTime
|
||||||
|
- path
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
public:
|
||||||
|
methods:
|
||||||
|
get: false
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
user:
|
||||||
|
methods:
|
||||||
|
get: false
|
||||||
|
post: false
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
"token:${SSR_TOKEN}":
|
||||||
|
methods:
|
||||||
|
# only via url=
|
||||||
|
get: true
|
||||||
|
post: true
|
||||||
|
put: false
|
||||||
|
delete: false
|
||||||
|
|
||||||
|
hooks:
|
||||||
|
get:
|
||||||
|
read:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/ssr/get_read.js
|
||||||
|
post:
|
||||||
|
bind:
|
||||||
|
type: javascript
|
||||||
|
file: hooks/ssr/post_bind.js
|
||||||
|
|
||||||
|
# we only need hooks
|
||||||
|
fields:
|
||||||
|
- name: path
|
||||||
|
type: string
|
||||||
|
index: [single, unique]
|
||||||
|
- name: content
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
inputProps:
|
||||||
|
multiline: true
|
58
api/config.yml
Normal file
58
api/config.yml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Der Namespace legt die eigentliche Projektbezeichnung und den Datenbankkontext fest.
|
||||||
|
# Er sollte nach Projektinitialisierung auf dem tibi-server nicht mehr angepasst werden.
|
||||||
|
# In den Projekteinstellungen im tibi-server kann der Namespace durch einen Datenbankeintrag
|
||||||
|
# überschrieben werden.
|
||||||
|
# Über die Bezeichnung des Namespace plus einen Prefix der in der globalen Server-Konfig
|
||||||
|
# hinterlegt ist, definiert sich der Datenbank-Name innerhalb der MongoDB.
|
||||||
|
namespace: demo
|
||||||
|
|
||||||
|
# Das "meta"-Objekt ist frei definierbar, wird aber vom tibi-admin in spezieller Form erwartet.
|
||||||
|
# Mögliche Angaben, die der tibi-admin versteht, sind hier mit aufgeführt.
|
||||||
|
meta:
|
||||||
|
# OpenAPI Spezifikationen
|
||||||
|
openapi:
|
||||||
|
#info:
|
||||||
|
# title: Demo API
|
||||||
|
# version: 1.0.0
|
||||||
|
# description: Eine Demo-API für den tibi-server
|
||||||
|
servers:
|
||||||
|
- url: https://tibi-admin-server.code.testversion.online/api/v1/_/demo
|
||||||
|
description: code-server
|
||||||
|
|
||||||
|
# Pfad zu einer Bilddatei die als Projektbild im tibi-admin verwendet wird
|
||||||
|
imageUrl:
|
||||||
|
eval: "$projectBase + '_/assets/img/pic.jpg'"
|
||||||
|
|
||||||
|
# Liste möglicher Berechtigungen, die Benutzern zugeordnet werden können
|
||||||
|
permissions:
|
||||||
|
- # Name der Berechtigung
|
||||||
|
name: news
|
||||||
|
# Label für die Anzeige im Admin
|
||||||
|
# (kann string oder object mit Sprachen als keys sein)
|
||||||
|
label:
|
||||||
|
de: Neuigkeiten
|
||||||
|
en: News
|
||||||
|
|
||||||
|
- name: pages
|
||||||
|
label:
|
||||||
|
de: Seiten
|
||||||
|
en: Pages
|
||||||
|
|
||||||
|
# "collections" ist eine Auflistung von Kollektions-Konfigurationen.
|
||||||
|
# Hier bietet sich eine Auslagerung und Einbindung via YAML-Tag "!include" an.
|
||||||
|
collections:
|
||||||
|
- !include collections/democol.yml
|
||||||
|
- !include collections/medialib.yml
|
||||||
|
# Dummy Kollektion für Hooks, die für serverseitiges Rendering benötigt werden
|
||||||
|
- !include collections/ssr.yml
|
||||||
|
|
||||||
|
# Unter "jobs" können Jobs definiert werden, die regelmäßig ausgeführt werden sollen.
|
||||||
|
jobs:
|
||||||
|
- !include jobs/demojob.yml
|
||||||
|
|
||||||
|
# Werden Dateien innerhalb vom tibi-admin benötigt, bietet es sich an diese über
|
||||||
|
# "assets"-Pfade erreichbar zu machen.
|
||||||
|
assets:
|
||||||
|
- !include assets/demoassets.yml
|
||||||
|
- name: img
|
||||||
|
path: img
|
1
api/config.yml.env
Normal file
1
api/config.yml.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
TOKEN=geheim
|
10
api/hooks/config-client.js
Normal file
10
api/hooks/config-client.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const release = "tibi-docs.dirty"
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
if (release && typeof context !== "undefined") {
|
||||||
|
context.response.header("X-Release", release)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
release,
|
||||||
|
}
|
27
api/hooks/config.js
Normal file
27
api/hooks/config.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
module.exports = {
|
||||||
|
ssrValidatePath: function (path) {
|
||||||
|
// validate if path ssr rendering is ok, -1 = NOTFOUND, 0 = NO SSR, 1 = SSR
|
||||||
|
// pe. use context.readCollection("product", {filter: {path: path}}) ... to validate dynamic urls
|
||||||
|
|
||||||
|
// / is de home
|
||||||
|
if (path == "/") return 1
|
||||||
|
|
||||||
|
// all other sites are in db
|
||||||
|
path = path?.replace(/^\//, "")
|
||||||
|
|
||||||
|
// filter for path or alternativePaths
|
||||||
|
const resp = context.db.find("content", {
|
||||||
|
filter: {
|
||||||
|
$or: [{ path }, { "alternativePaths.path": path }],
|
||||||
|
},
|
||||||
|
selector: { _id: 1 },
|
||||||
|
})
|
||||||
|
if (resp && resp.length) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found
|
||||||
|
return -1
|
||||||
|
},
|
||||||
|
ssrAllowedAPIEndpoints: ["content", "medialib"],
|
||||||
|
}
|
0
api/hooks/democol/delete_delete.js
Normal file
0
api/hooks/democol/delete_delete.js
Normal file
0
api/hooks/democol/delete_return.js
Normal file
0
api/hooks/democol/delete_return.js
Normal file
0
api/hooks/democol/get_read.js
Normal file
0
api/hooks/democol/get_read.js
Normal file
0
api/hooks/democol/get_return.js
Normal file
0
api/hooks/democol/get_return.js
Normal file
0
api/hooks/democol/post_bind.js
Normal file
0
api/hooks/democol/post_bind.js
Normal file
0
api/hooks/democol/post_create.js
Normal file
0
api/hooks/democol/post_create.js
Normal file
0
api/hooks/democol/post_return.js
Normal file
0
api/hooks/democol/post_return.js
Normal file
0
api/hooks/democol/post_validate.js
Normal file
0
api/hooks/democol/post_validate.js
Normal file
0
api/hooks/democol/put_bind.js
Normal file
0
api/hooks/democol/put_bind.js
Normal file
0
api/hooks/democol/put_return.js
Normal file
0
api/hooks/democol/put_return.js
Normal file
0
api/hooks/democol/put_update.js
Normal file
0
api/hooks/democol/put_update.js
Normal file
0
api/hooks/democol/put_validate.js
Normal file
0
api/hooks/democol/put_validate.js
Normal file
53
api/hooks/lib/utils.js
Normal file
53
api/hooks/lib/utils.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {any} str
|
||||||
|
*/
|
||||||
|
function log(str) {
|
||||||
|
console.log(JSON.stringify(str, undefined, 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert object to string
|
||||||
|
* @param {any} obj object
|
||||||
|
*/
|
||||||
|
function obj2str(obj) {
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return JSON.stringify(
|
||||||
|
obj.map(function (idx) {
|
||||||
|
return obj2str(idx)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else if (typeof obj === "object" && obj !== null) {
|
||||||
|
var elements = Object.keys(obj)
|
||||||
|
.sort()
|
||||||
|
.map(function (key) {
|
||||||
|
var val = obj2str(obj[key])
|
||||||
|
if (val) {
|
||||||
|
return key + ":" + val
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var elementsCleaned = []
|
||||||
|
for (var i = 0; i < elements.length; i++) {
|
||||||
|
if (elements[i]) elementsCleaned.push(elements[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return "{" + elementsCleaned.join("|") + "}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj) return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear SSR cache
|
||||||
|
*/
|
||||||
|
function clearSSRCache() {
|
||||||
|
var info = context.db.deleteMany("ssr", {})
|
||||||
|
context.response.header("X-SSR-Cleared", info.removed)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
log,
|
||||||
|
clearSSRCache,
|
||||||
|
obj2str,
|
||||||
|
}
|
183
api/hooks/ssr/get_read.js
Normal file
183
api/hooks/ssr/get_read.js
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
const { ssrValidatePath, ssrAllowedAPIEndpoints } = require("../config")
|
||||||
|
|
||||||
|
const { obj2str, log } = require("../lib/utils")
|
||||||
|
;(function () {
|
||||||
|
/** @type {HookResponse} */
|
||||||
|
var response = null
|
||||||
|
|
||||||
|
var request = context.request()
|
||||||
|
var url = request.query("url")
|
||||||
|
var noCache = request.query("noCache")
|
||||||
|
|
||||||
|
// add sentry trace id to head
|
||||||
|
var trace_id = context.debug.sentryTraceId()
|
||||||
|
function addSentryTrace(content) {
|
||||||
|
return content.replace("</head>", '<meta name="sentry-trace" content="' + trace_id + '" /></head>')
|
||||||
|
}
|
||||||
|
context.response.header("sentry-trace", trace_id)
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
// comment will be printed to html later
|
||||||
|
var comment = ""
|
||||||
|
|
||||||
|
url = url.split("?")[0]
|
||||||
|
comment += "url: " + url
|
||||||
|
|
||||||
|
if (url && url.length > 1) {
|
||||||
|
url = url.replace(/\/$/, "")
|
||||||
|
}
|
||||||
|
if (url == "/noindex" || !url) {
|
||||||
|
url = "/" // see .htaccess
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if url is in cache
|
||||||
|
var cache =
|
||||||
|
!noCache &&
|
||||||
|
context.db.find("ssr", {
|
||||||
|
filter: {
|
||||||
|
path: url,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (cache && cache.length) {
|
||||||
|
// use cache
|
||||||
|
throw {
|
||||||
|
status: 200,
|
||||||
|
log: false,
|
||||||
|
html: addSentryTrace(cache[0].content),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate url
|
||||||
|
var status = 200
|
||||||
|
|
||||||
|
var pNorender = false
|
||||||
|
var pNotfound = false
|
||||||
|
|
||||||
|
var pR = ssrValidatePath(url)
|
||||||
|
if (pR < 0) {
|
||||||
|
pNotfound = true
|
||||||
|
} else if (!pR) {
|
||||||
|
pNorender = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var head = ""
|
||||||
|
var html = ""
|
||||||
|
var error = ""
|
||||||
|
|
||||||
|
comment += ", path: " + url
|
||||||
|
|
||||||
|
var cacheIt = false
|
||||||
|
if (pNorender) {
|
||||||
|
html = "<!-- NO SSR RENDERING -->"
|
||||||
|
} else if (pNotfound) {
|
||||||
|
status = 404
|
||||||
|
html = "404 NOT FOUND"
|
||||||
|
} else {
|
||||||
|
// try rendering, if error output plain html
|
||||||
|
try {
|
||||||
|
// @ts-ignore
|
||||||
|
context.ssrCache = {}
|
||||||
|
// @ts-ignore
|
||||||
|
context.ssrFetch = function (endpoint, options) {
|
||||||
|
var data
|
||||||
|
if (ssrAllowedAPIEndpoints.indexOf(endpoint) > -1) {
|
||||||
|
var _options = Object.assign({}, options)
|
||||||
|
|
||||||
|
if (_options.sort) _options.sort = [_options.sort]
|
||||||
|
|
||||||
|
try {
|
||||||
|
/*console.log(
|
||||||
|
"SSR",
|
||||||
|
endpoint,
|
||||||
|
JSON.stringify(_options)
|
||||||
|
)*/
|
||||||
|
var goSlice = context.db.find(endpoint, _options || {})
|
||||||
|
// need to deep copy, so shift and delete on pure js is possible
|
||||||
|
data = JSON.parse(JSON.stringify(goSlice))
|
||||||
|
} catch (e) {
|
||||||
|
console.log("ERROR", JSON.stringify(e))
|
||||||
|
data = []
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("SSR forbidden", endpoint)
|
||||||
|
data = []
|
||||||
|
}
|
||||||
|
|
||||||
|
var count = (data && data.length) || 0
|
||||||
|
if (options && count == options.limit) {
|
||||||
|
// read count from db
|
||||||
|
count = context.db.count(endpoint, _options || {})
|
||||||
|
}
|
||||||
|
var r = { data: data, count: count }
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
context.ssrCache[obj2str({ endpoint: endpoint, options: options })] = r
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// include App.svelte and render it
|
||||||
|
// @ts-ignore
|
||||||
|
var app = require("../lib/app.server")
|
||||||
|
var rendered = app.default.render({
|
||||||
|
url: url,
|
||||||
|
})
|
||||||
|
head = rendered.head
|
||||||
|
html = rendered.html
|
||||||
|
|
||||||
|
// add ssrCache to head
|
||||||
|
head +=
|
||||||
|
"\n\n" +
|
||||||
|
"<script>window.__SSR_CACHE__ = " +
|
||||||
|
// @ts-ignore
|
||||||
|
JSON.stringify(context.ssrCache) +
|
||||||
|
"</script>"
|
||||||
|
|
||||||
|
// status from webapp
|
||||||
|
// @ts-ignore
|
||||||
|
if (context.is404) {
|
||||||
|
status = 404
|
||||||
|
} else {
|
||||||
|
cacheIt = true
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// save error for later insert into html
|
||||||
|
log(e.message)
|
||||||
|
log(e.stack)
|
||||||
|
error = "error: " + e.message + "\n\n" + e.stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read html template and replace placeholders
|
||||||
|
var tpl = context.fs.readFile("templates/spa.html")
|
||||||
|
tpl = tpl.replace("<!--HEAD-->", head)
|
||||||
|
tpl = tpl.replace("<!--HTML-->", html)
|
||||||
|
tpl = tpl.replace("<!--SSR.ERROR-->", error ? "<!--" + error + "-->" : "")
|
||||||
|
tpl = tpl.replace("<!--SSR.COMMENT-->", comment ? "<!--" + comment + "-->" : "")
|
||||||
|
|
||||||
|
// save cache if adviced
|
||||||
|
if (cacheIt && !noCache) {
|
||||||
|
context.db.create("ssr", {
|
||||||
|
path: url,
|
||||||
|
content: tpl,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// return html
|
||||||
|
throw {
|
||||||
|
status: status,
|
||||||
|
log: false,
|
||||||
|
html: addSentryTrace(tpl),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// only admins are allowed to get without url parameter
|
||||||
|
var auth = context.user.auth()
|
||||||
|
if (!auth || auth.role !== 0) {
|
||||||
|
throw {
|
||||||
|
status: 403,
|
||||||
|
message: "invalid auth",
|
||||||
|
auth: auth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
16
api/hooks/ssr/post_bind.js
Normal file
16
api/hooks/ssr/post_bind.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const utils = require("../lib/utils")
|
||||||
|
|
||||||
|
;(function () {
|
||||||
|
if (context.request().query("clear")) {
|
||||||
|
utils.clearSSRCache()
|
||||||
|
throw {
|
||||||
|
status: 200,
|
||||||
|
message: "cache cleared",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw {
|
||||||
|
status: 500,
|
||||||
|
message: "ssr is only a dummy collection",
|
||||||
|
}
|
||||||
|
})()
|
BIN
api/img/pic.jpg
Normal file
BIN
api/img/pic.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 133 KiB |
0
api/jobs/demojob.js
Normal file
0
api/jobs/demojob.js
Normal file
14
api/jobs/demojob.yml
Normal file
14
api/jobs/demojob.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Jedem Job muss ein "cron" Eintrag zugeordnet werden, der die
|
||||||
|
# Ausführungszeitpunkte definiert.
|
||||||
|
# Das cron-Schema ist dem üblichen Linux cron-Schema nachempfunden.
|
||||||
|
cron: "*/10 * * * *"
|
||||||
|
|
||||||
|
# "type" des Jobs ist derzeit immer "javascript" mit der "file"-Referenz
|
||||||
|
# relativ zur "config.yml".
|
||||||
|
type: javascript
|
||||||
|
file: jobs/demojob.js
|
||||||
|
|
||||||
|
# Es können beliebige "meta"-Daten hinterlegt werden, die im Javascript
|
||||||
|
# des Jobs über "context.job.meta" abgerufen werden können.
|
||||||
|
meta:
|
||||||
|
name: Demo Job
|
0
api/templates/email_body.html.tpl
Normal file
0
api/templates/email_body.html.tpl
Normal file
0
api/templates/email_body.txt.tpl
Normal file
0
api/templates/email_body.txt.tpl
Normal file
0
api/templates/email_subject.txt.tpl
Normal file
0
api/templates/email_subject.txt.tpl
Normal file
20
babel.config.json
Normal file
20
babel.config.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"sourceMaps": "inline",
|
||||||
|
"inputSourceMap": true,
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
"useBuiltIns": "usage",
|
||||||
|
"corejs": {
|
||||||
|
"version": "3",
|
||||||
|
"proposals": true
|
||||||
|
},
|
||||||
|
"targets": ">0.5%, IE 11, not dead",
|
||||||
|
"debug": true,
|
||||||
|
"forceAllTransforms": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"plugins": []
|
||||||
|
}
|
178
docker-compose-local.yml
Normal file
178
docker-compose-local.yml
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
version: "3.8"
|
||||||
|
name: tibi-docs
|
||||||
|
|
||||||
|
services:
|
||||||
|
docpress:
|
||||||
|
profiles:
|
||||||
|
- docpress
|
||||||
|
image: node:18
|
||||||
|
volumes:
|
||||||
|
- ./:/data
|
||||||
|
- ./tmp:/tmp
|
||||||
|
- ./tmp/nonexistent:/nonexistent
|
||||||
|
working_dir: /data/docs
|
||||||
|
command: sh -c "yarn install && yarn docpress:serve"
|
||||||
|
expose:
|
||||||
|
- 3000
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}-docpress
|
||||||
|
user: ${UID}:${GID}
|
||||||
|
|
||||||
|
yarnstart:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
- tibi-dev
|
||||||
|
image: node:18
|
||||||
|
volumes:
|
||||||
|
- ./:/data
|
||||||
|
- ./tmp:/tmp
|
||||||
|
- ./tmp/nonexistent:/nonexistent
|
||||||
|
working_dir: /data
|
||||||
|
command: sh -c "yarn install && API_BASE=http://tibiserver:8080/api/v1/_/${TIBI_NAMESPACE} yarn start"
|
||||||
|
expose:
|
||||||
|
- 3000
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}
|
||||||
|
- traefik.http.routers.${PROJECT_NAME}-yarnstart.middlewares=${PROJECT_NAME}-yarnstart
|
||||||
|
- traefik.http.middlewares.${PROJECT_NAME}-yarnstart.basicauth.usersfile=${PWD}/.basic-auth-web
|
||||||
|
user: ${UID}:${GID}
|
||||||
|
|
||||||
|
tibiserver:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
image: gitbase.de/cms/tibi-server
|
||||||
|
volumes:
|
||||||
|
- ./:/data
|
||||||
|
environment:
|
||||||
|
DB_DIAL: mongodb://mongo
|
||||||
|
DB_PREFIX: ${TIBI_PREFIX}
|
||||||
|
MAIL_HOST: maildev:25
|
||||||
|
SECURITY_ALLOWABSOLUTEPATHS: "true"
|
||||||
|
SECURITY_ALLOWUPPERPATHS: "true"
|
||||||
|
depends_on:
|
||||||
|
- mongo
|
||||||
|
expose:
|
||||||
|
- 8080
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.services.${PROJECT_NAME}-tibiserver.loadbalancer.server.port=8080
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiserver
|
||||||
|
|
||||||
|
tibiserver-dev:
|
||||||
|
hostname: tibiserver
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
dockerfile: ./../../cms/tibi-server/Dockerfile.air
|
||||||
|
profiles:
|
||||||
|
- tibi-dev
|
||||||
|
volumes:
|
||||||
|
- ./:/data
|
||||||
|
- ./../../cms/tibi-server:/tibi-server
|
||||||
|
- ./../../../../tmp/go/pkg:/go/pkg
|
||||||
|
working_dir: /tibi-server
|
||||||
|
environment:
|
||||||
|
GOCACHE: /tmp/
|
||||||
|
DB_DIAL: mongodb://mongo
|
||||||
|
DB_PREFIX: ${TIBI_PREFIX}
|
||||||
|
MAIL_HOST: maildev:25
|
||||||
|
SECURITY_ALLOWABSOLUTEPATHS: "true"
|
||||||
|
SECURITY_ALLOWUPPERPATHS: "true"
|
||||||
|
depends_on:
|
||||||
|
- mongo
|
||||||
|
user: ${UID}:${GID}
|
||||||
|
expose:
|
||||||
|
- 8080
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.services.${PROJECT_NAME}-tibiserver.loadbalancer.server.port=8080
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiserver
|
||||||
|
|
||||||
|
tibiadmin:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
image: gitbase.de/cms/tibi-admin
|
||||||
|
environment:
|
||||||
|
INDEX: spa.html
|
||||||
|
WEBROOT: /data
|
||||||
|
API: /api:http://tibiserver:8080/api/v1
|
||||||
|
PORT: 80
|
||||||
|
depends_on:
|
||||||
|
- tibiserver
|
||||||
|
expose:
|
||||||
|
- 80
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiadmin
|
||||||
|
- traefik.http.routers.${PROJECT_NAME}-tibiadmin.middlewares=${PROJECT_NAME}-tibiadmin
|
||||||
|
- traefik.http.middlewares.${PROJECT_NAME}-tibiadmin.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||||
|
|
||||||
|
tibiadmin-dev:
|
||||||
|
profiles:
|
||||||
|
- tibi-dev
|
||||||
|
image: node:18
|
||||||
|
volumes:
|
||||||
|
- ./../../cms/tibi-admin:/data
|
||||||
|
working_dir: /data
|
||||||
|
command: sh -c "yarn install && API_BASE=http://tibiserver:8080/api/v1 yarn start:code-server"
|
||||||
|
expose:
|
||||||
|
- 3000
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiadmin-dev
|
||||||
|
- traefik.http.routers.${PROJECT_NAME}-tibiadmin-dev.middlewares=${PROJECT_NAME}-tibiadmin-dev
|
||||||
|
- traefik.http.middlewares.${PROJECT_NAME}-tibiadmin-dev.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||||
|
user: ${UID}:${GID}
|
||||||
|
|
||||||
|
mongo:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
- tibi-dev
|
||||||
|
image: gitbase.de/server/mongo:4.2
|
||||||
|
volumes:
|
||||||
|
- ./tmp/mongo-data:/data/db
|
||||||
|
user: ${UID}:${GID}
|
||||||
|
|
||||||
|
adminmongo:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
- tibi-dev
|
||||||
|
image: gitbase.de/server/adminmongo
|
||||||
|
environment:
|
||||||
|
CONN_NAME: mongo
|
||||||
|
DB_HOST: mongo
|
||||||
|
PORT: 1234
|
||||||
|
expose:
|
||||||
|
- 1234
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}-adminmongo
|
||||||
|
- traefik.http.routers.${PROJECT_NAME}-adminmongo.middlewares=${PROJECT_NAME}-adminmongo
|
||||||
|
- traefik.http.middlewares.${PROJECT_NAME}-adminmongo.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||||
|
|
||||||
|
maildev:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
- tibi-dev
|
||||||
|
image: maildev/maildev
|
||||||
|
command: node bin/maildev --web 1080 --smtp 25 -v --hide-extensions=STARTTLS
|
||||||
|
expose:
|
||||||
|
- 1080
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}-maildev
|
||||||
|
- traefik.http.services.${PROJECT_NAME}-maildev.loadbalancer.server.port=1080
|
||||||
|
- traefik.http.routers.${PROJECT_NAME}-maildev.middlewares=${PROJECT_NAME}-maildev
|
||||||
|
- traefik.http.middlewares.${PROJECT_NAME}-maildev.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||||
|
|
||||||
|
chisel:
|
||||||
|
profiles:
|
||||||
|
- chisel
|
||||||
|
image: jpillora/chisel
|
||||||
|
expose:
|
||||||
|
- 8080
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- online.testversion.code.subdomain=${PROJECT_NAME}-chisel
|
||||||
|
command: server --port 8080 --auth coder:coder
|
21
docs/README.md
Normal file
21
docs/README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# TibiCMS Dokumentation
|
||||||
|
|
||||||
|
![TibiCMS Aufbau](./md/tibi-aufbau.svg)
|
||||||
|
|
||||||
|
## Einleitung
|
||||||
|
|
||||||
|
_TibiCMS_ ist der Sammelbegriff für die Komponenten _tibi-server_ und _tibi-admin_, welche einen Rest-API Server und eine Administrationsoberfläche zur Verfügung stellen. Auf Basis dieser beiden Komponenten und der _MongoDB_ als Abhängigkeit lassen sich WebCMS Anwendungen abbilden.
|
||||||
|
|
||||||
|
Das CMS ist multi-mandanten-fähig, d.h. es kann mehrer Projekte mit unterschiedlichen Zugriffsbeschränkungen verwalten.
|
||||||
|
|
||||||
|
### tibi-server
|
||||||
|
|
||||||
|
Der Server selbst kommt ohne grafische Oberfläche oder WebUI. Er ist ausschließlich nach außen über eine Rest-API erreichbar.
|
||||||
|
|
||||||
|
Als einzige Abhängigkeit ist eine _MongoDB_ zu erwähnen. Da der Server in Go geschrieben ist, sind keine externen Bibliotheken notwendig. Er lässt sich daher prima via Docker-Container verteilen.
|
||||||
|
|
||||||
|
### tibi-admin
|
||||||
|
|
||||||
|
Die Administrationsoberfläche ist wie jeder andere Service, der die Rest-API des Servers nutzt, nur ein Frontend. _tibi-admin_ läuft vollständig im Browser und benötigt nur einen Webserver, der statischen Content ausliefert.
|
||||||
|
|
||||||
|
Die Version des _tibi-admin_ sollte synchron zur _tibi-server_ Version gehalten werden, damit alle Datentypen bedient werden können.
|
9
docs/docpress.json
Normal file
9
docs/docpress.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"docs": "md",
|
||||||
|
"markdown": {
|
||||||
|
"plugins": {
|
||||||
|
"code-include": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"css": ["md/docpress.css", "md/github-dark-dimmed.css"]
|
||||||
|
}
|
106
docs/markdown-it-code-include/index.js
Normal file
106
docs/markdown-it-code-include/index.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const INCLUDE_RE = /!{3}\s*include(.+?)!{3}/i;
|
||||||
|
const BRACES_RE = /\((.+?)\)/i;
|
||||||
|
|
||||||
|
const include_plugin = (md, options) => {
|
||||||
|
const defaultOptions = {
|
||||||
|
root: '.',
|
||||||
|
getRootDir: (pluginOptions/*, state, startLine, endLine*/) => pluginOptions.root,
|
||||||
|
includeRe: INCLUDE_RE,
|
||||||
|
throwError: false,
|
||||||
|
bracesAreOptional: false,
|
||||||
|
notFoundMessage: 'File \'{{FILE}}\' not found.',
|
||||||
|
circularMessage: 'Circular reference between \'{{FILE}}\' and \'{{PARENT}}\'.'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof options === 'string') {
|
||||||
|
options = {
|
||||||
|
...defaultOptions,
|
||||||
|
root: options
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
options = {
|
||||||
|
...defaultOptions,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const _replaceIncludeByContent = (src, rootdir, parentFilePath, filesProcessed) => {
|
||||||
|
filesProcessed = filesProcessed ? filesProcessed.slice() : []; // making a copy
|
||||||
|
let cap, filePath, mdSrc, errorMessage;
|
||||||
|
|
||||||
|
// store parent file path to check circular references
|
||||||
|
if (parentFilePath) {
|
||||||
|
filesProcessed.push(parentFilePath);
|
||||||
|
}
|
||||||
|
while ((cap = options.includeRe.exec(src))) {
|
||||||
|
let includePath = cap[1].trim();
|
||||||
|
const sansBracesMatch = BRACES_RE.exec(includePath);
|
||||||
|
|
||||||
|
if (!sansBracesMatch && !options.bracesAreOptional) {
|
||||||
|
errorMessage = `INCLUDE statement '${src.trim()}' MUST have '()' braces around the include path ('${includePath}')`;
|
||||||
|
} else if (sansBracesMatch) {
|
||||||
|
includePath = sansBracesMatch[1].trim();
|
||||||
|
} else if (!/^\s/.test(cap[1])) {
|
||||||
|
// path SHOULD have been preceeded by at least ONE whitespace character!
|
||||||
|
/* eslint max-len: "off" */
|
||||||
|
errorMessage = `INCLUDE statement '${src.trim()}': when not using braces around the path ('${includePath}'), it MUST be preceeded by at least one whitespace character to separate the include keyword and the include path.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errorMessage) {
|
||||||
|
filePath = path.resolve(rootdir, includePath);
|
||||||
|
|
||||||
|
// check if child file exists or if there is a circular reference
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
// child file does not exist
|
||||||
|
errorMessage = options.notFoundMessage.replace('{{FILE}}', filePath);
|
||||||
|
} else if (filesProcessed.indexOf(filePath) !== -1) {
|
||||||
|
// reference would be circular
|
||||||
|
errorMessage = options.circularMessage.replace('{{FILE}}', filePath).replace('{{PARENT}}', parentFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if there were any errors
|
||||||
|
if (errorMessage) {
|
||||||
|
if (options.throwError) {
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
}
|
||||||
|
mdSrc = `\n\n# INCLUDE ERROR: ${errorMessage}\n\n`;
|
||||||
|
} else {
|
||||||
|
// get content of child file
|
||||||
|
mdSrc = fs.readFileSync(filePath, 'utf8');
|
||||||
|
// check if child file also has includes
|
||||||
|
mdSrc = _replaceIncludeByContent(mdSrc, path.dirname(filePath), filePath, filesProcessed);
|
||||||
|
// remove one trailing newline, if it exists: that way, the included content does NOT
|
||||||
|
// automatically terminate the paragraph it is in due to the writer of the included
|
||||||
|
// part having terminated the content with a newline.
|
||||||
|
// However, when that snippet writer terminated with TWO (or more) newlines, these, minus one,
|
||||||
|
// will be merged with the newline after the #include statement, resulting in a 2-NL paragraph
|
||||||
|
// termination.
|
||||||
|
const len = mdSrc.length;
|
||||||
|
if (mdSrc[len - 1] === '\n') {
|
||||||
|
mdSrc = mdSrc.substring(0, len - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const labelStyle = `padding: 0 4px; font-size: 12px; font-weight: bold; color: #ffffff; background: #444444; opacity: .6;`
|
||||||
|
|
||||||
|
const fileLabel = `<div style="position:relative; height: 0px;"><div class="code-file-label" style="position:absolute; top: -10px;${labelStyle}">${includePath}</div></div>\n\n`
|
||||||
|
const fileExt = includePath.replace(/^.+\./, "")
|
||||||
|
|
||||||
|
// replace include by file content
|
||||||
|
src = src.slice(0, cap.index) + fileLabel + "```" + fileExt + "\n" + mdSrc + "\n```" + src.slice(cap.index + cap[0].length, src.length);
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
};
|
||||||
|
|
||||||
|
const _includeFileParts = (state, startLine, endLine/*, silent*/) => {
|
||||||
|
state.src = _replaceIncludeByContent(state.src, options.getRootDir(options, state, startLine, endLine));
|
||||||
|
};
|
||||||
|
|
||||||
|
md.core.ruler.before('normalize', 'include', _includeFileParts);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = include_plugin;
|
24
docs/markdown-it-code-include/package.json
Normal file
24
docs/markdown-it-code-include/package.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "markdown-it-code-include",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "A markdown-it plugin to include code blocks.",
|
||||||
|
"main": "./index.js",
|
||||||
|
"scripts": {
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"markdown",
|
||||||
|
"markdown-it",
|
||||||
|
"markdown-it-plugin",
|
||||||
|
"code-blocks",
|
||||||
|
"fence"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-html-parser": "^1.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"markdown-it": "^12.0.0",
|
||||||
|
"markdown-it-testgen": "^0.1.6",
|
||||||
|
"path": "^0.12.7"
|
||||||
|
}
|
||||||
|
}
|
50
docs/md/README.md
Normal file
50
docs/md/README.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
- [TibiCMS](../README.md)
|
||||||
|
- [Begriffe](begriffe.md)
|
||||||
|
- Servergrundlagen
|
||||||
|
- [Konfiguration](servergrundlagen/konfiguration.md)
|
||||||
|
- [Entitäten](servergrundlagen/entitaeten.md)
|
||||||
|
- RestAPI Endpunkte
|
||||||
|
- [/login](restapi/login.md)
|
||||||
|
- [/user](restapi/user.md)
|
||||||
|
- [/project](restapi/project.md)
|
||||||
|
- [/_/NS/COLLECTION](restapi/collection.md)
|
||||||
|
- [/_/NS/_/assets/ASSETSNAME](restapi/assets.md)
|
||||||
|
- Projekt Konfiguration
|
||||||
|
- [Ordnerstruktur](projektkonfig/ordnerstruktur.md)
|
||||||
|
- [config.yml](projektkonfig/config.yml.md)
|
||||||
|
- [collections](projektkonfig/collections.md)
|
||||||
|
- [fields](projektkonfig/collections/fields.md)
|
||||||
|
- [Datentypen](projektkonfig/collections/fields/datentypen.md)
|
||||||
|
- [Admin Widgets](projektkonfig/collections/fields/widgets.md)
|
||||||
|
- [· ContentBuilder](projektkonfig/collections/fields/widgets/contentbuilder.md)
|
||||||
|
- [indexes](projektkonfig/collections/indexes.md)
|
||||||
|
- [hooks](projektkonfig/collections/hooks.md)
|
||||||
|
- [imageFilter](projektkonfig/collections/imageFilter.md)
|
||||||
|
- [meta](projektkonfig/collections/meta.md)
|
||||||
|
- [jobs](projektkonfig/jobs.md)
|
||||||
|
- [assets](projektkonfig/assets.md)
|
||||||
|
- Admin Javascript Kontext
|
||||||
|
- [Allgemeines](admin-javascript-kontext/allgemeines.md)
|
||||||
|
- [collection.meta..eval](admin-javascript-kontext/collection.meta..eval.md)
|
||||||
|
- [field.meta..eval](admin-javascript-kontext/field.meta..eval.md)
|
||||||
|
- Server Javascript Kontext
|
||||||
|
- [Allgmeines](server-javascript-kontext/allgemeines.md)
|
||||||
|
- [hook](server-javascript-kontext/hook.md)
|
||||||
|
- [job](server-javascript-kontext/job.md)
|
||||||
|
- [validator](server-javascript-kontext/validator.md)
|
||||||
|
- Packages
|
||||||
|
- [user](server-javascript-kontext/packages/user.md)
|
||||||
|
- [response](server-javascript-kontext/packages/response.md)
|
||||||
|
- [cookie](server-javascript-kontext/packages/cookie.md)
|
||||||
|
- [db](server-javascript-kontext/packages/db.md)
|
||||||
|
- [http](server-javascript-kontext/packages/http.md)
|
||||||
|
- [smtp](server-javascript-kontext/packages/smtp.md)
|
||||||
|
- [fs](server-javascript-kontext/packages/fs.md)
|
||||||
|
- [tpl](server-javascript-kontext/packages/tpl.md)
|
||||||
|
- [jwt](server-javascript-kontext/packages/jwt.md)
|
||||||
|
- [image](server-javascript-kontext/packages/image.md)
|
||||||
|
- [bcrypt](server-javascript-kontext/packages/bcrypt.md)
|
||||||
|
- [xml](server-javascript-kontext/packages/xml.md)
|
||||||
|
- [charset](server-javascript-kontext/packages/charset.md)
|
||||||
|
- [pdf](server-javascript-kontext/packages/pdf.md)
|
||||||
|
- [debug](server-javascript-kontext/packages/debug.md)
|
47
docs/md/admin-javascript-kontext/allgemeines.md
Normal file
47
docs/md/admin-javascript-kontext/allgemeines.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Javascript-Kontext im tibi-admin
|
||||||
|
|
||||||
|
Diverse `meta`-Angaben ermöglichen neben der eigentliche Angabe eines festen Wertes wie z.B:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
defaultValue: "Hallo Welt"
|
||||||
|
```
|
||||||
|
|
||||||
|
auch die Angabe eines Javascript-Ausdrucks, der zur Laufzeit ausgewertet wird. Dieser Ausdruck wird in einem Javascript-Kontext clientseitig ausgeführt und ist mit diversen Variablen vorbelegt.
|
||||||
|
Die Angabe des Javascript-Codes erfolgt dabei meist mit dem `eval`-Attribut dessen Wert der String des Codes ist:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
defaultValue:
|
||||||
|
eval: "new Date().toISOString().substr(0, 10)"
|
||||||
|
```
|
||||||
|
|
||||||
|
In den Fällen in denen ein Oneliner nicht ausreiched ist, bieten sich "selbst ausführende Funktionen" an, wie z.B.:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(function() {
|
||||||
|
return new Date().toISOString().substr(0, 10)
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
Um diese im YAML unterzubringen nutzt man YAML-Multiline-Modifizierer:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
defaultValue:
|
||||||
|
eval: |
|
||||||
|
(function() {
|
||||||
|
return new Date().toISOString().substr(0, 10)
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kontext-Variablen
|
||||||
|
|
||||||
|
Der Javascript-Kontext ist mit folgenden Variablen standardmäßig angereichert:
|
||||||
|
|
||||||
|
| Variable | Datentyp | Bedeutung |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `$namespace` | string | Der Namespacebezeichner des aktuellen Projekts |
|
||||||
|
| `$apiBase` | string | Basis-URL des API-Endpunkts |
|
||||||
|
| `$projectBase` | string | Basis-URL des Projekts-API-Endpunkts (`$apiBase`_/`$namespace`/) |
|
||||||
|
| `$auth` TODO | object | Das aktuelle Auth-Objetc des eingeloggten Benutzers |
|
||||||
|
| `$project` | object | Das aktuelle Projekt-Objekt, siehe [API /project](./../restapi/project.md) |
|
||||||
|
|
||||||
|
Die `meta`-Daten der Collections und Fields bekommen in den Javascript-Kontext der `eval`-Eigenschaften noch jeweils zusätzliche Variablen.
|
@ -0,0 +1,9 @@
|
|||||||
|
# collection.meta..eval Javascript-Kontext
|
||||||
|
|
||||||
|
Die `eval`-Properties der Eigenschaften (wo möglich) bekommen unterhalb des `collection.meta`-Objektes zusätzlich zu den bereits bekannten Variablen (siehe [Allgemeines zum Kontext](./allgemeines.md)) folgende Variable zur Verfügung:
|
||||||
|
|
||||||
|
|
||||||
|
| Variable | Datentyp | Bedeutung |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `$object` | object | Das aktuelle Kollektion-Objekt, siehe [API /collection](./../restapi/collection.md) |
|
||||||
|
| `$navigation` | object | Das aktuelle Navigation-Objekt, also den entsprechenden aktiven Eintrag aus `meta.subNavigation` |
|
104
docs/md/admin-javascript-kontext/field.meta..eval.md
Normal file
104
docs/md/admin-javascript-kontext/field.meta..eval.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# field.meta..eval Javascript-Kontext
|
||||||
|
|
||||||
|
Zuätzlich zu den allgemeinen und Kollektions-spezifischen Variablen, die im Javascript-Kontext der `eval`-Eigenschaften unterhalb des zur Verfügung stehen, gibt es noch folgende Variablen unterhalb des `field.meta`-Objektes für die Evaluierung:
|
||||||
|
|
||||||
|
| Variable | Datentyp | Bedeutung |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `$field` TODO | object | Das aktuelle Feld-Objekt |
|
||||||
|
| `$method` | `"post"`/`"put"` | `"put"` bedeuted, dass der Datensatz gerade in Bearbeitung ist, `"post"` = Datensatz soll angelegt werden |
|
||||||
|
| `$this` | any | Der aktuelle Wert des Feldes |
|
||||||
|
| `$` | object | Das gesamte Objekt des Dokuments |
|
||||||
|
| `$parent` | object oder array | Der Wert des Elternknotens zum aktuellen Feld |
|
||||||
|
| `$stack` | array | Der Stack bis zum Ursprung des gesamten Objekts |
|
||||||
|
|
||||||
|
## Der Stack
|
||||||
|
|
||||||
|
Um die Abhängigkeiten zu bestimmten Werten ausdrücken zu können (z.B. in `meta.dependsOn.eval`), sind die Variablen `$this`, `$`, `$parent` und `$stack` verfügbar.
|
||||||
|
|
||||||
|
Folgendes Beispiel eines Datensatzes verdeutlicht die Belegung, während die Maske zum Editieren im *tibi-admin* geöffnet ist:
|
||||||
|
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "Mein Datensatz",
|
||||||
|
"meta": {
|
||||||
|
"keywords": [
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "blup",
|
||||||
|
"description": "Buh Blup"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
wobei wir den `"key": "pla"` betrachten, wären die Inhalte der Variablen folgende:
|
||||||
|
|
||||||
|
`$this`:
|
||||||
|
|
||||||
|
plah
|
||||||
|
|
||||||
|
`$parent` und `$stack[0]`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`$stack[1]`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "blup",
|
||||||
|
"description": "Buh Blup"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
`$stack[2]`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "blup",
|
||||||
|
"description": "Buh Blup"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`$stack[3]`, `entry` und `$`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "Mein Datensatz",
|
||||||
|
"meta": {
|
||||||
|
"keywords": [
|
||||||
|
{
|
||||||
|
"key": "pla",
|
||||||
|
"description": "Ah Plah"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "blup",
|
||||||
|
"description": "Buh Blup"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
53
docs/md/begriffe.md
Normal file
53
docs/md/begriffe.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Begriffe
|
||||||
|
|
||||||
|
## TibiCMS
|
||||||
|
|
||||||
|
Oberbegriff der den gesamten Stack, bestehend aus *tibi-server* mit *MongoDB** und *tibi-admin* beschreibt.
|
||||||
|
|
||||||
|
## tibi-server
|
||||||
|
|
||||||
|
Rest-API Server des *TibiCMS* Stack
|
||||||
|
|
||||||
|
## tibi-admin
|
||||||
|
|
||||||
|
Admin-UI/Backend zur Verwaltung der Inhalte im *tibi-server*
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
Schnittstelle (hier Rest-API) des *tibi-server* (im Projektkontext ebenso für Projektspezifische Schnittstelle vrwendet)
|
||||||
|
|
||||||
|
## project / Projekt
|
||||||
|
|
||||||
|
Projekt innerhalb des *TibiCMS* welches üblicherweise die Datengrundlage für eine Website im *TibiCMS* ist
|
||||||
|
|
||||||
|
## collection / Kollektion
|
||||||
|
|
||||||
|
Datensammlung innerhalb eines Projekte (z.B. Newsartikel), in relationalen Datenbanken oft eine Tabelle
|
||||||
|
|
||||||
|
## field / Feld
|
||||||
|
|
||||||
|
Ein Datenfeld innerhalb einer Kollektion mit einem bestimmten Datentyp (z.B. string, number, ...)
|
||||||
|
|
||||||
|
## validator / Validator
|
||||||
|
|
||||||
|
Code oder Anweisung zur Überprüfung der Gültigkeit von Feld-Daten
|
||||||
|
|
||||||
|
## filter / Filter
|
||||||
|
|
||||||
|
Bildfilter zum Verkleinern oder Bearbeiten von Bildern beim Abruf von der API
|
||||||
|
|
||||||
|
## projection / Projektion
|
||||||
|
|
||||||
|
Abbildung der Daten auf ein Subset der Originaldaten
|
||||||
|
|
||||||
|
## hook
|
||||||
|
|
||||||
|
Vorerst nur in Javascript geschriebene Algorithmen, die die sich in die API einklinken um Daten oder Abläufe zu manipulieren
|
||||||
|
|
||||||
|
## user / Benutzer
|
||||||
|
|
||||||
|
Ein Benutzer mit Login innerhalb des *TibiCMS*
|
||||||
|
|
||||||
|
## permission / Berechtigung
|
||||||
|
|
||||||
|
Berechtigung innerhalb eines Projektes, welche einem Benutzer zugeordnet werden kann
|
34
docs/md/docpress.css
Normal file
34
docs/md/docpress.css
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
.title, h1, h2, h3, h4, h5, .link.title.link-index {
|
||||||
|
color: #531414!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link.title {
|
||||||
|
color: black!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-menu .link.-active, .toc-menu .hlink.-active {
|
||||||
|
box-shadow: inset -2px 0 #7c2828!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.heading-list .hlink, ul.heading-list .hlink:visited {
|
||||||
|
color: #414141!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-toggle:hover, .footer-nav a:hover, .footer-nav a:hover:after, .footer-nav a:hover:before {
|
||||||
|
color: #7c2828!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-file-label {
|
||||||
|
background: #dcd9d9!important;
|
||||||
|
color: #3a0909!important;
|
||||||
|
right: 0px;
|
||||||
|
opacity: 1!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #7c2828!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color:#3a0909!important;
|
||||||
|
}
|
130
docs/md/github-dark-dimmed.css
Normal file
130
docs/md/github-dark-dimmed.css
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*!
|
||||||
|
Theme: GitHub Dark Dimmed
|
||||||
|
Description: Dark dimmed theme as seen on github.com
|
||||||
|
Author: github.com
|
||||||
|
Maintainer: @Hirse
|
||||||
|
Updated: 2021-05-15
|
||||||
|
|
||||||
|
Colors taken from GitHub's CSS
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs, pre, pre code {
|
||||||
|
color: #adbac7!important;
|
||||||
|
background: #22272e!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-doctag,
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-meta .hljs-keyword,
|
||||||
|
.hljs-template-tag,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-variable.language_,
|
||||||
|
.pl-k {
|
||||||
|
/* prettylights-syntax-keyword */
|
||||||
|
color: #f47067!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-title.class_,
|
||||||
|
.hljs-title.class_.inherited__,
|
||||||
|
.hljs-title.function_i,
|
||||||
|
.pl-s {
|
||||||
|
/* prettylights-syntax-entity */
|
||||||
|
color: #dcbdfb!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attr,
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-meta,
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-operator,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-class,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.pl-e {
|
||||||
|
/* prettylights-syntax-constant */
|
||||||
|
color: #6cb6ff!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-regexp,
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-meta .hljs-string,
|
||||||
|
.pl-s {
|
||||||
|
/* prettylights-syntax-string */
|
||||||
|
color: #96d0ff!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-symbol,
|
||||||
|
.pl-c1 {
|
||||||
|
/* prettylights-syntax-variable */
|
||||||
|
color: #f69d50!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-code,
|
||||||
|
.hljs-formula,
|
||||||
|
.pl-c {
|
||||||
|
/* prettylights-syntax-comment */
|
||||||
|
color: #768390!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-quote,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-selector-pseudo {
|
||||||
|
/* prettylights-syntax-entity-tag */
|
||||||
|
color: #8ddb8c!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-subst {
|
||||||
|
/* prettylights-syntax-storage-modifier-import */
|
||||||
|
color: #adbac7!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-section {
|
||||||
|
/* prettylights-syntax-markup-heading */
|
||||||
|
color: #316dca!important;
|
||||||
|
font-weight: bold!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-bullet {
|
||||||
|
/* prettylights-syntax-markup-list */
|
||||||
|
color: #eac55f!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
/* prettylights-syntax-markup-italic */
|
||||||
|
color: #adbac7!important;
|
||||||
|
font-style: italic!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-strong {
|
||||||
|
/* prettylights-syntax-markup-bold */
|
||||||
|
color: #adbac7!important;
|
||||||
|
font-weight: bold!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
/* prettylights-syntax-markup-inserted */
|
||||||
|
color: #b4f1b4!important;
|
||||||
|
background-color: #1b4721!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
/* prettylights-syntax-markup-deleted */
|
||||||
|
color: #ffd8d3!important;
|
||||||
|
background-color: #78191b!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-char.escape_,
|
||||||
|
.hljs-link,
|
||||||
|
.hljs-params,
|
||||||
|
.hljs-property,
|
||||||
|
.hljs-punctuation,
|
||||||
|
.hljs-tag {
|
||||||
|
/* purposely ignored */
|
||||||
|
}
|
BIN
docs/md/projektkonfig/api-ordner.png
Normal file
BIN
docs/md/projektkonfig/api-ordner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
6
docs/md/projektkonfig/assets.md
Normal file
6
docs/md/projektkonfig/assets.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# assets
|
||||||
|
|
||||||
|
Folgende Angaben sind in der `assets`-Sektion der [config.yml](./config.yml.md) geführt als Liste möglich:
|
||||||
|
|
||||||
|
|
||||||
|
!!!include(../api/assets/demoassets.yml)!!!
|
17
docs/md/projektkonfig/collections.md
Normal file
17
docs/md/projektkonfig/collections.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# collections
|
||||||
|
|
||||||
|
Die Konfiguration einer Kollektion sollte zur besseren Übersicht innerhalb einer gesonderten Datei im Unterorder **api/collections/** erfolgen und via `!include` in die [config.yml](./config.yml.md) eingebunden werden.
|
||||||
|
|
||||||
|
## Grundlegender Aufbau
|
||||||
|
|
||||||
|
Eine solche Datei hat folgenden Aufbau:
|
||||||
|
|
||||||
|
!!!include(../api/collections/democol.yml)!!!
|
||||||
|
|
||||||
|
### siehe
|
||||||
|
|
||||||
|
- [fields](./collections/fields.md)
|
||||||
|
- [indexes](./collections/indexes.md)
|
||||||
|
- [hooks](./collections/hooks.md)
|
||||||
|
- [imageFilter](./collections/imageFilter.md)
|
||||||
|
- [meta](./collections/meta.md)
|
BIN
docs/md/projektkonfig/collections/dependsOn.webm
Normal file
BIN
docs/md/projektkonfig/collections/dependsOn.webm
Normal file
Binary file not shown.
120
docs/md/projektkonfig/collections/fields.md
Normal file
120
docs/md/projektkonfig/collections/fields.md
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# fields
|
||||||
|
|
||||||
|
Felder im _tibi-server_ müssen einen bestimmten Datentyp haben. Über den _tibi-admin_ können die Felder über Widgets in unterschiedlichen Ausprägungen dargestellt werden (view-Widgets), bzw. dem Benutzer eine Eingabe abverlangen (input-Widgets).
|
||||||
|
|
||||||
|
Es gibt grundlegende Angaben, die jedes Feld haben muss um vom _tibi-server_ akzeptiert zu werden. Darüber hinaus kann auch jedes Feld ein `meta` Objekt haben, was dem _tibi-admin_ mitteilt, wie er dieses Feld für Ausgabe und Eingabe behandel soll.
|
||||||
|
|
||||||
|
Zunächst folgt der grundlegende Aufbau des Feld-Objektes:
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/date.yml)!!!
|
||||||
|
|
||||||
|
## validator Objekt
|
||||||
|
|
||||||
|
<video width="100%" controls muted autoplay loop>
|
||||||
|
<source src="validator.webm" type="video/webm">
|
||||||
|
</video>
|
||||||
|
|
||||||
|
Wie im Beispiel von **fields/date.yml** unter `validator` zu sehen ist, wird dort ein Datum nach dem aktuellen erwartet. Wie der Validator sich auf die UI auswirkt, ist im obigen Video zu sehen.
|
||||||
|
|
||||||
|
Das `validator` Objekt wird _tibi-server_ seitig genutzt um die Daten zu validieren. Da das `validator` Objekt dem _tibi-admin_ ebenso zur Verfügung steht, kann vorab eine client-seitige Validierung zusätzlich durchgeführt werden.
|
||||||
|
|
||||||
|
Attribute des Objektes:
|
||||||
|
|
||||||
|
| Attribut | Datentyp | Beschreibung |
|
||||||
|
| ----------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `required` | boolean | wenn `true`, dann ist zwingend eine Eingabe zu diesem Feld nötig |
|
||||||
|
| `allowZero` | boolean | in Kombination mit `required: true`, wenn `true`, dann ist der jeweilige "Null"-Wert des Datentyps erlaubt<br><br>z.B. `type: string` erlaubt den leeren String und `type: number` erlaubt `0` |
|
||||||
|
| `eval` | string | Javascript-Code der zu true evaluieren muss um den Wert des Feldes als gültig zu definieren |
|
||||||
|
|
||||||
|
### eval-Attribut
|
||||||
|
|
||||||
|
Der Javascript-Code in diesem Attribut kann folgende Rückgabe-Werte haben:
|
||||||
|
|
||||||
|
| Wert | Bedeutung |
|
||||||
|
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| `true` | Der Wert des Feldes ist gültig |
|
||||||
|
| `false` | Der Wert des Feldes ist ungültig |
|
||||||
|
| `"Text"` | Wird ein String zurückgegeben ist, wird der Wert es Feldes ebenso als ungültig erachtet und der String selbst ist eine benutzerdefinierte Fehlermeldung, die in der Serverantwort gelesen werden kann. |
|
||||||
|
|
||||||
|
Da der `eval` Code serverseitig immer ausgeführt wird und ein Fehlschlag zwangsläufig zum Abbruch der Serveraktion führt, ist es wichtig, dass der [serverseitige Javascript-Kontext](./../../server-javascript-kontext/validator.md) berücksichtigt wird.
|
||||||
|
|
||||||
|
Optional kann der Code auch zusätzlich über eine Lauffähigkeit ohne Fehler (z.B. keine Verwendung nicht vorhandender Kontext-Variablen oder Verwendung von `try ... catch`) im _tibi-admin_ verfügen. Das hat den Vorteil, dass eine Vorab-Validierung stattfindet, bevor der Datensatz an der Server gesendet wird.
|
||||||
|
|
||||||
|
Sollte der `eval` Code im _tibi-admin_ nicht lauffähig sein (nicht abgefangene Exception), wird der Validator clientseitig ingoriert und nur die serverseitige Prüfung beeinflusst die Aktion.
|
||||||
|
|
||||||
|
#### siehe
|
||||||
|
|
||||||
|
- [Server Javascript Kontext](./../../server-javascript-kontext/allgemeines.md)
|
||||||
|
- [Validator Javascript Kontext](./../../server-javascript-kontext/validator.md)
|
||||||
|
|
||||||
|
## dependsOn
|
||||||
|
|
||||||
|
<video width="100%" controls muted autoplay loop>
|
||||||
|
<source src="dependsOn.webm" type="video/webm">
|
||||||
|
</video>
|
||||||
|
|
||||||
|
Obige Darstellung wie im Video wird beispielsweise durch folgende Feld-Konfiguration erreicht:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# in einer Kollektions-Konfiguration
|
||||||
|
fields:
|
||||||
|
- name: type
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Typ
|
||||||
|
en: Type
|
||||||
|
widget: select
|
||||||
|
choices:
|
||||||
|
- name:
|
||||||
|
de: Standardseite
|
||||||
|
en: Standard page
|
||||||
|
id: page
|
||||||
|
- name:
|
||||||
|
de: News
|
||||||
|
en: News
|
||||||
|
id: news
|
||||||
|
|
||||||
|
- name: title
|
||||||
|
type: string
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Titel
|
||||||
|
en: Title
|
||||||
|
|
||||||
|
- name: date
|
||||||
|
type: date
|
||||||
|
meta:
|
||||||
|
label:
|
||||||
|
de: Titel
|
||||||
|
en: title
|
||||||
|
widget: date
|
||||||
|
defaultValue:
|
||||||
|
eval: new Date()
|
||||||
|
dependsOn:
|
||||||
|
eval: $parent?.type == "news"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
`meta.dependsOn` kann als Objekt mit `eval`-Attribut für Javascript oder als `string` mit dem Feldnamen (Punktschreibweise, z.B. `"additionalData.author"`) angegeben werden.
|
||||||
|
|
||||||
|
Wird der Feldname verwendet wird nur geprüft, ob das Feld belegt ist. TODO
|
||||||
|
|
||||||
|
Die `eval` Variante verwendet als Javascript-Kontext Variablen die auf folgenden Seite beschrieben werden:
|
||||||
|
|
||||||
|
- [Admin Javascript Kontext](./../../admin-javascript-kontext/allgemeines.md)
|
||||||
|
- [collection.meta..eval](./../../admin-javascript-kontext/collection.meta..eval.md)
|
||||||
|
- [field.meta..eval](./../../admin-javascript-kontext/field.meta..eval.md)
|
||||||
|
|
||||||
|
Die Rückgabe des Javascript-Codes beeinflusst die Einblendung des betroffenen Feldes in folgender Weise:
|
||||||
|
|
||||||
|
| Rückgabe | Bedeutung |
|
||||||
|
| -------- | -------------------------- |
|
||||||
|
| `true` | Das Feld wird angezeigt |
|
||||||
|
| `false` | Das Feld wird ausgeblendet |
|
||||||
|
|
||||||
|
## defaultValue
|
||||||
|
|
||||||
|
Für die Vorlegung neu anzulegender Datensätze kann in `field.meta.defaultValue` direkt der Standardwert hinterlegt werden, oder über `field.meta.defaultValue.eval` ein Javascript-Code angegeben werden, der den Wert ermittelt. Die Rückgabe des Javascript-Codes, sowie auch die direkte Vergabe des Wertes muss dem Datentyp des Feldes entsprechen.
|
||||||
|
|
||||||
|
Der Javascript-Kontext ist der gleiche wie bei `field.meta.dependsOn.eval`.
|
44
docs/md/projektkonfig/collections/fields/datentypen.md
Normal file
44
docs/md/projektkonfig/collections/fields/datentypen.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Datentypen
|
||||||
|
|
||||||
|
Via `type` wird der Datentyp des Feldes definiert. Folgende Datentypen sind möglich:
|
||||||
|
|
||||||
|
## string
|
||||||
|
|
||||||
|
String wird für Zeichenketten verwendet. Das Standardwidget ohne weitere Angabe ist bei der Ausgabe die direkte Textausgabe und bei der Eingabe ein HTML `<input ...>` Element mit dem Attribut `type="text"`.
|
||||||
|
|
||||||
|
## number
|
||||||
|
|
||||||
|
Number wird sowohl für ganze Zahlen, wie auch für Gleitkommawerte definiert. Auch hier ist das Standard-Widget für die Eingabe ein HTML `<input ...>` Element, allerdings mit dem Attribut `type="number"`.
|
||||||
|
|
||||||
|
## boolean
|
||||||
|
|
||||||
|
Ein boolcher Wert, also `true` oder `false`, wird über den Typ `"boolean"` definiert und standardmäßig als Checkbox dargestellt.
|
||||||
|
|
||||||
|
## date
|
||||||
|
|
||||||
|
`"date"` als Datentyp kann sowohl Datumsangabe mit, als auch ohne Uhrzeit aufnehmen. Das Standardwidget ist die einfache Datumseingabe ohne Uhrzeit.
|
||||||
|
|
||||||
|
## file
|
||||||
|
|
||||||
|
Der Datentyp `"file"` ist für Dateiuploads vorgesehen. Es daher standardmäßig ein Datei-Auswahl-Dialog als Widget für die Eingabe angeboten.
|
||||||
|
|
||||||
|
## string[]
|
||||||
|
|
||||||
|
Für `"string[]` Arrays ist die Angabe des Widgets zwingend notwendig.
|
||||||
|
|
||||||
|
## number[]
|
||||||
|
|
||||||
|
Auch für `"number[]"` Arrays wird die Widget-Angabe erwartet.
|
||||||
|
|
||||||
|
## object
|
||||||
|
|
||||||
|
`"object"` ist ein spezieller Datentyp der zur Strukturierung der API und der Eingabe dient. Dieser Datentyp fasst `subFields` zusammen.
|
||||||
|
|
||||||
|
## object[]
|
||||||
|
|
||||||
|
Wie `"object"` fasst auch das `"object[]"` Array `subFields` zusammen. Diese allerdings als Liste von Objekten, anstatt als Einzelobjekt.
|
||||||
|
|
||||||
|
## any
|
||||||
|
|
||||||
|
Felder vom Typ `"any"` können beliebige Daten aufnehmen. Die Validierung schlägt auf Basis der Typ-Validierung hier nie fehl.
|
||||||
|
|
39
docs/md/projektkonfig/collections/fields/widgets.md
Normal file
39
docs/md/projektkonfig/collections/fields/widgets.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Widgets
|
||||||
|
|
||||||
|
Das im *tibi-admin* für die Ein- und Ausgabe von Daten zu verwendente Widget wird über die Feldkonfiguration `meta.widget` festgelegt. Die Angabe erfolgt als String mit dem Widget-Namen.
|
||||||
|
|
||||||
|
Nicht jedes Widget kann mit jedem Datentyp umgehen, die möglichen Datentypen werden aber nachfolgend bei jedem Widget erwähnt. Außerdem wird auf individuelle Konfigurationsmöglichkeiten eingegangen.
|
||||||
|
|
||||||
|
## text
|
||||||
|
|
||||||
|
## number
|
||||||
|
|
||||||
|
## checkbox
|
||||||
|
|
||||||
|
## select
|
||||||
|
|
||||||
|
## date
|
||||||
|
|
||||||
|
## datetime
|
||||||
|
|
||||||
|
## richtext
|
||||||
|
|
||||||
|
## file
|
||||||
|
|
||||||
|
## image
|
||||||
|
|
||||||
|
## selectArray
|
||||||
|
|
||||||
|
## checkboxArray
|
||||||
|
|
||||||
|
## chipArray
|
||||||
|
|
||||||
|
## object
|
||||||
|
|
||||||
|
## objectArray
|
||||||
|
|
||||||
|
## tabs
|
||||||
|
|
||||||
|
## contentbuilder
|
||||||
|
|
||||||
|
siehe: [ContentBuilder](./widgets/contentbuilder.md)
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,35 @@
|
|||||||
|
# contentbuilder
|
||||||
|
|
||||||
|
> Der ContentBuilder ist ein Drittanbieter-Produkt und steht nicht in jeder Lizenz zur Verfügung. Bitte kontaktieren Sie uns, wenn Sie Interesse an diesem Widget haben.
|
||||||
|
|
||||||
|
Für die Gestaltung von HTML-Inhalten ist der ContentBuilder eine einfache und intuitive Lösung. Es sind Layout-Hilfmittel wie Spalten und Zeilen ebenso verfügbar, wie die Möglichkeit Dateien (Bilder, Video, Downloads) direkt in den HTML-Code einzubinden.
|
||||||
|
|
||||||
|
Wie der ContentBuilder an einem Feld konfiguriert wird verdeutlicht folgendes Beispiel:
|
||||||
|
|
||||||
|
!!!include(../api/collections/fields/content.yml)!!!
|
||||||
|
|
||||||
|
## Mediathek Kollektion
|
||||||
|
|
||||||
|
<video width="100%" controls autoplay muted loop>
|
||||||
|
<source src="contentbuilder-medialib.webm" type="video/webm">
|
||||||
|
</video>
|
||||||
|
|
||||||
|
Wie aus der obigen Definition unterhalb von z.B. "imageSelect" zu lesen, bedarf es einer eigenen Kollektion für Bilder und andere Dateien. Diese Kollektion könnte wie folgt aussehen:
|
||||||
|
|
||||||
|
> Die Bedeutung der hier nicht beschriebenen Eigenschaften ist unter [collections](./../../../collections.md) zu finden.
|
||||||
|
|
||||||
|
!!!include(../api/collections/medialib.yml)!!!
|
||||||
|
|
||||||
|
## Module (customTags)
|
||||||
|
|
||||||
|
Die Einbindung des konfigurierten Beispiel-Moduls aus obiger Definition erfolgt im ContentBuilder wie im folgenden Video zu sehen ist:
|
||||||
|
|
||||||
|
<video width="100%" controls autoplay muted loop>
|
||||||
|
<source src="contentbuilder-module.webm" type="video/webm">
|
||||||
|
</video>
|
||||||
|
|
||||||
|
Wie oben schon erwähnt, sind die `placeholder` frei wählbar. Eine HTML5-Schreibweise bietet sich aber sowohl für das Styling, als auch für die spätere Einbindung in ein Frontend an.
|
||||||
|
|
||||||
|
In unserem Beispiel hier wurden zusättzlich zum eigentlichen Modul-Tag noch Attribute (`title` und `description`) definiert. Diese können dann im Frontend das eigentliche Modul beeinflussen.
|
||||||
|
|
||||||
|
Im Frontend könnte ein Modul dann später als "Custom Element" implementiert werden oder es wird ein HTML-Parser verwendet, der die Tags durch eigene Komponenten ersetzt, wie er im Anhang [TODO] zu finden ist.
|
1
docs/md/projektkonfig/collections/hooks.md
Normal file
1
docs/md/projektkonfig/collections/hooks.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# hooks
|
30
docs/md/projektkonfig/collections/imageFilter.md
Normal file
30
docs/md/projektkonfig/collections/imageFilter.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# imageFilter Objekt
|
||||||
|
|
||||||
|
Die Bildmanipulation von hochgeladen Bildern zu einer Kollektion kann über das `imageFilter` Objekt definiert werden.
|
||||||
|
Der Filter wird angewandt, wenn an die Bild-URL der Parameter `filter=...` angehangen wird.
|
||||||
|
|
||||||
|
Der Prozess selbst erfolgt beim ersten Abruf des Bildes und wird zwischengespeichert.
|
||||||
|
|
||||||
|
Eine beispielhafte Konfiguration, die die Bilder nur verkleinert sieht so aus:
|
||||||
|
|
||||||
|
!!!include(../api/collections/democol/imageFilter.yml)!!!
|
||||||
|
|
||||||
|
Folgende Attribute können Filter-Eintrage haben, wobei `fit` und `fill` exklusiv sind:
|
||||||
|
|
||||||
|
| Attribut | Typ | Beschreibung |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `fit` | boolean | passt das Bild in ein Rechteck ein |
|
||||||
|
| `fill` | boolean | streckt/staucht das Bild, so dass es das Rechteck komplett ausfüllt |
|
||||||
|
| `height` | number | Höhe des Rechtecks |
|
||||||
|
| `width` | number | Breite des Rechtecks |
|
||||||
|
| `blur` | number | Verwischungsgrad |
|
||||||
|
| `brightness` | number | Helligkeit |
|
||||||
|
| `contrast` | number | Konrast |
|
||||||
|
| `gamma` | number | Gamma-Wert |
|
||||||
|
| `saturation` | number | Sättigung |
|
||||||
|
| `sharpen` | number | Schärfe |
|
||||||
|
| `invert` | boolean | Farben invertieren |
|
||||||
|
| `grayscale` | boolean | Schwarz-Weiß |
|
||||||
|
| `resampling` | "lanczos"<br>"nearestNeighbor"<br>"linear"<br>"catmullRom" | Resampling-Algorithmus |
|
||||||
|
| `quality` | number | Ausgabequalität 0..100 |
|
||||||
|
|
3
docs/md/projektkonfig/collections/indexes.md
Normal file
3
docs/md/projektkonfig/collections/indexes.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# indexes Liste
|
||||||
|
|
||||||
|
TODO
|
29
docs/md/projektkonfig/collections/meta.md
Normal file
29
docs/md/projektkonfig/collections/meta.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# meta Objekt
|
||||||
|
|
||||||
|
Wie bereits an anderer Stelle beschrieben, dient das `meta` Objekt zur Definition von Merkmalen, die im *tibi-admin* finden. Zum Anlegen der Struktur in der Datenbank und Definition der API haben diese Angaben keine Relevanz.
|
||||||
|
|
||||||
|
Folgende Angaben sind möglich:
|
||||||
|
|
||||||
|
!!!include(../api/collections/democol/meta.yml)!!!
|
||||||
|
|
||||||
|
## views Liste
|
||||||
|
|
||||||
|
`views` werden für die Darstellung der Kollektion-Daten im *tibi-admin* benötigt. Die Auswahl des passenden View erfolgt über CSS Media-Queries.
|
||||||
|
|
||||||
|
Optionale Unternavigationen können eigene `views` haben.
|
||||||
|
|
||||||
|
Folgende möglche Einträge für `views` gibt es derzeit:
|
||||||
|
|
||||||
|
### simpleList
|
||||||
|
|
||||||
|
!!!include(../api/collections/democol/simpleList.yml)!!!
|
||||||
|
|
||||||
|
### table
|
||||||
|
|
||||||
|
!!!include(../api/collections/democol/table.yml)!!!
|
||||||
|
|
||||||
|
## tablist
|
||||||
|
|
||||||
|
Wird die `tablist` verwendet, ist sicher zu stellen, dass alle Felder in der Definition aufgenommen werden. Werden Felder nicht in die `tablist` aufgenommen, sind diese weiterhin in einer Gesamtliste unterhalb der Tabs und bringen das Layout durcheinander.
|
||||||
|
|
||||||
|
!!!include(../api/collections/democol/tablist.yml)!!!
|
BIN
docs/md/projektkonfig/collections/validator.webm
Normal file
BIN
docs/md/projektkonfig/collections/validator.webm
Normal file
Binary file not shown.
15
docs/md/projektkonfig/config.yml.md
Normal file
15
docs/md/projektkonfig/config.yml.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# config.yml
|
||||||
|
|
||||||
|
Die Datei **config.yml** ist der Einstieg in die API-Konfiguration eines Projekts. Die Datei kann sich an einem beliebigen Ort befinden. Die einzige Bedingung ist, dass sie durch den tibi-server lesbar ist.
|
||||||
|
|
||||||
|
Es hat sich jedoch als günstig erwiesen bei Webprojekten die Datei und alle anderen Datein, die zur API-Konfiguration gehören, im ordner [api/](./ordnerstruktur.md) unterhalb des eigentlichen Webprojektes anzuordnen. Die Quellen des Frontends und der API können somit in ein Mono-Repo eingecheckt werden.
|
||||||
|
|
||||||
|
## Aufbau
|
||||||
|
|
||||||
|
!!!include(../api/config.yml)!!!
|
||||||
|
|
||||||
|
### siehe
|
||||||
|
|
||||||
|
- [collections](./collections.md)
|
||||||
|
- [jobs](./jobs.md)
|
||||||
|
- [assets](./assets.md)
|
11
docs/md/projektkonfig/jobs.md
Normal file
11
docs/md/projektkonfig/jobs.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# jobs
|
||||||
|
|
||||||
|
In dem ein oder anderen Projekt werden sicherlich Jobs im Hintergrund benötigt, die zu bestimmten Zeiten oder Intervallweise ausgeführt werden müssen (z.B. Datenbereinigung). Diese Jobs können innerhalb der [config.yml](./config.yml.md) definiert werden.
|
||||||
|
|
||||||
|
Wie in allen YAML-Definitionen können auch die Jobs via `!include` ausgelagert werden.
|
||||||
|
|
||||||
|
Der Aufbau eines Jobs ausgelagert in einer Datei sieht beispielsweise folgendermaßen aus:
|
||||||
|
|
||||||
|
!!!include(../api/jobs/demojob.yml)!!!
|
||||||
|
|
||||||
|
Die Möglichkeiten innerhalb der Javascript-Datei werden im Kapitel [Javascript Kontext](./../server-javascript-kontext/job.md) beschrieben.
|
65
docs/md/projektkonfig/ordnerstruktur.md
Normal file
65
docs/md/projektkonfig/ordnerstruktur.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Ordnerstruktur
|
||||||
|
|
||||||
|
Als Konvention für neue Projekte hat sich folgende Ordnerstruktur etabliert:
|
||||||
|
|
||||||
|
![Ordnerstruktur](api-ordner.png)
|
||||||
|
|
||||||
|
Die Aufteilung der YAML-Konfiguration ist durch den YAML-Tag `!include` möglich. Genaueres dazu wird auf den nachfolgenden Seiten beschrieben.
|
||||||
|
|
||||||
|
## /api
|
||||||
|
|
||||||
|
Der Einstiegsordner in die Konfiguration ist frei wählbar. "/api" innerhalb des Projektrepositories hat sich jedoch bewährt.
|
||||||
|
|
||||||
|
Die Einstiegsdatei in die Gesamt-Konfiguration liegt hier und heißt [config.yml](./config.yml.md). In dieser können Umgebungsvariablen erstetzt werden, welche in [config.yml.env](./config.yml.md) definiert sind.
|
||||||
|
|
||||||
|
Ebenso sind alle nachfolgenden Unterordner beliebig zu benennen. Da aber ein JSON-Schema und VSCode-Konfiguration zur Validierung der YAML Dateien existiert, ist folgende Struktur hilfreich.
|
||||||
|
|
||||||
|
### JSON-Schema
|
||||||
|
|
||||||
|
Das JSON-Schema ist in die package.json einzubinden via:
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"devDependencies": {
|
||||||
|
...,
|
||||||
|
"tibi-types": "https://gitbase.de/cms/tibi-types.git"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Die im Projekt liegende VSCode-Konfig sollte dementsprechend ergänzt werden:
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"yaml.schemas": {
|
||||||
|
"node_modules/tibi-types/schemas/api-config/config.json": "api/config.y*ml",
|
||||||
|
"node_modules/tibi-types/schemas/api-config/collection.json": "api/collections/*.y*ml",
|
||||||
|
"node_modules/tibi-types/schemas/api-config/field.json": "api/collections/fields/*.y*ml",
|
||||||
|
"node_modules/tibi-types/schemas/api-config/fieldArray.json": "api/collections/fieldLists/*.y*ml"
|
||||||
|
},
|
||||||
|
"yaml.customTags": ["!include scalar"],
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Sollte Yarn2 verwendet werden ist die Verlinkung von **node_modules** nötig. Dazu ist folgendes in der **.yarnrc.yml** einzutragen:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
...
|
||||||
|
nodeLinker: node-modules
|
||||||
|
```
|
||||||
|
|
||||||
|
## /api/collections
|
||||||
|
|
||||||
|
Bei Aufteilung der Kollektionskonfigurationen in einzelne Dateien, sollten diese in diesem Ordner gespeichert werden. Für jede Kollektion sollte eine eigene Datei verwendet werden, hier im Beispiel [api/collections/democol.yml](./collections.md).
|
||||||
|
|
||||||
|
### /api/collections/fields
|
||||||
|
|
||||||
|
Sollten Feldkonfigurationen wieder verwendet werden, können diese im [api/collections/fields/](./collections/fields.md) Unterordner gepeichert werden. Diese sind pro Feldkonfiguration als einzelne Datei aufzuführen.
|
||||||
|
|
||||||
|
### /api/hooks
|
||||||
|
|
||||||
|
Jede Javascript-Datei, die einen Hook bedient sollte im Unterordner benannt nach der Kollektion im Ordner [api/hooks/](./collections/hooks.md) sein. Der Name der Datei sollte sich nach den Hook richten. Z.B. **get_return.js** ist zustängig für den GET-Hook nach dem Lesen der Daten, bevor diese zurück gegeben werden. Mehr dazu unter [Hooks](./collections/hooks.md).
|
||||||
|
|
||||||
|
### /api/templates
|
||||||
|
|
||||||
|
Ist es nötig im Projekt Templates zu rendern (z.B. für den Email-Versand), sind diese im Ordner **templates** gut aufgehoben.
|
3
docs/md/restapi/assets.md
Normal file
3
docs/md/restapi/assets.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# `/_/NAMESPACE/_/assets/ASSETSNAME`
|
||||||
|
|
||||||
|
TODO
|
3
docs/md/restapi/collection.md
Normal file
3
docs/md/restapi/collection.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# `/_/NAMESPACE/COLLECTION`
|
||||||
|
|
||||||
|
TODO
|
3
docs/md/restapi/login.md
Normal file
3
docs/md/restapi/login.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# `/login`
|
||||||
|
|
||||||
|
TODO
|
3
docs/md/restapi/project.md
Normal file
3
docs/md/restapi/project.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# `/project`
|
||||||
|
|
||||||
|
TODO
|
3
docs/md/restapi/user.md
Normal file
3
docs/md/restapi/user.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# `/user`
|
||||||
|
|
||||||
|
TODO
|
0
docs/md/server-javascript-kontext/allgemeines.md
Normal file
0
docs/md/server-javascript-kontext/allgemeines.md
Normal file
0
docs/md/server-javascript-kontext/hook.md
Normal file
0
docs/md/server-javascript-kontext/hook.md
Normal file
0
docs/md/server-javascript-kontext/job.md
Normal file
0
docs/md/server-javascript-kontext/job.md
Normal file
0
docs/md/server-javascript-kontext/packages/db.md
Normal file
0
docs/md/server-javascript-kontext/packages/db.md
Normal file
0
docs/md/server-javascript-kontext/packages/debug.md
Normal file
0
docs/md/server-javascript-kontext/packages/debug.md
Normal file
0
docs/md/server-javascript-kontext/packages/fs.md
Normal file
0
docs/md/server-javascript-kontext/packages/fs.md
Normal file
0
docs/md/server-javascript-kontext/packages/http.md
Normal file
0
docs/md/server-javascript-kontext/packages/http.md
Normal file
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user