diff --git a/.gitignore b/.gitignore index 00f3c09..5e5b429 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,10 @@ out/ archives/ +build/ -src/images/*.png -src/3-99-generiertes-schema.md - -composer.json -composer.lock -vendor/ - -*.komodoproject -*.DS_Store ._* .cache +__pycache__ en/*-schema.md de/*-schema.md diff --git a/.travis.yml b/.travis.yml index a1e6ea3..42385a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: python python: - '3.5' +- '3.6' cache: apt: true @@ -10,11 +11,29 @@ cache: addons: apt: packages: - - pandoc - - lacheck + - etoolbox + - ghostscript + - lmodern - graphviz + - make + - pandoc + - pandoc-citeproc + - texlive-fonts-recommended + - texlive-generic-recommended + - texlive-humanities + - texlive-lang-german + - texlive-latex-recommended + - latex-xcolor + - texlive-luatex + - texlive-xetex + - librsvg2-bin + +install: +- pip install pyaml +# We use git describe which doesn't work on a shallow clone +- git fetch --unshallow -script: make test +script: ./build.py notifications: slack: diff --git a/.tx/config b/.tx/config new file mode 100644 index 0000000..e3e35fc --- /dev/null +++ b/.tx/config @@ -0,0 +1,152 @@ +[main] +host = https://www.transifex.com + +[spec-1.0-00-metadatamd] +source_lang = de +source_file = src/0-00-metadata.md +file_filter = locales//src/0-00-metadata.md +type = GITHUBMARKDOWN + +[spec-1.1-00-einleitungmd] +source_lang = de +source_file = src/1-00-einleitung.md +file_filter = locales//src/1-00-einleitung.md +type = GITHUBMARKDOWN + +[spec-1.1-01-was-ist-oparlmd] +source_lang = de +source_file = src/1-01-was-ist-oparl.md +file_filter = locales//src/1-01-was-ist-oparl.md +type = GITHUBMARKDOWN + +[spec-1.1-02-zielsetzung-von-oparlmd] +source_lang = de +source_file = src/1-02-zielsetzung-von-oparl.md +file_filter = locales//src/1-02-zielsetzung-von-oparl.md +type = GITHUBMARKDOWN + +[spec-1.1-03-transparenz-und-beteiligung-durch-open-datamd] +source_lang = de +source_file = src/1-03-transparenz-und-beteiligung-durch-open-data.md +file_filter = locales//src/1-03-transparenz-und-beteiligung-durch-open-data.md +type = GITHUBMARKDOWN + +[spec-1.1-04-nutzungsszenarienmd] +source_lang = de +source_file = src/1-04-nutzungsszenarien.md +file_filter = locales//src/1-04-nutzungsszenarien.md +type = GITHUBMARKDOWN + +[spec-1.1-05-nomenklaturmd] +source_lang = de +source_file = src/1-05-nomenklatur.md +file_filter = locales//src/1-05-nomenklatur.md +type = GITHUBMARKDOWN + +[spec-1.1-06-datenschutzmd] +source_lang = de +source_file = src/1-06-datenschutz.md +file_filter = locales//src/1-06-datenschutz.md +type = GITHUBMARKDOWN + +[spec-1.1-07-oparl-governancemd] +source_lang = de +source_file = src/1-07-oparl-governance.md +file_filter = locales//src/1-07-oparl-governance.md +type = GITHUBMARKDOWN + +[spec-1.1-08-oparl-autorenmd] +source_lang = de +source_file = src/1-08-oparl-autoren.md +file_filter = locales//src/1-08-oparl-autoren.md +type = GITHUBMARKDOWN + +[spec-1.2-00-prinzipien-und-funktionen-der-schnittstellemd] +source_lang = de +source_file = src/2-00-prinzipien-und-funktionen-der-schnittstelle.md +file_filter = locales//src/2-00-prinzipien-und-funktionen-der-schnittstelle.md +type = GITHUBMARKDOWN + +[spec-1.2-01-designprinzipienmd] +source_lang = de +source_file = src/2-01-designprinzipien.md +file_filter = locales//src/2-01-designprinzipien.md +type = GITHUBMARKDOWN + +[spec-1.2-02-zukunftssicherheitmd] +source_lang = de +source_file = src/2-02-zukunftssicherheit.md +file_filter = locales//src/2-02-zukunftssicherheit.md +type = GITHUBMARKDOWN + +[spec-1.2-03-urlsmd] +source_lang = de +source_file = src/2-03-urls.md +file_filter = locales//src/2-03-urls.md +type = GITHUBMARKDOWN + +[spec-1.2-04-json-ausgabemd] +source_lang = de +source_file = src/2-04-json-ausgabe.md +file_filter = locales//src/2-04-json-ausgabe.md +type = GITHUBMARKDOWN + +[spec-1.2-05-objektlisten-und-paginierungmd] +source_lang = de +source_file = src/2-05-objektlisten-und-paginierung.md +file_filter = locales//src/2-05-objektlisten-und-paginierung.md +type = GITHUBMARKDOWN + +[spec-1.2-06-cross-origin-resource-sharing-corsmd] +source_lang = de +source_file = src/2-06-cross-origin-resource-sharing-cors.md +file_filter = locales//src/2-06-cross-origin-resource-sharing-cors.md +type = GITHUBMARKDOWN + +[spec-1.2-07-dateizugriffemd] +source_lang = de +source_file = src/2-07-dateizugriffe.md +file_filter = locales//src/2-07-dateizugriffe.md +type = GITHUBMARKDOWN + +[spec-1.2-08-geloeschte-objektemd] +source_lang = de +source_file = src/2-08-geloeschte-objekte.md +file_filter = locales//src/2-08-geloeschte-objekte.md +type = GITHUBMARKDOWN + +[spec-1.2-09-ausnahmebehandlungmd] +source_lang = de +source_file = src/2-09-ausnahmebehandlung.md +file_filter = locales//src/2-09-ausnahmebehandlung.md +type = GITHUBMARKDOWN + +[spec-1.2-10-endpunktmd] +source_lang = de +source_file = src/2-10-endpunkt.md +file_filter = locales//src/2-10-endpunkt.md +type = GITHUBMARKDOWN + +[spec-1.3-00-schemamd] +source_lang = de +source_file = src/3-00-schema.md +file_filter = locales//src/3-00-schema.md +type = GITHUBMARKDOWN + +[spec-1.3-01-eigenschaften-mit-verwendung-in-mehreren-objekttypenmd] +source_lang = de +source_file = src/3-01-eigenschaften-mit-verwendung-in-mehreren-objekttypen.md +file_filter = locales//src/3-01-eigenschaften-mit-verwendung-in-mehreren-objekttypen.md +type = GITHUBMARKDOWN + +[spec-1.buildingmd] +source_lang = de +source_file = building.md +file_filter = building..md +type = GITHUBMARKDOWN + +[spec-1.schema_stringsyml] +source_lang = de +source_file = schema/strings.yml +file_filter = locales//schema/strings.yml +type = YML diff --git a/Dockerfile b/Dockerfile index 7c2665f..e0defce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,19 +22,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -FROM debian:latest -MAINTAINER Stefan Graupner - -RUN apt update -y -RUN apt upgrade -y +FROM debian:testing-slim # recommended packages for pandoc + basic pdf export -RUN apt install --no-install-recommends -y \ - etoolbox \ +RUN apt update -y && apt upgrade -y && apt install --no-install-recommends -y \ ghostscript \ lmodern \ graphviz \ - make \ pandoc \ pandoc-citeproc \ texlive-fonts-recommended \ @@ -43,7 +37,21 @@ RUN apt install --no-install-recommends -y \ texlive-lang-german \ texlive-latex-recommended \ texlive-luatex \ - texlive-xetex + texlive-xetex \ + python3 \ + python3-pip \ + python3-setuptools \ + imagemagick \ + zip \ + tar \ + git-core \ + bzip2 && \ + pip3 install pyyaml && \ + apt remove -y --purge \ + python3-pip \ + python3-setuptools && \ + rm -rf /var/lib/apt/lists/* && \ + apt clean -RUN apt -y install python3 imagemagick zip tar bzip2 +ENTRYPOINT [ "python3", "build.py" ] diff --git a/LICENCE b/LICENSE similarity index 100% rename from LICENCE rename to LICENSE diff --git a/Makefile b/Makefile deleted file mode 100644 index f226bc9..0000000 --- a/Makefile +++ /dev/null @@ -1,125 +0,0 @@ -# Variables -VERSION=1.1-draft -HUMAN_VERSION="1.1 Entwurf" -BASENAME=OParl-$(VERSION) - -# Directories -SRC_DIR=src -IMG_DIR=src/images -SHM_DIR=schema -EXP_DIR=examples -OUT_DIR=out -ARC_DIR=archives - -# Commands -PANDOC=pandoc -DOT=dot -LATEX=xelatex -GS=gs -CONVERT=convert -PYTHON=python3 - -# Command Flags -# --- -# The default flags for the commands are separated from the -# command binaries to simplify switching out the binary for -# a command with environment variables. For instance, one might -# want to use a not-in-path variant of pandoc and this way, -# the make call can simply be prefixed as `PANDOC=/path/to/pandoc make` - -PANDOC_FLAGS=--from markdown --standalone --table-of-contents \ - --toc-depth=2 --number-sections -GS_FLAGS=-dQUIET -dSAFER -dBATCH -dNOPAUSE -sDisplayHandle=0 \ - -sDEVICE=png16m -r600 -dTextAlphaBits=4 - -LATEX_TEMPLATE=resources/template.tex -SCHEMA_MD=$(SRC_DIR)/3-99-generiertes-schema.md -HTML5_CSS=resources/html5.css - -PDF_IMAGES=$(wildcard $(IMG_DIR)/*.pdf) -GS_IMAGES=$(PDF_IMAGES:.pdf=.png) - -SVG_IMAGES=$(wildcard $(IMG_DIR)/*.svg) -MAGICK_IMAGES=$(SVG_IMAGES:.svg=.png) - -DOT_IMAGES=$(wildcard $(IMG_DIR)/*.dot) -GRAPHVIZ_IMAGES=$(DOT_IMAGES:.dot=.png) - -SCHEMA_JSON=$(wildcard $(SHM_DIR)/*.json) - -.PHONY: all clean test live html pdf odt txt epub - -all: html pdf odt docx txt epub - -# preliminary targets - -# transform dot file using dot -Tpng graphviz.dot -o graphviz.png -$(IMG_DIR)/%.png: $(IMG_DIR)/%.dot - $(DOT) -Tpng $< -o $@ - -$(IMG_DIR)/%.png: $(IMG_DIR)/%.pdf - $(GS) $(GS_FLAGS) -sOutputFile=$@ -f $< - -$(IMG_DIR)/%.png: $(IMG_DIR)/%.svg - $(CONVERT) $< $@ - -$(OUT_DIR): - mkdir -p $(OUT_DIR) - -$(SCHEMA_MD): $(SHM_DIR)/*.json $(EXP_DIR)/*.json scripts/json_schema2markdown.py - $(PYTHON) scripts/json_schema2markdown.py $(SHM_DIR) $(EXP_DIR) $(SCHEMA_MD) - -# main targets - -common: $(OUT_DIR) $(SCHEMA_MD) $(GS_IMAGES) $(MAGICK_IMAGES) $(GRAPHVIZ_IMAGES) - -html: common - $(PANDOC) $(PANDOC_FLAGS) --to html5 --css $(HTML5_CSS) --section-divs --self-contained \ - -o $(OUT_DIR)/$(BASENAME).html resources/lizenz-als-bild.md $(SRC_DIR)/*.md - -pdf: common - $(PANDOC) $(PANDOC_FLAGS) --latex-engine=$(LATEX) --template $(LATEX_TEMPLATE) \ - -o $(OUT_DIR)/$(BASENAME).pdf $(SRC_DIR)/*.md - -odt: common - $(PANDOC) $(PANDOC_FLAGS) -o $(OUT_DIR)/$(BASENAME).odt resources/lizenz-als-text.md $(SRC_DIR)/*.md - -docx: common # FIXME: License information in header is missing - $(PANDOC) $(PANDOC_FLAGS) -o $(OUT_DIR)/$(BASENAME).docx resources/lizenz-als-text.md $(SRC_DIR)/*.md - -txt: common - $(PANDOC) $(PANDOC_FLAGS) -o $(OUT_DIR)/$(BASENAME).txt $(SRC_DIR)/*.md - -epub: common - $(PANDOC) $(PANDOC_FLAGS) -o $(OUT_DIR)/$(BASENAME).epub $(SRC_DIR)/*.md - -# Used for the spec website -live: common - $(PANDOC) $(PANDOC_FLAGS) --to html5 --section-divs --no-highlight \ - -o $(OUT_DIR)/live.html $(SRC_DIR)/*.md - -clean: - rm -rf $(OUT_DIR) - rm -f $(CONTRIB_MD) - rm -f $(SCHEMA_MD) - rm -f $(GS_IMAGES) - rm -f $(MAGICK_IMAGES) - rm -rf $(ARC_DIR) - -# archives - -archives: zip gz bz - -zip: all - mkdir -p $(ARC_DIR) && cd $(OUT_DIR) && zip -qr ../$(ARC_DIR)/$(BASENAME).zip . - -gz: all - mkdir -p $(ARC_DIR) && cd $(OUT_DIR) && tar -czf ../$(ARC_DIR)/$(BASENAME).tar.gz . - -bz: all - mkdir -p $(ARC_DIR) && cd $(OUT_DIR) && tar -cjf ../$(ARC_DIR)/$(BASENAME).tar.bz2 . - -# test - -test: - scripts/test.sh diff --git a/README.md b/README.md index eeef967..61d6930 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,20 @@ [![Build Status](https://travis-ci.org/OParl/spec.svg)][travis] -In diesem Repository wird die Spezifikation zum [OParl][oparl]-Standard erarbeitet. +In diesem Repository wird die Spezifikation zum [OParl][oparl]-Standard gepflegt. -Der OParl-Standard dient der Definition einer einheitlichen Schnittstelle zum Abruf von -maschinenlesbaren Informationen aus Ratsinformationssystemen. Mehr über OParl: +Der OParl-Standard definiert eine einheitliche Schnittstelle zum Abruf von +maschinenlesbaren Informationen aus Ratsinformationssystemen. -- Mehr über OParl: [https://oparl.org][oparl] +- Mehr über OParl: [https://oparl.org][oparl] - Weitere Informationen für Entwickler: [https://dev.oparl.org][oparl-dev] -## Änderungen an OParl vornehmen +Änderungsvorschläge können über Pull Requests eingebracht werden. +Hilfe im Umgang mit GitHub findest du [hier][github-help]. -OParl wird hauptsächlich auf GitHub entwickelt. Hilfe im Umgang mit GitHub findest du [hier][github-help]. Änderungsvorschläge können über Pull Requests eingebracht werden. +## Die Spezifikation herunterladen -Weitere Hinweise zum Mitentwickeln finden sich [hier][building]. - -## Die Spezifikation in verschiedenen Formaten - -Es stehen Versionen des Dokuments in verschiedenen Formaten zur Verfügung: +Die Spezifikation kann in verschiedenen Formaten heruntergeladen werden. ### Version 1.0 @@ -38,13 +35,79 @@ Es stehen Versionen des Dokuments in verschiedenen Formaten zur Verfügung: * [EPub][spec-master-epub] * [Nur Text][spec-master-txt] +## Erstellen der Dokumente + +Es gibt zwei Möglichkeiten, die Dokumente zu erstellen: Direkt mit `build.py` oder über eine Docker-Container. + +### Mit `build.py` + +Für das Erstellen der Spezifikation ist folgende Software erforderlich: + +- [Pandoc][pandoc] +- [Graphviz][graphviz] +- [Python >= 3.5][python] +- [Ghostscript][ghostscript] +- [ImageMagick][imagemagick] + +Zur Erstellung der Archive außerdem: + +- [GNU Tar][tar] +- [Zip][zip] + +Unter Ubuntu können alle benötigten Pakete mit einem Befehl installiert werden: + +```bash +sudo apt install etoolbox ghostscript lmodern graphviz make pandoc pandoc-citeproc texlive-fonts-recommended \ +texlive-generic-recommended texlive-humanities texlive-lang-german texlive-latex-recommended texlive-luatex \ +texlive-xetex librsvg2-bin python3 python3-yaml +``` + +Das eigentliche Bauen der Dokumente ist dann nur noch ein einziger Befehl: + +```bash +python3 build.py +``` + +Die fertigen Dokumente finden sich dann sich in `build/`. + +Ein einzelnes Ausgabeformat kann mit `python3 build.py ` erstellt werden, mit `python3 build.py archives` können +Archive mit allen Ausgabeformaten gepackt werden. Dazu müssen allerdings +die enstprechenden Archivierungsprogramme vorhanden sein. + +### Docker + +Für den geneigten Containerfreund gibt es ein Container, der alle Tools enthält. +Auch hier ein Ausgabeformat an den Aufruf angehängt werden kann: + +``` +docker run -u $UID:$GID --rm -v $(pwd):$(pwd) -w $(pwd) oparl/specbuilder:latest +``` + +## Aufbau des Repositories + +Die Dateien, aus denen die Spezifikation erstellt wird, sind auf mehrere Ordner aufgeteilt: + + - `src/`: Enthält den gesamten Fließtext als [Markdown][markdown-help]-Dateien. + - `schema/`: Enthält das Datenmodell, d.h. den Aufbau der von OParl genutzten json-Objekte, als json-Dateien in einem + auf [JSON Schema][json-schema] aufbauenden Format. + - `examples/`: Die im Text eingebundenen Beispiele + - `scripts/`: Enthält Skripte, die u.a. die json-Dateien in Markdown umwandeln und die Beispiele validieren + + [oparl]: https://oparl.org/ [oparl-dev]: https://dev.oparl.org/ -[travis]: https://travis-ci.org/OParl/spec/ - +[ghostscript]: https://www.ghostscript.com/ [github-help]: https://help.github.com/ -[building]: building.md +[graphviz]: http://www.graphviz.org/ +[imagemagick]: https://www.imagemagick.org/script/index.php +[json-schema]: https://json-schema.org/ +[markdown-help]: https://help.github.com/articles/markdown-basics/ +[pandoc]: http://pandoc.org/ +[python]: https://www.python.org/ +[tar]: https://www.gnu.org/software/tar/ +[travis]: https://travis-ci.org/OParl/spec/ +[zip]: http://www.info-zip.org/ [spec-1-0-pdf]: https://dev.oparl.org/downloads/spezifikation-1.0.pdf [spec-1-0-html]: https://dev.oparl.org/downloads/spezifikation-1.0.html diff --git a/build.py b/build.py new file mode 100755 index 0000000..f951cdf --- /dev/null +++ b/build.py @@ -0,0 +1,349 @@ +#!/usr/bin/env python3 +# This program is part of OParl and may be used to build the specification + +import os +import shlex +import shutil +import subprocess +import sys +from argparse import ArgumentParser +from glob import glob +from os import path + +from scripts.json_schema2markdown import schema_to_markdown + +SPECIFICATION_BUILD_ACTIONS = [ + 'all', + 'clean', + 'test', + 'live', + 'html', + 'pdf', + 'odt', + 'docx', + 'txt', + 'epub', + 'archives', + 'zip', + 'gz', + 'bz' +] + +SPECIFICATION_BUILD_TOOLS = [ + 'pandoc', + 'dot', + 'xelatex', + 'gs', + 'convert', + 'python3', + 'tar', + 'zip' +] + +SPECIFICATION_BUILD_FLAGS = { + 'gs': '-dQUIET -dSAFER -dBATCH -dNOPAUSE -sDisplayHandle=0 -sDEVICE=png16m -r600 -dTextAlphaBits=4', + 'pandoc': '--from markdown --standalone --table-of-contents --toc-depth=2 --number-sections' +} + + +def configure_argument_parser(): + parser = ArgumentParser( + prog='./build.py', + epilog=''' + build.py is part of the OParl Specification and thus distributed + under the terms of the Creative Commons SA 4.0 License. + ''' + ) + + parser.add_argument( + '--language', + '-l', + help='Specification language', + default='de', + action='store', + ) + + parser.add_argument( + '--version', + '-V', + help='This will be displayed as version in the specification. Defaults to `git desribe`', + action='store', + ) + + parser.add_argument( + '--print-basename', + help='This will output the base name used for build output', + action='store_true', + dest='print_basename' + ) + + parser.add_argument( + '--latex-template', + help='Change the latex template used for PDF generation', + action='store', + default='resources/template.tex' + ) + + parser.add_argument( + '--html-style', + help='Change the CSS file used for styling the HTML output', + action='store', + default='resources/html5.css' + ) + + parser.add_argument( + 'action', + help='Build action to take, available actions are: {}'.format(', '.join(SPECIFICATION_BUILD_ACTIONS)), + action='store', + nargs='*' + ) + + return parser + + +def check_build_action(action): + if len(action) == 0: + return 'all' + + if action[0] in SPECIFICATION_BUILD_ACTIONS: + return action[0] + + raise Exception( + 'Unknown build action: {}, choose one of: {}'.format(action, ', '.join(SPECIFICATION_BUILD_ACTIONS))) + + +def get_git_describe_version(): + return subprocess.check_output('git describe', shell=True, universal_newlines=True).strip() + + +def check_available_tools(): + tools = {} + for tool in SPECIFICATION_BUILD_TOOLS: + executable = shutil.which(tool) + if executable: + tools[tool] = executable + else: + raise Exception('{} not found, aborting.'.format(tool)) + + return tools + + +def get_filename_base(language, version): + return 'OParl-{}-{}'.format(version, language) + + +def prepare_builddir(filename_base): + os.makedirs('build/src/images') + os.makedirs('build/{}'.format(filename_base)) + + +def prepare_schema(language): + language_file = 'schema/strings.yml' + if language != 'de': + language_file = 'locales/{}/schema/strings.yml'.format(language) + + output_file = 'build/src/9-99-schema.md' + + schema_to_markdown('schema', 'examples', output_file, language, language_file) + + +def prepare_markdown(language): + glob_pattern = 'src/*.md' + if language != 'de': + glob_pattern = 'locales/en/*.md' + + files = glob(glob_pattern) + for f in files: + shutil.copy2(f, 'build/src/') + + +def prepare_images(tools): + glob_pattern = 'src/images/*.*' + + files = glob(glob_pattern) + for f in files: + convert_command = '' + filename, extension = os.path.splitext(f) + fout = path.join('build', 'src', 'images', os.path.basename(filename) + '.png') + + shutil.copy2(f, fout) + + if extension == '.pdf': + convert_command = '{} {} -sOutputFile={} -f {}'.format( + tools['gs'], + SPECIFICATION_BUILD_FLAGS['gs'], + fout, + f + ) + + if extension == '.dot': + convert_command = '{} -Tpng {} -o {}'.format( + tools['dot'], + f, + fout + ) + + if extension == '.svg': + convert_command = '{} {} {}'.format( + tools['convert'], + f, + fout + ) + + cmd = shlex.split(convert_command) + try: + subprocess.run(cmd, check=True) + except subprocess.CalledProcessError: + raise Exception( + 'Errored on image prep for {}, please check the command:\n{}'.format( + f, convert_command + ) + ) + + +def get_pandoc_version(pandoc_bin): + version_tuple = subprocess.getoutput('{} --version'.format(pandoc_bin)).split('\n')[0].split(' ')[1].split('.') + return [int(v) for v in version_tuple] + + +def run_pandoc(pandoc_bin, filename_base, output_format, extra_args='', extra_files=''): + output_file = 'build/{}/{}.{}'.format(filename_base, filename_base, output_format) + if path.exists(output_file): + return + + source_files = glob('build/src/*.md') + source_files.sort(key=lambda file: path.basename(file)) + + # NOTE: Once we can safely assume pandoc 2.0, we can use resource-path + # for neater include management in the markdown files + # pandoc_command = '{} {} {} --resource-path=.:build/src -o {} {} {}'.format( + pandoc_command = '{} {} {} -o {} {} {}'.format( + pandoc_bin, + SPECIFICATION_BUILD_FLAGS['pandoc'], + extra_args, + output_file, + extra_files, + ' '.join(source_files) + ) + + cmd = shlex.split(pandoc_command) + try: + subprocess.run(cmd, check=True, stdout=sys.stdout, stderr=sys.stderr) + except subprocess.CalledProcessError: + raise Exception( + 'Errored on pandoc: {}'.format(pandoc_command) + ) + + +class Action: + @staticmethod + def clean(): + shutil.rmtree('build', ignore_errors=True) + + @staticmethod + def test(): + # TODO: validate.py appears to be broken + pass + + @staticmethod + def live(tools, _, filename_base): + args = '--to html5 --section-divs --no-highlight' + run_pandoc(tools['pandoc'], filename_base, 'html', extra_args=args, extra_files='resources/lizenz-als-bild.md') + + @staticmethod + def html(tools, options, filename_base): + args = '--to html5 --css {} --section-divs --self-contained'.format(options.html_style) + run_pandoc(tools['pandoc'], filename_base, 'html', extra_args=args, extra_files='resources/lizenz-als-bild.md') + + @staticmethod + def pdf(tools, options, filename_base): + args = '--pdf-engine=xelatex' + if get_pandoc_version(tools['pandoc'])[0] < 2: + args = '--latex-engine=xelatex' + + args += ' --template {}'.format(options.latex_template) + + run_pandoc(tools['pandoc'], filename_base, 'pdf', extra_args=args) + + @staticmethod + def odt(tools, _, filename_base): + run_pandoc(tools['pandoc'], filename_base, 'odt', extra_files='resources/lizenz-als-text.md') + + @staticmethod + def docx(tools, _, filename_base): + run_pandoc(tools['pandoc'], filename_base, 'docx', extra_files='resources/lizenz-als-text.md') + + @staticmethod + def txt(tools, _, filename_base): + run_pandoc(tools['pandoc'], filename_base, 'txt') + + @staticmethod + def epub(tools, _, filename_base): + run_pandoc(tools['pandoc'], filename_base, 'epub') + + @staticmethod + def all(tools, options, filename_base): + Action.html(tools, options, filename_base) + Action.pdf(tools, options, filename_base) + Action.odt(tools, options, filename_base) + Action.docx(tools, options, filename_base) + Action.txt(tools, options, filename_base) + Action.epub(tools, options, filename_base) + + @staticmethod + def zip(tools, options, filename_base): + Action.all(tools, options, filename_base) + archive_name = '{}.zip'.format(filename_base) + subprocess.run(['zip', '-qr', archive_name, filename_base], cwd='build') + + @staticmethod + def gz(tools, options, filename_base): + Action.all(tools, options, filename_base) + archive_name = '{}.tar.gz'.format(filename_base) + subprocess.run(['tar', '-czf', archive_name, filename_base], cwd='build') + + @staticmethod + def bz(tools, options, filename_base): + Action.all(tools, options, filename_base) + archive_name = '{}.tar.bz2'.format(filename_base) + subprocess.run(['tar', '-cjf', archive_name, filename_base], cwd='build') + + @staticmethod + def archives(tools, options, filename_base): + Action.zip(tools, options, filename_base) + Action.gz(tools, options, filename_base) + Action.bz(tools, options, filename_base) + + +def main(): + options = configure_argument_parser().parse_args() + action = check_build_action(options.action) + + if options.version is None: + options.version = get_git_describe_version() + + filename_base = get_filename_base(options.language, options.version) + + if options.print_basename: + print(filename_base) + exit(0) + + tools = check_available_tools() + + # always clean + Action.clean() + + if action == 'clean': + exit(0) + + prepare_builddir(filename_base) + prepare_schema(options.language) + prepare_markdown(options.language) + prepare_images(tools) + + # Avoid much boilerplate + getattr(Action, action)(tools, options, filename_base) + + +if __name__ == '__main__': + main() diff --git a/building.md b/building.en.md similarity index 100% rename from building.md rename to building.en.md diff --git a/locales/en/schema/strings.yml b/locales/en/schema/strings.yml new file mode 100644 index 0000000..578a5b2 --- /dev/null +++ b/locales/en/schema/strings.yml @@ -0,0 +1 @@ +en: {} diff --git a/locales/en/src/0-00-einleitung.md b/locales/en/src/0-00-einleitung.md new file mode 100644 index 0000000..e16cfae --- /dev/null +++ b/locales/en/src/0-00-einleitung.md @@ -0,0 +1,3 @@ +# Introduction {#einleitung} + +This document contains the specification of the OParl interface standard for parliamentary information systems ^ [in Germany the term "Ratsinformationssystem" is established at the municipal level. However, OParl is not limited to municipal councils and therefore the term "parliamentary information system" is being used. It serves as the basis for the implementation of OParl compliant server and client applications. diff --git a/locales/en/src/0-00-metadata.md b/locales/en/src/0-00-metadata.md new file mode 100644 index 0000000..a145b8f --- /dev/null +++ b/locales/en/src/0-00-metadata.md @@ -0,0 +1,8 @@ +--- +title: OParl-Spezifikation 1.0 Entwurf +rights: CC BY-SA 4.0 +language: en-US +author: OParl contributors +description: Spezifikation einer einheitlichen Schnittstelle zum Abruf von maschinenlesbaren Informationen aus Ratsinformationssystemen. +toc-title: Table Of Contents +--- diff --git a/locales/en/src/0-02-zielsetzung-von-oparl.md b/locales/en/src/0-02-zielsetzung-von-oparl.md new file mode 100644 index 0000000..588a792 --- /dev/null +++ b/locales/en/src/0-02-zielsetzung-von-oparl.md @@ -0,0 +1,50 @@ +## Zielsetzung von OParl {#zielsetzung-von-oparl} + +OParl is aimed at several user groups and stakeholders: + +* Verwaltungen und andere politische Gremien in Gebietskörperschaften +* Bürger, politische Parteien und Organisationen +* Open Data Initiatives +* scientists +* Anbieter von Server- und Softwareprodukten im Umfeld von parlamentarischen Informationssystemen und Öffentlichkeitsbeteiligung + +Die Gründe, warum Betreiber von parlamentarischen Informationssystemen den +Zugriff darauf über eine standardisierte Schnittstelle ermöglichen sollten +oder möchten, können vielfältig und je nach Nutzergruppe unterschiedlich sein. + +Ein zentrales Argument für Verwaltung und politische Gremien, sei es in +Gebietskörperschaften oder auf Landes- oder Bundesebene, +ist die Verpflichtung der Parlamente gegenüber der +Bevölkerung, diese über die Fortschritte der parlamentarischen Arbeit zu +informieren und auf dem Laufenden zu halten. Ein erster Schritt, der +Bevölkerung Einblicke in die Arbeit und Zugriff auf Dokumente zu gewähren, +ist vielerorts in den letzten Jahren durch Einführung von Ratsinformationssystemen +mit anonymem, lesendem Zugriff über das World Wide Web gemacht worden. + +Die damit eingeschlagene Richtung konsequent weiter zu gehen, bedeutet, die Daten der parlamentarischen Informationssysteme soweit offen zu legen, wie die Inhalte es erlauben. Es bedeutet, die Daten und Inhalte so universell weiterverwendbar und so barrierearm wie möglich anzubieten, dass jegliche weitere Verwendung durch Dritte technisch möglich ist. Der seit einiger Zeit etablierte Begriff für dieses Prinzip heißt "Open Data". + +Open-Data-Initiativen können unter Rückgriff auf Ratsinformationssysteme (RIS) mit OParl-Schnittstelle einfacher Dokumente und Daten aus unterschiedlichen Gebietskörperschaften in Open-Data-Katalogen verzeichnen und so einfacher auffindbar machen für die Weiterverwendung durch Dritte. + +Bürgerinnen und Bürger, politische Parteien und zivilgesellschaftliche Organisationen können einfacher auf Inhalte parlamentarischer Informationssysteme zugreifen und diese entsprechend ihren Interessen aufbereiten. Dies können beispielsweise Visualisierungen von enthaltenen Daten, die Anreicherung von Informationsangeboten für spezielle Nutzergruppen oder die Schaffung von Benutzeroberflächen mit besonderen Funktionen für verschiedene Endgeräte sein. + +Das Interesse an parlamentarischen Informationen und an Anwendungen, die diese nutzbar und auswertbar machen, ist offensichtlich vorhanden. Die Entwickler der alternativen Ratsinformationssysteme wie Frankfurt Gestalten^[Frankfurt Gestalten: ], Offenes Köln oder der OpenRuhr:RIS-Instanzen (die letzten beiden wurden zusammengeführt in Politik Bei Uns^[Politik Bei Uns: ]) wissen zu berichten, wie viel Interesse den Projekten gerade aus Orten entgegen gebracht wird, in denen derartige Systeme noch nicht verfügbar sind. + +Die Anwendungsmöglichkeiten für parlamentarische Informationen, wenn sie über eine Schnittstelle schnell und einfach abgerufen werden können, sind vielfältig. Beispiele sind: + +* Apps für den Abruf auf mobilen Endgeräten +* Möglichkeiten zur Wiedergabe für Nutzerinnen und Nutzer mit Beeinträchtigung des Sehvermögens + Alternative und erweiterte Suchmöglichkeiten in Inhalten +* Auswertung und Analyse von Themen, Inhalten, Sprache etc. +* Benachrichtigungsfunktionen beim Erscheinen bestimmter Inhalte +* Die Standardisierung dieses Zugriffs über die Grenzen einzelner Systeme hinweg erlaubt zudem, diese Entwicklungen auch geographisch und politisch grenzüberschreitend zu denken. Damit steigt nicht nur die potenzielle Nutzerschaft einzelner Entwicklungen. Auch das Potenzial für Kooperationen zwischen Anwendungsentwicklern wächst. + +Für Wissenschaftler, die z. B. an vergleichenden Untersuchungen zu Vorgängen in verschiedenen Gebietskörperschaften interessiert sind, ergeben sich ebenso vielfältige Möglichkeiten über mehrere RIS-Instanzen hinweg auf entsprechende Informationen zuzugreifen und diese so einfacher in ihre Analysen einzubeziehen. + +Darüber hinaus sind auch Motivationen innerhalb von Organisationen und Körperschaften erkennbar. So sollen parlamentarische Informationssysteme vielerorts in verschiedenste Prozesse und heterogene Systemlandschaften integriert werden. Durch eine einheitliche Schnittstelle bieten sich effiziente Möglichkeiten zur Integration der Daten in anderen Systeme, wie beispielsweise Webportale. + +Anbieter von Softwareprodukten, die RIS-Lösungen anbieten, können ihren Kunden mit der Implementation der OParl-Schnittstelle eine entsprechende einheitliche Schnittstelle anbieten. + +Ausführlichere Beschreibungen einiger möglicher Anwendungsszenarien finden sich im Kapitel [Nutzungsszenarien](#nutzungsszenarien). + +Ausführlichere Beschreibungen einiger möglicher Anwendungsszenarien finden sich +im Kapitel [Nutzungsszenarien](#nutzungsszenarien). diff --git a/locales/en/src/1-00-einleitung.md b/locales/en/src/1-00-einleitung.md new file mode 100644 index 0000000..e16cfae --- /dev/null +++ b/locales/en/src/1-00-einleitung.md @@ -0,0 +1,3 @@ +# Introduction {#einleitung} + +This document contains the specification of the OParl interface standard for parliamentary information systems ^ [in Germany the term "Ratsinformationssystem" is established at the municipal level. However, OParl is not limited to municipal councils and therefore the term "parliamentary information system" is being used. It serves as the basis for the implementation of OParl compliant server and client applications. diff --git a/locales/en/src/1-01-was-ist-oparl.md b/locales/en/src/1-01-was-ist-oparl.md new file mode 100644 index 0000000..56580c4 --- /dev/null +++ b/locales/en/src/1-01-was-ist-oparl.md @@ -0,0 +1,7 @@ +## What is OParl? {#was_ist_oparl} + +OParl is the grouping which is the initiator and editor of the present specification. Contributers to OParl are public associations, civil sociate organisations, software vendors as well as interested individuals. + +This document specifies the OParl standard. Dieser definiert eine Webserviceschnittstelle, die den anonymen, lesenden Zugriff auf öffentliche Inhalte aus parlamentarischen Informationssystemen ermöglicht. Wie der Name "Webservice" ausdrückt, setzt diese Schnittstelle auf dem World Wide Web auf. Sie ermöglicht, dass parlamentarische Informationen maschinenlesbar als offene Daten (Open Data) veröffentlicht werden. + +Die vorliegende Version ist die erste verabschiedete Version der Spezifikation des OParl-Standards. diff --git a/locales/en/src/1-02-zielsetzung-von-oparl.md b/locales/en/src/1-02-zielsetzung-von-oparl.md new file mode 100644 index 0000000..588a792 --- /dev/null +++ b/locales/en/src/1-02-zielsetzung-von-oparl.md @@ -0,0 +1,50 @@ +## Zielsetzung von OParl {#zielsetzung-von-oparl} + +OParl is aimed at several user groups and stakeholders: + +* Verwaltungen und andere politische Gremien in Gebietskörperschaften +* Bürger, politische Parteien und Organisationen +* Open Data Initiatives +* scientists +* Anbieter von Server- und Softwareprodukten im Umfeld von parlamentarischen Informationssystemen und Öffentlichkeitsbeteiligung + +Die Gründe, warum Betreiber von parlamentarischen Informationssystemen den +Zugriff darauf über eine standardisierte Schnittstelle ermöglichen sollten +oder möchten, können vielfältig und je nach Nutzergruppe unterschiedlich sein. + +Ein zentrales Argument für Verwaltung und politische Gremien, sei es in +Gebietskörperschaften oder auf Landes- oder Bundesebene, +ist die Verpflichtung der Parlamente gegenüber der +Bevölkerung, diese über die Fortschritte der parlamentarischen Arbeit zu +informieren und auf dem Laufenden zu halten. Ein erster Schritt, der +Bevölkerung Einblicke in die Arbeit und Zugriff auf Dokumente zu gewähren, +ist vielerorts in den letzten Jahren durch Einführung von Ratsinformationssystemen +mit anonymem, lesendem Zugriff über das World Wide Web gemacht worden. + +Die damit eingeschlagene Richtung konsequent weiter zu gehen, bedeutet, die Daten der parlamentarischen Informationssysteme soweit offen zu legen, wie die Inhalte es erlauben. Es bedeutet, die Daten und Inhalte so universell weiterverwendbar und so barrierearm wie möglich anzubieten, dass jegliche weitere Verwendung durch Dritte technisch möglich ist. Der seit einiger Zeit etablierte Begriff für dieses Prinzip heißt "Open Data". + +Open-Data-Initiativen können unter Rückgriff auf Ratsinformationssysteme (RIS) mit OParl-Schnittstelle einfacher Dokumente und Daten aus unterschiedlichen Gebietskörperschaften in Open-Data-Katalogen verzeichnen und so einfacher auffindbar machen für die Weiterverwendung durch Dritte. + +Bürgerinnen und Bürger, politische Parteien und zivilgesellschaftliche Organisationen können einfacher auf Inhalte parlamentarischer Informationssysteme zugreifen und diese entsprechend ihren Interessen aufbereiten. Dies können beispielsweise Visualisierungen von enthaltenen Daten, die Anreicherung von Informationsangeboten für spezielle Nutzergruppen oder die Schaffung von Benutzeroberflächen mit besonderen Funktionen für verschiedene Endgeräte sein. + +Das Interesse an parlamentarischen Informationen und an Anwendungen, die diese nutzbar und auswertbar machen, ist offensichtlich vorhanden. Die Entwickler der alternativen Ratsinformationssysteme wie Frankfurt Gestalten^[Frankfurt Gestalten: ], Offenes Köln oder der OpenRuhr:RIS-Instanzen (die letzten beiden wurden zusammengeführt in Politik Bei Uns^[Politik Bei Uns: ]) wissen zu berichten, wie viel Interesse den Projekten gerade aus Orten entgegen gebracht wird, in denen derartige Systeme noch nicht verfügbar sind. + +Die Anwendungsmöglichkeiten für parlamentarische Informationen, wenn sie über eine Schnittstelle schnell und einfach abgerufen werden können, sind vielfältig. Beispiele sind: + +* Apps für den Abruf auf mobilen Endgeräten +* Möglichkeiten zur Wiedergabe für Nutzerinnen und Nutzer mit Beeinträchtigung des Sehvermögens + Alternative und erweiterte Suchmöglichkeiten in Inhalten +* Auswertung und Analyse von Themen, Inhalten, Sprache etc. +* Benachrichtigungsfunktionen beim Erscheinen bestimmter Inhalte +* Die Standardisierung dieses Zugriffs über die Grenzen einzelner Systeme hinweg erlaubt zudem, diese Entwicklungen auch geographisch und politisch grenzüberschreitend zu denken. Damit steigt nicht nur die potenzielle Nutzerschaft einzelner Entwicklungen. Auch das Potenzial für Kooperationen zwischen Anwendungsentwicklern wächst. + +Für Wissenschaftler, die z. B. an vergleichenden Untersuchungen zu Vorgängen in verschiedenen Gebietskörperschaften interessiert sind, ergeben sich ebenso vielfältige Möglichkeiten über mehrere RIS-Instanzen hinweg auf entsprechende Informationen zuzugreifen und diese so einfacher in ihre Analysen einzubeziehen. + +Darüber hinaus sind auch Motivationen innerhalb von Organisationen und Körperschaften erkennbar. So sollen parlamentarische Informationssysteme vielerorts in verschiedenste Prozesse und heterogene Systemlandschaften integriert werden. Durch eine einheitliche Schnittstelle bieten sich effiziente Möglichkeiten zur Integration der Daten in anderen Systeme, wie beispielsweise Webportale. + +Anbieter von Softwareprodukten, die RIS-Lösungen anbieten, können ihren Kunden mit der Implementation der OParl-Schnittstelle eine entsprechende einheitliche Schnittstelle anbieten. + +Ausführlichere Beschreibungen einiger möglicher Anwendungsszenarien finden sich im Kapitel [Nutzungsszenarien](#nutzungsszenarien). + +Ausführlichere Beschreibungen einiger möglicher Anwendungsszenarien finden sich +im Kapitel [Nutzungsszenarien](#nutzungsszenarien). diff --git a/locales/en/src/1-03-transparenz-und-beteiligung-durch-open-data.md b/locales/en/src/1-03-transparenz-und-beteiligung-durch-open-data.md new file mode 100644 index 0000000..549f7b5 --- /dev/null +++ b/locales/en/src/1-03-transparenz-und-beteiligung-durch-open-data.md @@ -0,0 +1,61 @@ +## Transparenz und Beteiligung durch Open Data {#transparenz-und-beteiligung-durch-open-data} + +Öffentliche Stellen verfügen über vielfältige Informationen und Daten. Seit einigen +Jahren sind zivilgesellschaftliche Organisationen sowie Politik und Verwaltung unter +dem Schlagwort *Open Data* international und auch in Deutschland um eine stärkere Öffnung dieser Daten bemüht^[Eine weltweite Übersicht zu +Open-Data-Projekten bietet z. B. der Open-Data-Showroom ]. +Bei dem Ansatz Open Data^[vgl. ] geht es +darum, diese Daten so bereitzustellen, dass Dritte diese einfacher finden und +weiterverwenden können. + +Die zehn Open-Data-Prinzipien der Sunlight-Foundation^[Ten +Principles for Opening Up Open Government Information, +] beschreiben +die Offenheit von Datensätzen. Wesentlich dabei sind vor allem die einfache rechtliche +und die technische Offenheit. Bei ersterer geht es darum, dass Datensätze unter +Nutzungsbestimmungen bereitgestellt werden, die kurz und verständlich formuliert +sind und mindestens jegliche weitere Verwendung inklusive der kommerziellen erlauben, +unter der Voraussetzung, dass bei der Weiterverwendung die Quelle benannt wird. Bei +der technischen Offenheit steht die Bereitstellung von Datensätzen in möglichst +maschinenlesbaren Formaten im Vordergrund. Dies bedeutet, stärker strukturierte +Datensätze sind in der Bereitstellung zu bevorzugen. Liegen Daten innerhalb einer +Organisation in einer Datenbank vor, so bietet es sich an, diese +über eine Programmierschnittstelle (API) für Außenstehende bereitzustellen. + +Die Erfüllung dieser rechtlichen und technischen Offenheit erlaubt es im +Falle von OParl Dritten – dies können Bürgerinnen und Bürger, Unternehmen, +Forschungseinrichtungen oder auch andere Verwaltungseinheiten sein – +die Verwaltungsdaten wesentlich unkomplizierter für eigene Vorhaben wie +Anwendungen oder Visualisierungen einzusetzen. Mit dem Ansatz offener +Verwaltungsdaten soll so erstens mehr Transparenz über Prozesse und +Entscheidungen in Politik und Verwaltung erreicht werden. Zweitens können +Dritte auf Grundlage dieser Daten leichter eigene Geschäftsmodelle verfeinern +oder neue entwickeln. Drittens wird es auch öffentlichen Stellen selbst +erleichtert bereits im öffentlichen Sektor existierende Daten zu finden und +weiterzuverwenden. + +Das Prinzip offener Daten bzw. offener Verwaltungsdaten über die +Minimalprinzipien rechtlicher und technischer Offenheit hinaus in die Tat +umzusetzen, erfordert im Einzelfall häufig eine Zusammenarbeit von +Datenbereitstellern und potentiellen Datennutzern. Die bloße Bereitstellung +einer OParl-konformen API wird weder die +Einhaltung der technischen Prinzipien, noch der weiteren Open-Data-Prinzipien vollständig +garantieren. Viele Bestandteile der OParl-Spezifikation, die einen weitgehend +barrierearmen Zugang zu Informationen[^1] ermöglichen sollen, sind in der +vorliegenden Version noch optional (Beispiel: Volltexte von Dokumenten über +die API abrufbar machen). Andere Bestandteile,die von Interesse wären, sind +noch gar nicht von OParl abgedeckt (Beispiel: Abstimmungsergebnisse). +Grund dafür ist, dass sich OParl in einem frühen Stadium befindet und primär am Status Quo der +parlamentarischen Informationssysteme ausgerichtet ist. Es liegt also auch weiterhin an +Verwaltung und Politik, durch einen verantwortungsvollen Umgang mit den Systemen die +maximal erreichbare Transparenz zu bieten. Das fängt bei verfügbaren Dokumentformaten an +(ein PDF mit digitalem Text weist weit weniger Barrieren auf, als ein gescannter Brief, +der ebenfalls als PDF gespeichert wurde) und hört bei der verwendeten Sprache auf[^2]. + +[^1]: Barrierefreie Informationstechnik-Verordnung 2.0 + +[^2]: Weitere generelle Informationen zur Bereitstellung offener Verwaltungsdaten bieten +i.e. + + * Praktische Informationen: Open-Data-Handbook der Open Knowledge Foundation + * Grundsätzliche Informationen: Die vom Bundesministerium des Innern beauftragte Studie "Open Government Data Deutschland" diff --git a/locales/en/src/1-04-nutzungsszenarien.md b/locales/en/src/1-04-nutzungsszenarien.md new file mode 100644 index 0000000..2a1d51a --- /dev/null +++ b/locales/en/src/1-04-nutzungsszenarien.md @@ -0,0 +1,51 @@ +## Nutzungsszenarien {#nutzungsszenarien} + +Für OParl sind verschiedene Nutzungsszenarien denkbar. Die Nachfolgende +Auflistung soll einen kleinen Überblick geben, erhebt aber bei weitem keinen +Anspruch auf Vollständigkeit: + +### Mobile Anwendung {#szenario-mobile-anwendung} + +Eine Anwendung für mobile Endgeräte wie Smartphones und Tablets, nachfolgend +"App" genannt, könnte das Ziel verfolgen, Nutzern unterwegs, sowie abseits +vom Desktop-PC optimierten Zugriff auf ein parlamentarisches +Informationssystem zu ermöglichen. Dies könnte auch zur Vereinfachung der bisherigen Prozesse beitragen, da Nutzerinnen z.B. die Möglichkeit gegeben werden kann, auf Einladungen zu reagieren, oder Protokolle zu lesen. + +### Integration in ein Webportal {#szenario-webportal} + +Portallösungen bieten den Betreibern die Möglichkeit, Inhalte auf einer +einheitlichen Weboberfläche zu veröffentlichen, die aus verschiedensten +Quellen und Plattformen bereitgestellt werden. Ein Beispiel für die +Realisierung eines solchen Integrations-Ansatzes wäre eine Kommune, die für +ihre allgemeine Website eine Portallösung einsetzt und hier auch Inhalte aus +dem kommunalen Ratsinformationssystem einspeisen und darstellen möchte. +Vorteil einer solchen Einbindung, also der kontextbezogenen Darstellung von +parlamentarischen Informationen im Gegensatz zu einem monolithischen +parlamentarischen Informationssystem könnte sein, dass Nutzer in einer +gewohnten und akzeptierten Oberfläche jeweils die relevanten Informationen +erhalten, ohne sich an die ungewohnte Umgebung eines parlamentarischen +Informationssystems gewöhnen zu müssen. + +### Meta-Suche {#szenario-meta-suche} + +Die Ermöglichung einer nutzerfreundlichen Suche, die damit verbundene +Indexierung von verschiedensten Dokumenteninhalten und die Kategorisierung +von Inhalten kann eine sowohl konzeptionell als auch technisch +anspruchsvolle Aufgabe sein. Angelehnt an das seit den Anfängen des Webs +etablierte Modell der externen Web-Suchmaschine sind spezielle Suchmaschinen +für OParl-konforme parlamentarische Informationssysteme denkbar. Solche +Plattformen treten gegenüber dem OParl-Server als Client auf und rufen +bestimmte oder sämtliche Informationen, die das System bereithält, ab. +Vorbild sind die Robots oder Spider von Web-Suchmaschinen. Die abgerufenen +Informationen können dann indexiert und je nach Anforderungen für eine +gezielte Suche weiterverarbeitet werden. + +### Forschungsprojekt "Themenanalyse" {#szenario-forschung} + +In einem Forschungsprojekt sollen Pro- und Contra-Argumentationen bei +Ratsdiskussionen zum Ausbau von Stromtrassen identifiziert werden. Dazu +nutzen die Mitarbeitenden des Forschungsprojektes die OParl-Schnittstellen +der parlamentarischen Informationssysteme aller Kommunen entlang der +geplanten überregionalen Trassen. Über diese einheitlichen Schnittstellen +können sie insbesondere die relevanten Wortprotokolle abrufen und zum +Beispiel in einem Werkzeug zur qualitativen Datenanalyse lokal verarbeiten. diff --git a/locales/en/src/1-05-nomenklatur.md b/locales/en/src/1-05-nomenklatur.md new file mode 100644 index 0000000..f7572e9 --- /dev/null +++ b/locales/en/src/1-05-nomenklatur.md @@ -0,0 +1,88 @@ +## Nomenklatur {#nomenklatur} + +### Zwingende, empfohlene und optionale Anforderungen {#muss_sollte_darf} + +Dieses Spezifikation nutzt **müssen**, **können** und **sollten** +in einer eindeutig definierten Art und Weise. Diese ist angelehnt an die +Definitionen der Begriffe MUST, SHOULD und MAY (bzw. MUST NOT, SHOULD NOT und +MAY NOT) aus RFC2119.^[RFC2119 ] + +Die Bedeutung im Einzelnen: + +**müssen**/**muss** bzw. **zwingend**: + +: Die Erfüllung einer so gekennzeichneten Anforderung ist zwingend erforderlich. + + Die Entsprechung in RFC2119 lautet "MUST", "REQUIRED" oder "SHALL". + +**nicht dürfen**/**darf nicht**: + +: Dieses Stichwort kennzeichnet ein absolutes Verbot. + + Die Entsprechung in RFC2119 lautet "MUST NOT" oder "SHALL NOT". + +**sollten**/**sollte** bzw. **empfohlen**: + +: Mit dem Wort **sollten** bzw. **sollte** sind empfohlene Anforderungen gekennzeichnet, + die von jeder Implementierung erfüllt werden sollten. Eine Nichterfüllung + ist als Nachteil zu verstehen, beispielsweise weil die Nutzerfreundlichkeit + dadurch Einbußen erleidet, und sollte daher sorgfältig abgewogen werden. + + Die Entsprechung in RFC2119 lautet "SHOULD" oder "RECOMMENDED". + +**sollten nicht**/**sollte nicht** bzw. **nicht empfohlen**: + +: Diese Formulierung wird verwendet, wenn unter gewissen Umständen Gründe + existieren können, die ein bestimmtes Verhalten akzeptabel oder sogar + nützlich erscheinen lassen, jedoch die Auswirkung des Verhaltens vor + einer entsprechenden Implementierung verstanden und abgewogen werden + sollten. + + Die Entsprechung in RFC2119 lautet "SHOULD NOT" oder "NOT RECOMMENDED". + +**dürfen**/**darf** bzw. **optional**: + +: Mit dem Wort **dürfen** bzw. **darf** oder **optional** sind optionale Bestandteile + gekennzeichnet. Ein Anbieter könnte sich entscheiden, den entsprechenden + Bestandteil aufgrund besonderer Kundenanforderungen zu unterstützen, + während andere diesen Bestandteil ignorieren könnten. Implementierer von + Clients oder Servern **dürfen** in solchen Fällen **nicht** davon ausgehen, dass der + jeweilige Kommunikationspartner den entsprechenden, optionalen Anteil + unterstützt. + + Die Entsprechung in RFC2119 lautet "MAY". + + +### Geschlechterspezifische Begrifflichkeiten {#geschlechterspezifische-begrifflichkeiten} + +Um bei Begriffen wie Nutzer, Anwender, Betreiber etc. die sonst übliche Dominanz +der männlichen Variante zu vermeiden, werden in diesem Dokument +männliche und weibliche Varianten gemischt. Gemeint sind in allen Fällen +Personen jeglichen Geschlechts. + + +### Codebeispiele {#codebeispiele} + +Die in diesem Dokument aufgeführten Codebeispiele dienen der Veranschaulichung +der beschriebenen Prinzipien. Es handelt sich um frei erfundene Daten. + +Codebeispiele erheben insbesondere bei JSON-Code nicht den Anspruch auf +syntaktische Korrektheit und Vollständigkeit. Dementsprechend können in +Codebeispielen Auslassungen vorkommen, die mit `...` gekennzeichnet werden. + + +### Namespace-Präfixe für Objekt- und Datentypen {#namespace-praefixe-fuer-objekt-und-datentypen} + +Bei der Erwähnung von Objekttypen, die in dieser Spezifikation beschrieben +werden, wird in der Regel ein Präfix `oparl:` vor den Namen gesetzt, z. B. +"oparl:Organization". Damit soll verdeutlicht werden, dass der Objekttyp +innerhalb der OParl-Spezifikation gemeint ist. + +Das Präfix `oparl:` steht hierbei für die folgende Namespace-URL: + + https://schema.oparl.org/1.1/ + +Dadurch kann eine Typenangabe wie `oparl:Organization` eindeutig in die +folgende URL übersetzt werden: + + https://schema.oparl.org/1.1/Organization diff --git a/locales/en/src/1-06-datenschutz.md b/locales/en/src/1-06-datenschutz.md new file mode 100644 index 0000000..376cd9e --- /dev/null +++ b/locales/en/src/1-06-datenschutz.md @@ -0,0 +1,13 @@ +## Privacy {#datenschutz} + +Gemäß der Grundlage "öffentliche Daten nutzen, private Daten schützen" hat +Datenschutz auch bei OParl eine hohe Priorität. Hierbei ist die deutsche +Datenschutz-Gesetzgebung zu beachten. + +Um personenbezogene Daten zu veröffentlichen, ist üblicherweise eine explizite +Zustimmung der betroffenen Person erforderlich. Dies gilt für die bestehende +Weboberfläche des Ratsinformationssystems ebenso wie für die OParl- +Schnittstelle. Eine besondere Beachtung sollten hierbei unter anderem E-Mail- +Adressen, Anschriften, Fotos und Anwesenheitslisten finden. Es wird +empfohlen, vor Veröffentlichung über die Schnittstelle den zuständigen +Datenschutzbeauftragten zu kontaktieren. diff --git a/locales/en/src/1-07-oparl-governance.md b/locales/en/src/1-07-oparl-governance.md new file mode 100644 index 0000000..443bb47 --- /dev/null +++ b/locales/en/src/1-07-oparl-governance.md @@ -0,0 +1,16 @@ +## OParl Governance {#oparl-governance} + +Im Verlauf der Weiterentwicklung können wie bei jedem Standardisierungsprozess +Konflikte über die Ausrichtung und die Implementierung entstehen. Ist dies der +Fall, so sollte als erstes der +[Issue Tracker auf Github](https://github.com/OParl/spec/issues/) +für eine offene Diskussion und eine konstruktive Lösung verwendet werden. + +Sollte es auf Github wider Erwarten keine Lösung geben, wird die Entscheidung +an das OParl-Schlichtungsgremium weitergegeben. In diesem Gremium vertreten sind +Entwickler, Anwender und Datenbereitsteller, so dass eine ausgewogene +Weiterentwicklung im Interesse aller Akteure gewahrt bleibt. + +Es ist natürlich unabhängig davon jederzeit erlaubt, einen Fork der +OParl-Schnittstelle zu erstellen und dort neue zunächst nicht mehrheitsfähige +Konzepte, Features und Funktionen auszuprobieren. diff --git a/locales/en/src/1-08-oparl-autoren.md b/locales/en/src/1-08-oparl-autoren.md new file mode 100644 index 0000000..1229595 --- /dev/null +++ b/locales/en/src/1-08-oparl-autoren.md @@ -0,0 +1,24 @@ +## Authors {#oparl-autoren} + +Folgende Personen haben an OParl 1.0 mitgewirkt: + +Jayan Areekadan, +Jan Erhardt, +Stefan Graupner, +Lucas Jacob, +Jens Klessmann (\*), +Andreas Kuckartz (\*\*), +Ernesto Ruge, +Konstantin Schütze, +Babett Schalitz, +Tim Scheuermann, +Christine Siegfried (\*), +Ralf Sternberg, +Marian Steinbach (\*), +Bernd Thiem, +Thomas Tursics, +Jakob Voss, +Marianne Wulff(\*) + +(\*): Initiator(in), (\*\*): bis 4.7.2014 + diff --git a/locales/en/src/2-00-prinzipien-und-funktionen-der-schnittstelle.md b/locales/en/src/2-00-prinzipien-und-funktionen-der-schnittstelle.md new file mode 100644 index 0000000..e6e2985 --- /dev/null +++ b/locales/en/src/2-00-prinzipien-und-funktionen-der-schnittstelle.md @@ -0,0 +1 @@ +# Principles and features of the interface {#prinzipien-und-funktionen-der-schnittstelle} diff --git a/locales/en/src/2-01-designprinzipien.md b/locales/en/src/2-01-designprinzipien.md new file mode 100644 index 0000000..851bc44 --- /dev/null +++ b/locales/en/src/2-01-designprinzipien.md @@ -0,0 +1,92 @@ +## Designprinzipien {#designprinzipien} + +### Aufbauen auf gängiger Praxis {#aufbauen-auf-gaengiger-praxis} + +Grundlage für die Erarbeitung der OParl-Spezifikation in der vorliegenden Version +ist eine Analyse von aktuell (2012 bis 2016) in Deutschland etablierten +parlamentarischen Informationssystemen und ihrer Nutzung. Erklärtes Ziel für diese erste +Version ist es, mit möglichst geringem Entwicklungsaufwand auf Seite der Softwareanbieter und +ebenso geringem Migrationsaufwand auf Seite der Betreiber zu einer Bereitstellung von parlamentarischen +Informationen über eine OParl-API zu gelangen. Hierbei war es von entscheidender +Bedeutung, dass sich die Informationsmodelle der einschlägigen Softwareprodukte stark +ähneln. Für die OParl-Spezifikation wurde sozusagen ein Datenmodell als "gemeinsamer Nenner" +auf Basis der gängigen Praxis konstruiert. + +### Verbesserung gegenüber dem Status Quo wo möglich {#verbesserung-gegenueber-status-quo} + +Dort, wo es dem Ziel der einfachen Implementierbarkeit und der einfachen Migration +nicht im Weg steht, erlauben sich die Autoren dieser Spezifikation, auch Funktionen +aufzunehmen, die noch nicht als gängige Praxis im Bereich der Ratsinformationssysteme +bezeichnet werden können oder welche nur von einzelnen Systemen unterstützt werden. +Solche Funktionen sind dann so integriert, dass sie nicht als zwingende Anforderung +gelten. + +Ein Beispiel für eine derartige Funktion ist die Abbildung von Geodaten im Kontext von +Drucksachen (`oparl:Paper`), um beispielsweise die Lage eines Bauvorhabens, das in +einer Beschlussvorlage behandelt wird, zu beschreiben. Zwar ist den Autoren nur ein +einziges parlamentarisches Informationssystem^[Das Ratsinformationssystem BoRis, eine +Eigenentwicklung der Stadt Bonn ] +in Deutschland bekannt, das +Geoinformationen – und zwar in Form von Punktdaten, also einer Kombination aus +Längen- und Breitengradangaben – mit Dokumenten verknüpft. Der Vorteil dieser +Funktion ist jedoch anhand zahlreicher Anwendungsszenarien, wie z.B. dem Bauinformationssystem "Bürger baut Stadt"^[bürgerbautstadt, ], belegbar. Somit ist in der +vorliegenden OParl-Spezifikation die Möglichkeit beschrieben, Geodaten-Objekte +einzubetten. + +Die Angabe eines einzelnen Punktes ist dabei der einfachste Fall. Die +Spezifikation erlaubt auch die Kodierung von mehreren Objekten, die Punkte, +Linien oder Polygone repräsentieren können. Vgl. dazu `oparl:Location`. + +Auch die Ausgabe einer Nur-Text-Version im Kontext der Datei (`oparl:File`), +das den barrierefreien Zugriff auf Inhalte oder Indexierung für Volltextsuchfunktionen +deutlich vereinfacht, ist eine Möglichkeit, die in der gängigen Praxis noch nicht zu +finden ist. Ebenso die Möglichkeit, Beziehungen zwischen einzelnen Dateien +herzustellen, um so z.B. von einer Datei zu anderen Dateien mit identischem +Inhalt, aber in anderen technischen Formaten zu verweisen, etwa von einer +ODT-Datei zu einer PDF-Version. + +### Self-documentation {#selbstbeschreibungsfaehigkeit} + +Ausgaben des Servers sollten so beschaffen sein, dass sie für menschliche Nutzerinnen +weitgehend selbsterklärend sein können. Dies betrifft besonders die Benennung von +Objekten und Objekteigenschaften. + +Um den Kreis der Entwicklerinnen und Entwickler, die mit einer OParl-API +arbeiten können, nicht unnötig einzuschränken, wird hierbei grundsätzlich und +soweit sinnvoll auf englischsprachige Begrifflichkeiten gesetzt. + +### Erweiterbarkeit {#erweiterbarkeit} + +Implementierer sollen in der Lage sein, über eine OParl-konforme Schnittstelle auch +solche Informationen auszugeben, die nicht im Rahmen des OParl-Schemas abgebildet werden +können. Dies bedeutet zum einen, dass ein System Objekttypen unterstützen und ausliefern +darf, die nicht (oder noch nicht) im OParl-Schema beschrieben sind. Das bedeutet auch, +dass Objekttypen so um eigene Eigenschaften erweitert werden können, die nicht im OParl +Schema beschrieben sind. + +Ein weiterer Aspekt betrifft die Abwärtskompatibilität, also die Kompatibilität von +OParl-Clients mit zukünftigen Schnittstellen. So können beispielsweise zukünftige Erweiterungen +des OParl-Schemas, etwa um neue Objekttypen, genauso durchgeführt werden, wie die Erweiterungen +um herstellerspezifische Objekttypen. Ein Client muss diese Anteile nicht auswerten, sofern +sie nicht für die Aufgabe des Clients relevant sind. Es bedeutet im Umkehrschluss allerdings auch, dass ein Client +nicht fehlschlagen darf, falls derartige Erweiterungen vorhanden sind. + + +### Browseability/Verlinkung {#browseability_verlinkung} + +Klassische Webservice-Schnittstellen erfordern von den Entwicklern vollständige Kenntnis +der angebotenen Einstiegspunkte und Zugriffsmethoden, gepaart mit sämtlichen unterstützten +URL-Parametern, um den vollen Funktionsumfang der Schnittstelle ausschöpfen zu können. + +Parlamentarische Informationen sind weitgehend in Form von Graphen aufgebaut. Das bedeutet, dass +Objekte häufig mit einer Vielzahl anderer Objekte verknüpft sind. So ist eine Person +beispielsweise Mitglied in mehreren Gremien, das Gremium hat mehrere Sitzungen abgehalten +und zu diesen Sitzungen gibt es jeweils zahlreiche Drucksachen, die ihrerseits wieder +zahlreiche Dokumente enthalten. + +Eine OParl-Schnittstelle gibt jedem einzelnen Objekt eine eindeutige Adresse, eine URL. +Somit kann die Schnittstelle den Verweis von einem Objekt, beispielsweise einem Gremium, +auf ein anderes Objekt, etwa ein Mitglied des Gremiums, dadurch ausgeben, dass im Kontext +des Gremiums die URL des Mitglieds ausgeben wird. Der Client kann somit ausgehend von einem +bestimmten Objekt die zugehörigen Objekte im System finden, indem er einfach den angebotenen +URLs folgt. Dieses Prinzip wird auch "Follow Your Nose"^[] genannt. diff --git a/locales/en/src/2-02-zukunftssicherheit.md b/locales/en/src/2-02-zukunftssicherheit.md new file mode 100644 index 0000000..24692e5 --- /dev/null +++ b/locales/en/src/2-02-zukunftssicherheit.md @@ -0,0 +1,7 @@ +## Zukunftssicherheit {#zukunftssicherheit} + +Sollte in Zukunft eine zu OParl 1.0 inkompatible Version 2.0 erscheinen, kann ein +Server beide Versionen gleichzeitig unterstützen, um mit OParl 1.0 Clients +kompatibel zu bleiben. Dazu muss der Server die OParl 2.0-Schnittstelle unter +einer eigenen URL parallel zur bestehenden OParl 1.0-Schnittstelle anbieten, +siehe Kapitel [System](#system). diff --git a/locales/en/src/2-03-urls.md b/locales/en/src/2-03-urls.md new file mode 100644 index 0000000..5532a72 --- /dev/null +++ b/locales/en/src/2-03-urls.md @@ -0,0 +1,80 @@ +## URLs {#urls} + +![Aufbau einer URL](src/images/url.png) + +Den URLs (für _Uniform Resource Locators_) kommt eine besondere Bedeutung zu +und es werden deshalb eine Reihe von Anforderungen an deren Aufbau und +Eigenschaften gestellt. Die allgemeine Funktionsweise von URLs ist in RFC 3986 +beschrieben^[RFC 3986: ]. + +Grundsätzlich **müssen** alle Zugriffe zustandslos erfolgen können, also ohne +Sessioninformationen wie Cookies. Das bedeutet, dass alle Informationen, +die zum Abrufen eines Objekts nötig sind, in der URL vorhanden sein müssen. + +### URL canonicalisation {#url_kanonisierung} + +Um Objekte eindeutig identifizieren zu können ist es notwendig, dass ein Server +für ein Objekt genau eine unveränderliche URL benutzt. Diese Festlegung auf +genaue eine eindeutige URL wird Kanonisierung genannt. Ein Server **muss** +deshalb für jedes seiner Objekte eine kanonische URL bestimmen können. + +Es wird empfohlen keine IP-Adressen in URLs zu benutzen, sondern einen +mit Bedacht gewählten Hostnamen einzusetzen. Das ist vor allem im Hinblick +auf die Langlebigkeit der URLs wichtig. + +Um die Kanonisierung zu gewährleisten **sollten** OParl-Server so konfiguriert +werden, dass sie nur über eine bestimmte Domain erreichbar sind. OParl-Server **sollten** dagegen möglichst **nicht** nur über eine IP-Addresse sowieso möglichst auch **nicht** über weitere, nicht kanonische URLs erreichbar sein. + +Wenn ein Server auch durch eine nicht-kanonische URL erreichbar ist, dann +**sollte** eine entsprechende HTTP-Anfrage mit einer Weiterleitung auf die +entsprechende kanonische URL und HTTP-Status-Code 301 beantwortet werden. +Zur überprüfung kann z.B. der `Host`-Header einer HTTP-Anfrage verwendet werden. + +Beim Pfad-Bestandteil der URL **müssen** Server-Implementierer darüber hinaus +beachten, dass zur kanonischen Schreibweise auch die Groß- und Kleinschreibung, die Anzahl von Schrägstrichen als Pfad-Trennzeichen und die Anzahl von führenden Nullen vor numerischen URL-Bestandteilen gehört. + +Die Kanonisierung umfasst auch den Query-String-Bestandteil der URL. Wie auch +beim Pfad gilt, dass für jeden Parameter und jeden Wert im Query-String genau +eine kanonische Schreibweise gelten **muss**. + +Darüber hinaus **sollte** der Server-Implementierer darauf achten, Query-String-Parameter +immer nach demselben Prinzip zu sortieren. Als Beispiel: Die beiden URLs + + https://oparl.example.org/members?body=1&committee=2 + https://oparl.example.org/members?committee=2&body=1 + +unterscheiden sich lediglich in der Reihenfolge der Query-String-Parameter. Da +sie jedoch nicht identisch sind, könnten Clients annehmen, dass beide URLs +verschiedene Objekte repräsentieren. + +Clients **sollen** die vom Server gelieferten URLs bei Anzeige, Speicherung +und Weiterverarbeitung nicht verändern. + +### HTTP und HTTPS {#http-und-https} + +Der Einsatz des verschlüsselten HTTPS wird empfohlen. Bei Verwendung von HTTPS +wird allen URLs "https://" voran gestellt, ansonsten beginnen URLs mit +"http://". + +Aus Gründen der URL-Kanonisierung ist es **zwingend** notwendig, dass ein +Server-Betreiber sich entweder für HTTP oder für HTTPS entscheidet. +Es jedoch möglich, eine Weiterleitung (HTTP Status-Code 301) +einzurichten. Eine Weiterleitung von HTTPS auf HTTP wird **nicht empfohlen**. + + +### Langlebigkeit {#url_langlebigkeit} + +Weiterhin sollen URLs langlebig sein, sodass sie möglichst lange zur Abfrage des +dazugehörigen Objekts verwendet werden können. + +In URLs **sollten** deshalb nur Eigenschaften des Objekts aufgenommen werden, +die nicht verändert werden. Ändert sich beispielsweise die Kennung einer +Drucksache im Verlauf ihrer Existenz, dann scheidet sie für die Bildung +der URL aus. + +Des weiteren sollen Eigenschaften der Implementierung nicht sichtbar sein. +Ist ein OParl-Server beispielsweise in PHP geschrieben, **sollte** dies +**nicht** dazu führen, dass im Pfad ein Bestandteil wie "oparl.php/" erscheint. + +Weitere Empfehlungen für langlebige URLs liefern Tim Berners-Lee^[Berners-Lee, Tim: Cool URIs don't change. ] sowie die Europäische Kommission^[Study on persistent URIs, with identification of +best practices and recommendations on the topic for the MSs and the EC. (PDF) ]. diff --git a/locales/en/src/2-04-json-ausgabe.md b/locales/en/src/2-04-json-ausgabe.md new file mode 100644 index 0000000..c150199 --- /dev/null +++ b/locales/en/src/2-04-json-ausgabe.md @@ -0,0 +1,82 @@ +## JSON Output {#json-ausgabe} + +Ein OParl-Server **muss** Objekte in Form von JSON ausgeben. Die Abkürzung JSON steht +für "JavaScript Object Notation". Das JSON-Format ist in +RFC 7159^[RFC 7159: ] beschrieben. + +Sämtliche JSON-Ausgabe **muss** in UTF-8 ohne Byte Order Mark (BOM) geschehen. Dies entspricht +RFC 7159 Section 8.1[^fn-rfc7159-81]. Gemäß RFC 7159 Section 7[^fn-rfc7159-7] **darf** UTF-8 +String-Escaping verwendet werden. XML-/HTML-String-Escaping **darf nicht** verwendet werden. + +Eine Syntaxübersicht und weitere Implementierungshinweise finden sich auf +[json.org](http://json.org/). + +Es ist gestattet, weitere zur JSON-Ausgabe semantisch identische +Formate^[Zu semantisch identischen Formaten zählen u.a.: YAML, MessagePack, etc.] +anzubieten. Da diese jedoch nicht Bestandteil der Spezifikation sind, +**sollten** sich Clients nicht auf deren Vorhandensein verlassen. + +[^fn-rfc7159-7]: [RFC 7159 Section 7](https://tools.ietf.org/html/rfc7159#section-7) +[^fn-rfc7159-81]: [RFC 7159 Section 8.1](https://tools.ietf.org/html/rfc7159#section-8.1) + +### In OParl verwendete Datentypen + +In OParl werden alle in JSON definierten Dateitypen verwendet: + +object: +: Objects entsprechen der Definition des Objects in RFC 7159 Section 4 + +array: +: Arrays entsprechen der Definition des Arrays in RFC 7159 Section 5 + +integer: +: Integers entsprechen der Definition des Integer-Parts der Number aus RFC 7159 Section 6 + +boolean: +: Booleans entsprechen der Definition von Boolean in RFC 7159 Section 3 + +string: +: Strings entsprechen der Definition der Unicode-Strings aus RFC 7159 Section 7 + + +In OParl werden verschiedene String-Typen verwendet. Wenn von diesen Typen gesprochen wird, +so wird automatisch ein JSON-String vorausgesetzt: + +url: +: Eine URL ist ein String, der entsprechend des [URL-Kapitels](#urls) formatiert wurde. + +url (Object): +: Eine URL mit in Klammern angehängtem Objektname beschreibt eine URL auf eben diesen Objekttypus. + +date: +: Entspricht einem Datum ohne Uhrzeit und ohne Zeitzone, wie sie im folgenden Abschnitt beschrieben werden. + +date-time: +: Entspricht einem Datum und einer Uhrzeit mit Zeitzone, wie sie im folgenden Abschnitt beschrieben werden. + +### Datums- und Zeitangaben {#datum_zeit} + +Für Datums- und Zeitangaben wird eine Spezielisierung der in ISO 8601 +beschriebenen Formate verwendet. +Ein Datum (date) **muss** muss die Form `yyyy-mm-dd` besitzen und ein +Zeitpunkt (date-time) **muss** in der Form `yyyy-mm-ddThh:mm:ss±hh:mm` angegeben werden. + +Beispiel für ein Datum: `1969-07-21` + +Beispiel für einen Zeitpunkt: `1969-07-21T02:56:00+00:00` + +### `null`-Werte und leere Listen {#null-werte-und-leere-listen} + +JSON erlaubt es grundsätzlich, Eigenschaften mit dem Wert `null` zu versehen. +Eigenschaften **sollten** nicht mit dem Wert `null` ausgegeben werden, wenn zu +einer Eigenschaft keine Daten vorliegen. Obligatorische Eigenschaften +**dürfen nicht** den Wert `null` haben. + +Im Fall von Arrays erlaubt JSON grundsätzlich die Ausgabe von `[]` für leere +Arrays. Wie bei `null` wird auch hier **empfohlen**, auf die Ausgabe einer +Eigenschaft mit dem Wert `[]` zu verzichten, wenn zu einer Eigenschaft keine Daten +vorliegen. Bei obligatorischen Eigenschaften **muss** jedoch eine leere Liste +ausgegeben werden. + +Bei nicht obligatorischen Eigenschaften sollte gleichermaßen auf die +Ausgabe eines leeren Strings `""` verzichtet werden. diff --git a/locales/en/src/2-05-objektlisten-und-paginierung.md b/locales/en/src/2-05-objektlisten-und-paginierung.md new file mode 100644 index 0000000..e5568f8 --- /dev/null +++ b/locales/en/src/2-05-objektlisten-und-paginierung.md @@ -0,0 +1,245 @@ +## Objektlisten und Paginierung {#objektlisten-und-paginierung} + +Oft wird für ein Attribut kein Wert ausgegeben, sondern ein anderes Objekt oder +eine Liste von Objekten. Dabei kann eine Referenz auf das Objekt bzw. die +Objektliste angegeben werden, oder das Objekt bzw. die Objektlist wird intern +ausgegeben. Beide Verfahren sollen im Folgenden erklärt werden. +Zu beachten ist, dass für jedes Listenattribut festgelegt ist, welches dieser +Verfahren jeweils zu verwenden ist. Diese Information ist den +[Schemadefinitionen](#schema) zu entnehmen. + +### Referenzierung von Objekten via URL + +Bei der Referenzierung einzelner Objekte wird eine URL angegeben, welche auf +das entsprechende Objekt verweist. Der Typ ist hierbei ein +`string (url: Objekt-ID)`. +Ein Beispiel hierfür ist `subOrganizationOf` in `Organization`: + +~~~~~ {#objektlisten_ex1 .json} +{ + "id": "https://oparl.example.org/organization/1", + "type": "https://schema.oparl.org/1.1/Organization", + "subOrganizationOf": "https://oparl.example.org/organization/2" + ... +} +~~~~~ + +Es kann auch eine Liste von Referenzen ausgegeben werden. Der Typ ist in diese +Fall `array of string (url: Objekt-ID)`. + +Ein Beispiel hierfür ist `meeting` in `Organization`: + +~~~~~ {#objektlisten_ex2 .json} +{ + "id": "https://oparl.example.org/organization/1", + "type": "https://schema.oparl.org/1.1/Organization", + "meeting": [ + "https://oparl.example.org/meeting/1", + "https://oparl.example.org/meeting/2", + "https://oparl.example.org/meeting/3", + ] + ... +} +~~~~~ + +### Interne Ausgabe von Objekten + +Objekte können auch intern ausgegeben werden. Dabei wird das gesamte Objekt als +Wert eines Attributs angegeben. Ein Beispiel für ein internes Objekt ist +`location` in `oparl:Body`: + +~~~~~ {#objektlisten_ex3 .json} +{ + "id": "https://oparl.example.org/body/1", + "type": "https://schema.oparl.org/1.1/Body", + "location": { + "id": "https://oparl.example.org/location/1", + "type": "https://schema.oparl.org/1.1/Location", + "description": "Ratshausvorplatz 1, 12345 Beispielstadt" + }, + ... +} +~~~~~ + +Ebenso kann eine Liste von Objekten intern ausgegeben werden. Hier das +Beispiel des Attributes `membership` in `oparl:Person`. + +~~~~~ {#objektlisten_ex4 .json} +{ + "id": "https://oparl.example.org/person/1", + "type": "https://schema.oparl.org/1.1/Person", + "membership": [ + { + "id": "https://oparl.example.org/memberships/385", + "organization": "https://oparl.example.org/organizations/5", + "role": "Vorsitzende", + "votingRight": true, + "startDate": "2013-12-03" + }, + { + "id": "https://oparl.example.org/memberships/693", + "organization": "https://oparl.example.org/organizations/9", + "role": "Sachkundige Bürgerin", + "votingRight": false, + "startDate": "2013-12-03", + "endDate": "2014-07-28" + } + ], + ... +} +~~~~~ + +### Externe Objektlisten + +Es können auch Referenzen zu sogenannten externen Objektlisten angegeben werden. +Die externe Liste enthält dann die betreffenden Objekte in Form einer +Listenausgabe. Ein Beispiel dafür ist `organization` in `oparl:Body`. + +`oparl:Body`: + +~~~~~ {#objektlisten_ex5a .json} +{ + "id": "https://oparl.example.org/body/1", + "type": "https://schema.oparl.org/1.1/Body", + "organization": "https://oparl.example.org/body/1/organization" + ... +} +~~~~~ + +Die externe Objektliste: + +~~~~~ {#objektlisten_ex5b .json} +{ + "data": [ + { + "id": "https://oparl.example.org/organization/1", + "type": "https://schema.oparl.org/1.1/Organization", + "name": "Organisation Nummer 1", + ... + }, + { + "id": "https://oparl.example.org/organization/2", + "type": "https://schema.oparl.org/1.1/Organization", + "name": "Organisation Nummer 2", + ... + }, + { + "id": "https://oparl.example.org/organization/3", + "type": "https://schema.oparl.org/1.1/Organization", + "name": "Organisation Nummer 3", + ... + }, + ], + ... +} +~~~~~ + + +### Paginierung {#paginierung} + +Für externe Objektlisten ist eine Aufteilung sogenannte *Listenseiten* +vorgesehen, wobei jede Listenseite eine eigene URL erhält. Das dient dazu, +die bei der jeweiligen Anfrage übertragenen Datenmengen und Antwortzeiten zu +begrenzen. + +Die Entscheidung, ob eine externe Objektliste mit Paginierung +ausgegeben wird, liegt allein beim Server. Bei Listen mit mehr als 100 +Einträgen wird dies **empfohlen**. + +Ein Server **muss** für eine stabile Sortierung von Listeneinträgen sorgen. Das +heißt, dass die Sortierung der Einträge einem konstanten Prinzip folgt und sich +nicht von Abfrage zu Abfrage ändert. Das kann z.B. durch die Sortierung von +Objekten nach einer eindeutigen und unveränderlichen ID erreicht werden. + +Jede Listenseite **muss** die Attribute folgenden Attribute enthalten: + +- **data** (Array der intern ausgegebenen Objekte) + +- **pagination** (Object) + +- **links** (Object) + +Für `pagination` sind die folgenden Attribute festgelegt, die alle **optional** +sind: + +- `totalElements`: Gibt die Gesamtanzahl der Objekte in der Liste an. Diese Zahl +kann sich unter Umständen bis zum Aufruf der nächsten Listenseiten ändern. + +- `elementsPerPage`: Gibt die Anzahl der Objekte pro Listenseite an. Dieser Wert +muss auf allen Listenseiten bis auf die letzte gleich sein. + +- `currentPage`: Gibt die aktuelle Seitenzahl in der Liste an. + +- `totalPages`: Gibt die Gesamtanzahl der Seiten in der Liste an. + +Für `links` sind folgende Attribute festgelegt, die bis auf `next` alle +**optional** sind: + +- `first`: URL der ersten Listenseite + +- `prev`: URL der vorherigen Listenseite + +- `self`: Die kanonische URL dieser Listenseite + +- `next`: URL der nächsten Listen. Für alle Seiten bis auf die letzte ist die +Angabe dieser URL **zwingend**. + +- `last`: URL der letzten Listenseite + +- `web`: s. [web](#web) + +~~~~~ {#paginierung_ex1 .json} +{ + "data": [ + {...}, + {...}, + ... + ], + "pagination": { + "totalElements": 50000, + "elementsPerPage": 100, + "currentPage": 3, + "totalPages":500 + }, + "links": { + "first": "https://oparl.example.org/organization/", + "prev": "https://oparl.example.org/organization/?page=2", + "self": "https://oparl.example.org/organization/?page=3", + "next": "https://oparl.example.org/organization/?page=4", + "last": "https://oparl.example.org/organization/?page=500", + "web": "https://web.example.org/organization/?page=500" + } +} +~~~~~ + +### Filter {#filter} + +Externe Objektlisten können mit den URL-Parametern `created_since`, `created_until`, +`modified_since` und `modified_until` eingeschränkt werden. Diese Parameter +beziehen sich auf die entsprechenden Attribute der jeweiligen Objekte, wobei +reservierte Zeichen URL-Kodiert werden müssen. Ein Server muss diese Parameter +bei allen externen Objektlisten unterstützen. + +Die Filter werden vom Client benutzt, indem die gewünschten URL-Parameter an +die URL der ersten Listensiete angehängt werden. Bei allen weiteren Seiten hat +der Server sicherzustellen, dass die verwendeten Filter erhalten bleiben. +Lautet die URL für eine Liste von Drucksachen wie folgt: + + https://oparl.example.org/papers/ + +kann der Client die folgende URL bilden, um die Ausgabe der Liste auf +Drucksachen einzuschränken, die seit dem 1. Januar 2014 veröffentlicht wurden: + + https://oparl.example.org/papers/?created_since=2014-01-01T00%3A00%3A00%2B01%3A00 + +Mehrere Parameter können auch gemeinsam verwendet werden. So kann man z.B. eine +Einschränkung vom 1.1.2014 bis zum 31.1.2014 vornehmen: + + https://oparl.example.org/papers/?created_since=2014-01-01T00%3A00%3A00%2B01%3A00&created_until=2014-01-31T23%3A59%3A59%2B01%3A00 + +Die genannten URL-Parameter erwarten grundsätzlich eine vollständige [`date-time`-Angabe](#datum_zeit). + +Des Weiteren kann ein Client die Anzahl der Objekte pro Listenseite durch +den URL-Parameter `elementsPerPage` begrenzen, der sich auf das gleichnamige +Attribut bezieht. Ein Client **darf nicht** erwarten, dass sich ein Server an +seine `elementsPerPage`-Anfrage hält. diff --git a/locales/en/src/2-06-cross-origin-resource-sharing-cors.md b/locales/en/src/2-06-cross-origin-resource-sharing-cors.md new file mode 100644 index 0000000..c45d008 --- /dev/null +++ b/locales/en/src/2-06-cross-origin-resource-sharing-cors.md @@ -0,0 +1,32 @@ +Cross-Origin Resource Sharing (CORS) {#cors} +------------------------------------ + +Wenn Webbrowser mittels Skript auf JSON-Ressourcen zugreifen sollen +unterliegen diese Zugriffe üblicherweise einer _Same-Origin-Policy_ (SOP). +Das heißt, eine Anfrage ist nur an den Server zulässig, der auch das +initiierende Skript ausgeliefert hat. Anfragen an andere Server werden +vom Browser blockiert. Diese Einschränkung dient im Allgemeinen +der Sicherheit von Webbrowsern.^[vgl. Wikipedia: Same-Origin-Policy ] + +Um die Daten von OParl-Servern auch im Kontext von Webanwendungen +flexibel nutzen zu können, ist die Überwindung der SOP nötig. Hierzu dient +_Cross-Origin Resource Sharing_ (CORS)^[Cross Origin Resource Sharing - +W3C Recommendation 16. Januar 2014: ]. Mittels CORS +kann ein Server mitteilen, dass bestimmte von ihm ausgelieferte Ressourcen +auch innerhalb von Webapplikationen genutzt werden dürfen, die nicht vom selben Server ausgeliefert werden. Technisch wird dies durch Ausgabe +zusätzlicher HTTP-Header erreicht. + +OParl-Server **müssen** für jegliche Anfrage, die mit der Ausgabe von JSON-Daten +beantwortet wird (das sind alle Anfragen außer [Dateizugriffe](#dateizugriff)) +den folgenden HTTP-Antwort-Header senden: + + Access-Control-Allow-Origin: * + +Der HTTP-Antwort-Header `Access-Control-Allow-Methods` **sollte** darüber hinaus +**nicht** gesetzt sein, oder **muss** die Methode `GET` beinhalten. + +Entwicklerinnen von Webanwendungen sollten sich darüber bewusst sein, dass +durch die direkte Einbindung von Skripten Dritter in ihre Anwendungen mögliche +Sicherheitsrisiken entstehen. Für den Fall, dass ein OParl-Server, etwa in +Folge einer Manipulation, Schadcode ausliefert, könnte dieser unmittelbar +von Skripten im Browser ausgeführt werden. diff --git a/locales/en/src/2-07-dateizugriffe.md b/locales/en/src/2-07-dateizugriffe.md new file mode 100644 index 0000000..a42d7b1 --- /dev/null +++ b/locales/en/src/2-07-dateizugriffe.md @@ -0,0 +1,40 @@ +Dateizugriffe {#dateizugriff} +------------- + +Mit dem Begriff "Datei" sind im Sinne dieser Spezifikation alle Ressourcen +gemeint, die von einem OParl-Server zur Verfügung gestellt werden und +deren Metadaten über die JSON-API als [`oparl:File`](#entity-file) +abgerufen werden können. Es handelt sich dabei beispielsweise um Textdokumente +im PDF-Format oder Abbildungen im JPEG- oder PNG-Format. + +Jede Datei **muss** dabei mit einer HTTP-GET-Anfrage abrufbar sein. + +### Empfehlungen für Dateizugriffe + +* Ein Server **sollte** die Verwendung von Kompression gemäß dem HTTP-Standard +unterstützen. + +* Ein Server **sollte** "Conditional GET", insbesondere +`If-Modified-Since` und `If-None-Match` sowie "Chunked GET" unterstützen. + +* Die Ausgabe der HTTP-Header `Last-Modified`, `Content-Length` und `ETag` ist +**empfohlen**. + +* Bei gelöschten Dateien **sollte** der HTTP-Statuscode `410` verwendet werden. + +### Allgemeiner Zugriff und expliziter Download + +Mit der im `oparl:File` **zwingend** anzugebenden Eigenschaft `accessUrl` liefert +der Server dem Client eine URL, die dem allgemeinen Zugriff auf die Datei dient. +Beim Zugriff auf dieser URL **darf** der Server **nicht** den `Content-Disposition`-Header +mit dem Parameter `attachment` senden. ^[vgl. RFC2138] + +Es wird daher **empfohlen**, zusätzlich eine Eigenschaft `downloadUrl` anzubieten. Beim +Zugriff auf die Download-URL **muss** der Server in der HTTP-Antwort einen +`Content-Disposition`-Header senden, der als ersten Parameter den +Typ `attachment` enthält und mit dem `filename`-Parameter den Namen der Datei +angibt. + +Beispiel: + + Content-Disposition: attachment; filename="2014-08-22 Rat Wortprotokoll.pdf" diff --git a/locales/en/src/2-08-geloeschte-objekte.md b/locales/en/src/2-08-geloeschte-objekte.md new file mode 100644 index 0000000..f0d056f --- /dev/null +++ b/locales/en/src/2-08-geloeschte-objekte.md @@ -0,0 +1,26 @@ +## Gelöschte Objekte {#geloeschte-objekte} + +Das Löschen der Objekte _oparl:System_, _oparl:Body_, _oparl:Organisation_, _oparl:Person_, _oparl:Meeting_, +_oparl:Paper_, _oparl:File_ und _oparl:Location_ muss in OParl gesondert vermerkt werden. +Es **darf** insbesondere **nicht** einfach gelöscht werden, so dass unter der +betreffenden URL kein gültiges Objekt ausgeliefert wird. + +Hintergrund ist, dass alle OParl-Clients zeitnah erfahren können müssen, +wenn ein Objekt gelöscht wurde. Dies wird durch die folgenden Regeln +gewährleistet. + +Wenn ein Objekt gelöscht wird, + +* **muss** das Objekt das zusätzliche Attribut `deleted`: true bekommen +* **muss** das Attribut `modified` auf den Zeitpunkt der Löschung setzen +* **müssen** die Attribute `id`, `type` und `created` erhalten bleiben + +Als HTTP-Statuscode **muss** weiterhin 200 verwendet werden. + +Die Objekte _LegislativeTerm_, _Membership_, _AgendaItem_ und _Consultation_ können dagegen einfach +gelöscht werden. Beim Löschen dieser Objekte muss allerdings der +Wert `modified` aller Objekte aktualisiert werden, in die dieses Objekt +eingebunden war. + +Dies garantiert, dass das gelöschte Objekt beim Updaten eines Client-Datenbestandes +aktualisiert wird, falls der Client nur seit dem letzten Update aktualisierte Objekte abruft. diff --git a/locales/en/src/2-09-ausnahmebehandlung.md b/locales/en/src/2-09-ausnahmebehandlung.md new file mode 100644 index 0000000..3ff9683 --- /dev/null +++ b/locales/en/src/2-09-ausnahmebehandlung.md @@ -0,0 +1,20 @@ +## Ausnahmebehandlung {#ausnahmebehandlung} + +Wenn ein Server eine Anfrage nicht bearbeiten kann, z.B. weil die +URL ungültig ist oder das angefragte Objekt nicht existiert, dann **sollte** er +mit dem entsprechenden HTTP-Statuscode antworten. + +Ein Server **sollte** in diesem Fall ein Objekt ausgeben, das die folgenden +3 Attribute enthält: + + * `type`: Enthält als Wert die URL `https://schema.oparl.org/1.1/Error` + * `message`: Eine Fehlermeldung, die zur Anzeige für einen Nutzer + gedacht ist. Die Fehlermeldung sollte deshalb in der Sprache der durch die + Schnittstelle ausgelieferten Inhalte verfasst sein + * `debug`: Zusätzliche Informationen über den Fehler + + Wenn ein Server ein solches Objekt ausgibt, dann **muss** er dazu einen + HTTP-Statuscode senden, der einen Fehler anzeigt. + + Ein Client **darf nicht** voraussetzen, dass er im Fall eines Fehlers + verwertbare Informationen wie das oben beschriebene Fehlerobjekt erhält. diff --git a/locales/en/src/2-10-endpunkt.md b/locales/en/src/2-10-endpunkt.md new file mode 100644 index 0000000..2365bf3 --- /dev/null +++ b/locales/en/src/2-10-endpunkt.md @@ -0,0 +1,8 @@ +## OParl Endpoint + +Als OParl Endpunkt bzw. Einsprungspunkt zur Schnittstelle wird ein `OParl:System` +Objekt genutzt. Falls auf einem HTTP-Host mehrere OParl-Schnittstellen oder +mehrere OParl Versionen parallel installiert sind, **müssen** diese eindeutige und +voneinander unabhängige OParl-Endpunkte anbieten. Es ist allerdings möglich, +eine Liste von `OParl:System`-Objekten auszugeben, die z.B. auf verschiedene +OParl-Versionen einer Schnittstelle verweisen. diff --git a/locales/en/src/3-00-schema.md b/locales/en/src/3-00-schema.md new file mode 100644 index 0000000..ca62e44 --- /dev/null +++ b/locales/en/src/3-00-schema.md @@ -0,0 +1,145 @@ +# Schema {#schema} + +Dieses Kapitel beschreibt das Schema von OParl. Das Schema definiert +die Objekttypen und ihre Eigenschaften. Darüber hinaus ist im Schema +auch festgelegt, in welcher Beziehung verschiedene Objekttypen zu +einander stehen. + +![OParl Objekttypen: Ein Überblick. Die Zahl an den Verbindungslinien entspricht der Anzahl der Attribute, die eine oder mehrere Verknüpfungen herstellen.](src/images/objekttypen_graph.png) + +## Die Objekte {#objekttypen} + +OParl nutzt folgenden Objekte: + +* oparl:System +* oparl:Body +* oparl:LegislativeTerm +* oparl:Organization +* oparl:Person +* oparl:Membership +* oparl:Meeting +* oparl:AgendaItem +* oparl:Paper +* oparl:Consultation +* oparl:File +* oparl:Location + +Einige Objekte werden intern in anderen Objekten ausgegeben: + +* oparl:LegislativeTerm wird intern in oparl:Body ausgegeben +* oparl:Membership wird intern in oparl:Person ausgegeben +* oparl:AgendaItem wird intern in oparl:Meeting ausgegeben +* oparl:Consultation wird intern in Paper ausgegeben +* oparl:File wird intern in oparl:Meeting, oparl:AgendaItem und oparl:Paper ausgegeben +* oparl:Location wird intern in oparl:Body, oparl:Organization, oparl:Meeting und oparl:Paper ausgegeben + +Grundsätzlich muss jedes Objekt unter seiner ID abrufbar sein - auch dann, wenn +das Objekt in anderen Objekten intern ausgegeben wird. Bei der internen Ausgabe +wird beim internen Objekt auf die Rückreferenz auf das Elternobjekt verzichtet. + +Als Beispiel hier eine Ausgabe von `oparl:Meeting`, in welchem ein `oparl:File` enthalten +ist: + +~~~~~ {#objekte_example1 .json} +{ + "id": "https://oparl.example.org/meeting/281", + "type": "https://schema.oparl.org/1.1/Meeting", + "name": "4. Sitzung des Finanzausschusses", + "start": "2013-01-04T08:00:00+01:00", + "end": "2013-01-04T12:00:00+01:00", + "invitation": { + "id": "https://oparl.example.org/files/57739", + "name": "Einladung", + "fileName": "einladung.pdf", + "mimeType": "application/pdf", + "date": "2012-01-08", + "modified": "2012-01-08T14:05:27+01:00", + "sha1Checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "size": 82930, + "accessUrl": "https://oparl.example.org/files/57739.pdf", + "downloadUrl": "https://oparl.example.org/files/download/57739.pdf" + } + [...] +} +~~~~~ + +Das enthaltene `oparl:File` muss auch einzeln abgerufen werden können. Dabei kommt +dann das Eltern-Objekt als zusätzliches Attribut hinzu.: + +~~~~~ {#objekte_example2 .json} +{ + "id": "https://oparl.example.org/files/57739", + "type": "https://schema.oparl.org/1.1/File", + "name": "Einladung", + "fileName": "einladung.pdf", + "mimeType": "application/pdf", + "date": "2012-01-08", + "modified": "2012-01-08T14:05:27+01:00", + "sha1Checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "size": 82930, + "accessUrl": "https://oparl.example.org/files/57739.pdf", + "downloadUrl": "https://oparl.example.org/files/download/57739.pdf", + "meeting": [ + "https://oparl.example.org/meeting/281" + ] +} +~~~~~ + +Das zusätzliche Attribut ist ein Array, da es auch möglich ist, dass Dateien +von mehreren Hauptobjekten aus genutzt werden. Das kann z.B. bei `oparl:Location` +vorkommen: + +~~~~~ {#objekte_example2 .json} +{ + "id": "https://oparl.example.org/locations/29856", + "type": "https://schema.oparl.org/1.1/File", + "description": "Honschaftsstraße 312, Köln", + "geojson": { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 7.03291, + 50.98249 + ] + } + }, + "meeting": [ + "https://oparl.example.org/meeting/281", + "https://oparl.example.org/meeting/766", + "https://oparl.example.org/meeting/1002" + ], + "paper": [ + "https://oparl.example.org/paper/749", + "https://oparl.example.org/paper/861", + "https://oparl.example.org/paper/1077" + ] +} +~~~~~ + + +## Übergreifende Aspekte {#uebergreifende-aspekte} + +### Vollständigkeit {#schema-vollstaendigkeit} + +Alle regulär öffentlich abrufbaren Informationen **sollten** auch in OParl +ausgegeben werden, solange dies nicht den Datenschutzbestimmungen widerspricht. +Daher sind sämtliche Felder im Schema als **empfohlen** zu behandeln, wenn +nicht explizit etwas anderes angegeben wurde. + +### Herstellerspezifische Erweiterungen {#herstellerspezifische-erweiterungen} + +In OParl können zusätzliche, herstellerspezifische Eigenschaften hinzugefügt werden. +Dazu wird diesen Eigenschaften ein Herstellerprefix vorangestellt. So könnte man z.B. +`oparl:Person` um eine Faxnummer erweitern: + +~~~~~ +"BeispielHersteller:faxNumber": "012345678", +~~~~~ + +### URL-Pfade in den Beispielen {#url-pfade-in-den-beispielen} + +OParl-Clients wissen nichts vom Aufbau von Pfaden innerhalb von URLs, +müssen dies nicht wissen, und es gibt deshalb in der OParl-Spezifikation +keine Festlegungen dazu. Die in den Beispielen verwendeten URLs zeigen einen +möglichen Weg zur Umsetzungen der Empfehlungen in URLs. diff --git a/locales/en/src/3-01-eigenschaften-mit-verwendung-in-mehreren-objekttypen.md b/locales/en/src/3-01-eigenschaften-mit-verwendung-in-mehreren-objekttypen.md new file mode 100644 index 0000000..b148aa9 --- /dev/null +++ b/locales/en/src/3-01-eigenschaften-mit-verwendung-in-mehreren-objekttypen.md @@ -0,0 +1,88 @@ +## Eigenschaften mit Verwendung in mehreren Objekttypen {#eigenschaften-mit-verwendung-in-mehreren-objekttypen} + +### `id` {#eigenschaft-id} + +Die Eigenschaft `id` enthält den eindeutigen Bezeichner des Objekts, nämlich seine URL. +Dies ist ein **zwingendes** Merkmal für jedes Objekt. + +### `type` {#eigenschaft-type} + +Objekttypenangabe des Objekts, **zwingend** für jedes Objekt. Der Wert ist +eine Namespace-URL. Für die OParl-Objekttypen sind die folgenden URLs +definiert: + +Typ (kurz) | Namespace-URL +-------------------------|------------------------------------------- +`oparl:AgendaItem` |https://schema.oparl.org/1.1/AgendaItem +`oparl:Body` |https://schema.oparl.org/1.1/Body +`oparl:Consultation` |https://schema.oparl.org/1.1/Consultation +`oparl:File` |https://schema.oparl.org/1.1/File +`oparl:LegislativeTerm` |https://schema.oparl.org/1.1/LegislativeTerm +`oparl:Location` |https://schema.oparl.org/1.1/Location +`oparl:Meeting` |https://schema.oparl.org/1.1/Meeting +`oparl:Membership` |https://schema.oparl.org/1.1/Membership +`oparl:Organization` |https://schema.oparl.org/1.1/Organization +`oparl:Paper` |https://schema.oparl.org/1.1/Paper +`oparl:Person` |https://schema.oparl.org/1.1/Person +`oparl:System` |https://schema.oparl.org/1.1/System + +### `name` und `shortName` {#eigenschaft-name-shortname} + +Beide Eigenschaften können bei vielen Objekttypen genutzt werden um den +Namen des Objekts anzugeben. Üblicherweise ist `name` eine Pflichteigenschaft +für den ausgeschriebenen offiziellen Namen, während `shortName` optional +angegeben werden kann. Dies ist dann zu empfehlen, wenn zu einem Namen eine +kurze bzw. kompakte und eine längere, aber weniger nutzerfreundliche Variante +existieren. So ist "Innenministerium" die Kurzform des offiziellen +"Bundesministerium des Inneren". + +### `license` {#eigenschaft_license} + +Mit `license` wird angegeben, unter welcher Lizenz die Daten des jeweiligen +Objekts stehen. ^[Verzeichnisse für Lizenz-URLs sind unter anderem unter + und + +zu finden. Allgemeine Informationen zur Lizensierung von Open Data finden sich auch +im Open Data Handbook der Open Knowledge Foundation unter +.] + +Wird `license` im `oparl:System`-Objekt oder am `oparl:Body`-Objekt verwendet, +dann bedeutet das, dass alle Objekte dieses Systems bzw. der Körperschaft +unter der angegebenen Lizenz veröffentlicht werden, sofern nicht das +einzelne Objekt eine anders lautende Lizenz-URL angibt. Es wird **empfohlen**, +die Lizenzinformation sofern möglich global am `oparl:System` Objekt mitzuteilen +und auf redundante Informationen zu verzichten. + +### `created` {#eigenschaft-created} + +Datum und Uhrzeit der Erstellung des jeweiligen Objekts. + +Diese Eigenschaft **muss** in allen Objekttypen angegeben werden, die nicht +in anderen Objekten intern ausgegeben werden. + +### `modified` {#eigenschaft-modified} + +Diese Eigenschaft kennzeichnet stets Datum und Uhrzeit der letzten Änderung des +jeweiligen Objekts. + +Diese Eigenschaft **muss** - genau wie `created` - in allen Objekttypen angegeben +werden, die nicht in anderen Objekten intern ausgegeben werden. + +Es ist **zwingend**, dass bei jeder Änderung eines Objekts der Wert dieses +Attributs auf die zu diesem Zeitpunkt aktuelle Uhrzeit gesetzt wird, da ein +Client in der Regel seinen Datenbestand nur auf Basis dieses Attributs +verlustfrei aktualisieren kann. + +### `keyword` {#eigenschaft-keyword} + +Die Eigenschaft `keyword` dient der optionalen Kategorisierung eines Objekts. + +### `web` {#eigenschaft-web} + +Gibt die URL einer Website an, die das Objekt im Browser darstellt. Das +ist z.B. die HTML-Ansicht eines parlamentarischen Informationssystems. + +### `deleted` {#eigenschaft-deleted} + +Falls das Objekt gelöscht wurde, muss dieses gemäß Kapitel 2.8 das Attribut +`deleted: true` bekommen. diff --git a/resources/specbuilder/Dockerfile b/resources/specbuilder/Dockerfile deleted file mode 100644 index ef45157..0000000 --- a/resources/specbuilder/Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -# Dockerfile to create a container able to build the OParl Specification -# -# MIT License -# -# Copyright (c) 2016, Stefan Graupner -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -FROM ubuntu:latest -MAINTAINER Stefan Graupner - -RUN apt update -y -RUN apt upgrade -y - -# recommended packages for pandoc + basic pdf export -RUN apt install --no-install-recommends -y \ - etoolbox \ - ghostscript \ - lmodern \ - graphviz \ - make \ - pandoc \ - pandoc-citeproc \ - texlive-fonts-recommended \ - texlive-generic-recommended \ - texlive-humanities \ - texlive-lang-german \ - texlive-latex-recommended \ - texlive-luatex \ - texlive-xetex - -RUN apt -y install python python3 imagemagick zip tar bzip2 -RUN adduser --disabled-password -q --gecos "" --shell=/bin/bash --home=/spec web diff --git a/resources/template.tex b/resources/template.tex index e50f538..4e4170c 100644 --- a/resources/template.tex +++ b/resources/template.tex @@ -155,7 +155,7 @@ \vspace{2em} \begin{figure}[htbp] \centering - \Oldincludegraphics[width=71pt,height=26pt]{src/images/CC-BY-SA.png} + \Oldincludegraphics[width=71pt,height=26pt]{build/src/images/CC-BY-SA.png} \end{figure} \end{titlepage} diff --git a/schema/AgendaItem.json b/schema/AgendaItem.json index 5350515..7dc5b2b 100644 --- a/schema/AgendaItem.json +++ b/schema/AgendaItem.json @@ -1,6 +1,6 @@ { "title": "AgendaItem", - "description": "Tagesordnungspunkte sind die Bestandteile von Sitzungen (`oparl:Meeting`). Jeder Tagesordnungspunkt widmet sich inhaltlich einem bestimmten Thema, wozu in der Regel auch die Beratung bestimmter Drucksachen gehört.\n\nDie Beziehung zwischen einem Tagesordnungspunkt und einer Drucksache wird über ein Objekt vom Typ `oparl:Consultation` hergestellt, das über die Eigenschaft `consultation` referenziert werden kann.", + "description": "{{ AgendaItem.description }}", "type": "object", "required": [ "id", @@ -16,25 +16,25 @@ "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\\/1\\.1\\/AgendaItem$" }, "meeting": { - "description": "Rückreferenz auf das Meeting, welches nur dann ausgegeben werden muss, wenn das agendaItem-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist.", + "description": "{{ AgendaItem.properties.meeting.description }}", "type": "string", "format": "url", "references": "Meeting" }, "number": { - "description": "Gliederungs-\"Nummer\" des Tagesordnungspunktes. Eine beliebige Zeichenkette, wie z. B. \"10.\", \"10.1\", \"C\", \"c)\" o. ä. Die Reihenfolge wird nicht dadurch, sondern durch die Reihenfolge der TOPs im `agendaItem`-Attribut von `oparl:Meeting` festgelegt, **sollte** allerdings zu dieser identisch sein.", + "description": "{{ AgendaItem.properties.number.description }}", "type": "string" }, "name": { - "description": "Das Thema des Tagesordnungspunktes.", + "description": "{{ AgendaItem.properties.name.description }}", "type": "string" }, "public": { - "description": "Kennzeichnet, ob der Tagesordnungspunkt zur Behandlung in öffentlicher Sitzung vorgesehen ist/war. Es wird ein Wahrheitswert (`true` oder `false`) erwartet.", + "description": "{{ AgendaItem.properties.public.description }}", "type": "boolean" }, "consultation": { - "description": "Beratung, die diesem Tagesordnungspunkt zugewiesen ist.", + "description": "{{ AgendaItem.properties.consultation.description }}", "references": "Consultation", "backreference": "agendaItem", "cardinality": "1:1", @@ -42,20 +42,20 @@ "format": "url" }, "result": { - "description": "Kategorische Information darüber, welches Ergebnis die Beratung des Tagesordnungspunktes erbracht hat, in der Bedeutung etwa \"Unverändert beschlossen\" oder \"Geändert beschlossen\".", + "description": "{{ AgendaItem.properties.result.description }}", "type": "string" }, "resolutionText": { - "description": "Falls in diesem Tagesordnungspunkt ein Beschluss gefasst wurde, kann hier ein Text angegeben werden. Das ist besonders dann in der Praxis relevant, wenn der gefasste Beschluss (z. B. durch Änderungsantrag) von der Beschlussvorlage abweicht.", + "description": "{{ AgendaItem.properties.resolutionText.description }}", "type": "string" }, "resolutionFile": { - "description": "Falls in diesem Tagesordnungspunkt ein Beschluss gefasst wurde, kann hier eine Datei angegeben werden. Das ist besonders dann in der Praxis relevant, wenn der gefasste Beschluss (z. B. durch Änderungsantrag) von der Beschlussvorlage abweicht.", + "description": "{{ AgendaItem.properties.resolutionFile.description }}", "type": "object", "schema": "File.json" }, "auxiliaryFile": { - "description": "Weitere Dateianhänge zum Tagesordnungspunkt.", + "description": "{{ AgendaItem.properties.auxiliaryFile.description }}", "type": "array", "items": { "type": "object", @@ -63,12 +63,12 @@ } }, "start": { - "description": "Datum und Uhrzeit des Anfangszeitpunkts des Tagesordnungspunktes. Bei zukünftigen Tagesordnungspunkten ist dies der geplante Zeitpunkt, bei einem stattgefundenen **kann** es der tatsächliche Startzeitpunkt sein.", + "description": "{{ AgendaItem.properties.start.description }}", "type": "string", "format": "date-time" }, "end": { - "description": "Endzeitpunkt des Tagesordnungspunktes als Datum/Uhrzeit. Bei zukünftigen Tagesordnungspunkten ist dies der geplante Zeitpunkt, bei einer stattgefundenen **kann** es der tatsächliche Endzeitpunkt sein.", + "description": "{{ AgendaItem.properties.end.description }}", "type": "string", "format": "date-time" }, @@ -86,4 +86,4 @@ "format": "url" } } -} +} \ No newline at end of file diff --git a/schema/Body.json b/schema/Body.json index 141c873..d46c296 100644 --- a/schema/Body.json +++ b/schema/Body.json @@ -1,6 +1,6 @@ { "title": "Body", - "description": "Der Objekttyp oparl:Body dient dazu, eine Körperschaft zu repräsentieren. Eine Körperschaft ist in den meisten Fällen eine Gemeinde, eine Stadt oder ein Landkreis.\n\nIn der Regel sind auf einem OParl-Server Daten von genau einer Körperschaft gespeichert und es wird daher auch nur ein Body-Objekt ausgegeben. Sind auf dem Server jedoch Daten von mehreren Körperschaften gespeichert, **muss** für jede Körperschaft ein eigenes Body-Objekt ausgegeben werden.", + "description": "{{ Body.description }}", "type": "object", "required": [ "id", @@ -22,7 +22,7 @@ "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\\/1\\.1\\/Body$" }, "system": { - "description": "System, zu dem dieses Objekt gehört.", + "description": "{{ Body.properties.system.description }}", "references": "System", "backreference": "bodies", "cardinality": "n:1", @@ -30,43 +30,43 @@ "format": "url" }, "shortName": { - "description": "Kurzer Name der Körperschaft.", + "description": "{{ Body.properties.shortName.description }}", "type": "string" }, "name": { - "description": "Der offizielle lange Name der Körperschaft.", + "description": "{{ Body.properties.name.description }}", "type": "string" }, "website": { - "description": "Allgemeine Website der Körperschaft.", + "description": "{{ Body.properties.website.description }}", "type": "string", "format": "url" }, "license": { - "description": "Lizenz, unter der die Daten dieser Körperschaft stehen, sofern nicht am einzelnen Objekt anders angegeben. Siehe [`license`](#eigenschaft_license).", + "description": "{{ Body.properties.license.description }}", "type": "string", "format": "url" }, "licenseValidSince": { - "description": "Zeitpunkt, seit dem die unter `license` angegebene Lizenz gilt. _Vorsicht bei Änderungen der Lizenz die zu restriktiveren Bedingungen führen!_", + "description": "{{ Body.properties.licenseValidSince.description }}", "type": "string", "format": "date-time" }, "oparlSince": { - "description": "Zeitpunkt, ab dem OParl für dieses Body bereitgestellt wurde. Dies hilft, um die Datenqualität einzuschätzen, denn erst ab der Einrichtung für OParl kann sichergestellt werden, dass sämtliche Werte korrekt in der Original-Quelle vorliegen.", + "description": "{{ Body.properties.oparlSince.description }}", "type": "string", "format": "date-time" }, "ags": { - "description": "Der achtstellige Amtliche Gemeindeschlüssel^[Amtliche Gemeindeschlüssel können im [Gemeindeverzeichnis (GV-ISys) des Statistischen Bundesamtes](https://www.destatis.de/DE/ZahlenFakten/LaenderRegionen/Regionales/Gemeindeverzeichnis/Gemeindeverzeichnis.html) eingesehen werden].", + "description": "{{ Body.properties.ags.description }}", "type": "string" }, "rgs": { - "description": "Der zwölfstellige Regionalschlüssel.", + "description": "{{ Body.properties.rgs.description }}", "type": "string" }, "equivalent": { - "description": "Dient der Angabe zusätzlicher URLs, die dieselbe Körperschaft repräsentieren. Hier können beispielsweise der entsprechende Eintrag der gemeinsamen Normdatei der Deutschen Nationalbibliothek^[Gemeinsame Normdatei ], der DBPedia^[DBPedia ] oder der Wikipedia^[Wikipedia ] angegeben werden. Body- oder System-Objekte mit anderen OParl-Versionen **dürfen nicht** Teil der Liste sein.", + "description": "{{ Body.properties.equivalent.description }}", "type": "array", "items": { "type": "string", @@ -74,15 +74,15 @@ } }, "contactEmail": { - "description": "Dient der Angabe einer Kontakt-E-Mail-Adresse. Die Adresse soll die Kontaktaufnahme zu einer für die Körperschaft und idealerweise das parlamentarische Informationssystem zuständigen Stelle ermöglichen. ", + "description": "{{ Body.properties.contactEmail.description }}", "type": "string" }, "contactName": { - "description": "Name oder Bezeichnung der mit `contactEmail` erreichbaren Stelle.", + "description": "{{ Body.properties.contactName.description }}", "type": "string" }, "organization": { - "description": "Link zur [Objektliste](#objektlisten) mit allen Gruppierungen der Körperschaft.", + "description": "{{ Body.properties.organization.description }}", "type": "string", "format": "url", "references": "externalList", @@ -92,7 +92,7 @@ } }, "person": { - "description": "Link zur [Objektliste](#objektlisten) mit allen Personen der Körperschaft.", + "description": "{{ Body.properties.person.description }}", "type": "string", "format": "url", "references": "externalList", @@ -102,7 +102,7 @@ } }, "meeting": { - "description": "Link zur [Objektliste](#objektlisten) mit allen Sitzungen der Körperschaft.", + "description": "{{ Body.properties.meeting.description }}", "type": "string", "format": "url", "references": "externalList", @@ -112,7 +112,7 @@ } }, "paper": { - "description": "Link zur [Objektliste](#objektlisten) mit allen Drucksachen der Körperschaft.", + "description": "{{ Body.properties.paper.description }}", "type": "string", "format": "url", "references": "externalList", @@ -122,7 +122,7 @@ } }, "legislativeTerm": { - "description": "[Objektliste](#objektlisten) mit den Wahlperioden der Körperschaft.", + "description": "{{ Body.properties.legislativeTerm.description }}", "type": "array", "items": { "type": "object", @@ -170,11 +170,11 @@ } }, "classification": { - "description": "Art der Körperschaft.", + "description": "{{ Body.properties.classification.description }}", "type": "string" }, "location": { - "description": "Ort, an dem die Körperschaft beheimatet ist.", + "description": "{{ Body.properties.location.description }}", "type": "object", "schema": "Location.json" }, @@ -200,4 +200,4 @@ "type": "boolean" } } -} +} \ No newline at end of file diff --git a/schema/Consultation.json b/schema/Consultation.json index 4f67054..992a348 100644 --- a/schema/Consultation.json +++ b/schema/Consultation.json @@ -1,7 +1,7 @@ { "title": "Consultation", "type": "object", - "description": "Der Objekttyp `oparl:Consultation` dient dazu, die Beratung einer Drucksache ([`oparl:Paper`](#oparl_paper)) in einer Sitzung abzubilden. Dabei ist es nicht entscheidend, ob diese Beratung in der Vergangenheit stattgefunden hat oder diese für die Zukunft geplant ist.\n\nDie Gesamtheit aller Objekte des Typs `oparl:Consultation` zu einer bestimmten Drucksache bildet das ab, was in der Praxis als \"Beratungsfolge\" der Drucksache bezeichnet wird.", + "description": "{{ Consultation.description }}", "required": [ "id", "type" @@ -18,11 +18,11 @@ "paper": { "type": "string", "format": "url", - "description": "Referenz auf das Paper, welche nur dann ausgegeben werden muss, wenn das Consultation-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist.", + "description": "{{ Consultation.properties.paper.description }}", "references": "Paper" }, "agendaItem": { - "description": "Referenz auf den Tagesordnungspunkt, unter dem die Drucksache beraten wird, welcher nur dann ausgegeben werden muss, wenn das Consultation-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist.", + "description": "{{ Consultation.properties.agendaItem.description }}", "references": "AgendaItem", "backreference": "consultation", "cardinality": "n:1", @@ -30,14 +30,14 @@ "format": "url" }, "meeting": { - "description": "Referenz auf die Sitzung, in der die Drucksache beraten wird oder wurde, welche nur dann ausgegeben werden muss, wenn das Consultation-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist.", + "description": "{{ Consultation.properties.meeting.description }}", "references": "Meeting", "cardinality": "n:1", "type": "string", "format": "url" }, "organization": { - "description": "Gremium, in dem die Drucksache beraten wird. Hier kann auch eine mit Liste von Gremien angegeben werden (die verschiedenen `oparl:Body` und `oparl:System` angehören können). Die Liste ist dann geordnet. Das erste Gremium der Liste ist federführend.", + "description": "{{ Consultation.properties.organization.description }}", "references": "Organization", "cardinality": "n:m", "type": "array", @@ -47,11 +47,11 @@ } }, "authoritative": { - "description": "Drückt aus, ob bei dieser Beratung ein Beschluss zu der Drucksache gefasst wird oder wurde (`true`) oder nicht (`false`).", + "description": "{{ Consultation.properties.authoritative.description }}", "type": "boolean" }, "role": { - "description": "Rolle oder Funktion der Beratung. Zum Beispiel Anhörung, Entscheidung, Kenntnisnahme, Vorberatung usw.", + "description": "{{ Consultation.properties.role.description }}", "type": "string" }, "license": { @@ -68,4 +68,4 @@ "format": "url" } } -} +} \ No newline at end of file diff --git a/schema/File.json b/schema/File.json index df1b9aa..04dd8fa 100644 --- a/schema/File.json +++ b/schema/File.json @@ -1,6 +1,6 @@ { "title": "File", - "description": "Ein Objekt vom Typ `oparl:File` repräsentiert eine Datei, beispielsweise eine PDF-Datei, ein RTF- oder ODF-Dokument, und hält Metadaten zu der Datei sowie URLs zum Zugriff auf die Datei bereit.\n\nObjekte vom Typ `oparl:File` können unter anderem mit Drucksachen (`oparl:Paper`) oder Sitzungen (`oparl:Meeting`) in Beziehung stehen. Dies wird durch die Eigenschaft `paper` bzw. `meeting` angezeigt.\n\nMehrere Objekte vom Typ `oparl:File` können mit einander in direkter Beziehung stehen, z.B. wenn sie den selben Inhalt in unterschiedlichen technischen Formaten wiedergeben. Hierfür werden die Eigenschaften `masterFile` bzw. `derivativeFile` eingesetzt. Das sgezeigte Beispiel-Objekt repräsentiert eine PDF-Datei (zu erkennen an der Eigenschaft `mimeType`) und zeigt außerdem über die Eigenschaft `masterFile` an, von welcher anderen Datei es abgeleitet wurde. Umgekehrt **kann** über die Eigenschaft `derivativeFile` angezeigt werden, welche Ableitungen einer Datei existieren.", + "description": "{{ File.description }}", "type": "object", "required": [ "id", @@ -17,55 +17,55 @@ "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\\/1\\.1\\/File$" }, "name": { - "description": "Ein zur Anzeige für Endnutzer bestimmter Name für dieses Objekt. Leerzeichen **dürfen** enthalten sein, Datei-Endungen wie \".pdf\" **sollten nicht** enthalten sein.", + "description": "{{ File.properties.name.description }}", "type": "string" }, "fileName": { - "description": "Dateiname, unter dem die Datei in einem Dateisystem gespeichert werden kann. Beispiel: \"einedatei.pdf\". Da der Name den kompletten Unicode-Zeichenumfang nutzen kann, **sollten** Clients ggfs. selbst dafür sorgen, diesen beim Speichern in ein Dateisystem den lokalen Erfordernissen anzupassen.", + "description": "{{ File.properties.fileName.description }}", "type": "string" }, "mimeType": { - "description": "MIME-Type der Datei ^[vgl. RFC2046: ].", + "description": "{{ File.properties.mimeType.description }}", "type": "string" }, "date": { - "description": "Datum, welches als Startpunkt für Fristen u.ä. verwendet ist.", + "description": "{{ File.properties.date.description }}", "type": "string", "format": "date" }, "size": { - "description": "Größe der Datei in Bytes.", + "description": "{{ File.properties.size.description }}", "type": "integer" }, "sha1Checksum": { - "description": "[Veraltet] SHA1-Prüfsumme des Dateiinhalts in Hexadezimal-Schreibweise. Sollte nicht mehr verwendet werden, da sha1 als unsicher gilt. Stattdessen sollte `sha512checksum` verwendet werden.", + "description": "{{ File.properties.sha1Checksum.description }}", "type": "string" }, "sha512Checksum": { - "description": "SHA512-Prüfsumme des Dateiinhalts in Hexadezimal-Schreibweise.", + "description": "{{ File.properties.sha512Checksum.description }}", "type": "string" }, "text": { - "description": "Reine Text-Wiedergabe des Dateiinhalts, sofern dieser in Textform wiedergegeben werden kann.", + "description": "{{ File.properties.text.description }}", "type": "string" }, "accessUrl": { - "description": "URL zum allgemeinen Zugriff auf die Datei. Näheres unter [Dateizugriffe](#dateizugriff).", + "description": "{{ File.properties.accessUrl.description }}", "type": "string", "format": "url" }, "downloadUrl": { - "description": "URL zum Download der Datei. Näheres unter [Dateizugriffe](#dateizugriff).", + "description": "{{ File.properties.downloadUrl.description }}", "type": "string", "format": "url" }, "externalServiceUrl": { - "description": "Externe URL, welche eine zusätzliche Zugriffsmöglichkeit bietet. Beispiel: YouTube-Video.", + "description": "{{ File.properties.externalServiceUrl.description }}", "type": "string", "format": "url" }, "masterFile": { - "description": "Datei, von der das aktuelle Objekt abgeleitet wurde. Details dazu in der allgemeinen Beschreibung weiter oben.", + "description": "{{ File.properties.masterFile.description }}", "references": "File", "backreference": "derivativeFile", "cardinality": "n:1", @@ -73,7 +73,7 @@ "format": "url" }, "derivativeFile": { - "description": "Dateien, die von dem aktuellen Objekt abgeleitet wurden. Details dazu in der allgemeinen Beschreibung weiter oben.", + "description": "{{ File.properties.derivativeFile.description }}", "references": "File", "backreference": "masterFile", "cardinality": "1:n", @@ -84,12 +84,12 @@ } }, "fileLicense": { - "description": "Lizenz, unter der die Datei angeboten wird. Wenn diese Eigenschaft nicht verwendet wird, ist der Wert von `license` beziehungsweise die Lizenz eines übergeordneten Objektes maßgeblich. Siehe [license](#eigenschaft_license)", + "description": "{{ File.properties.fileLicense.description }}", "type": "string", "format": "url" }, "meeting": { - "description": "Rückreferenzen auf Meeting-Objekte. Wird nur dann ausgegeben, wenn das File-Objekt nicht als eingebettetes Objekt aufgerufen wird.", + "description": "{{ File.properties.meeting.description }}", "type": "array", "references": "Meeting", "items": { @@ -98,7 +98,7 @@ } }, "agendaItem": { - "description": "Rückreferenzen auf AgendaItem-Objekte. Wird nur dann ausgegeben, wenn das File-Objekt nicht als eingebettetes Objekt aufgerufen wird.", + "description": "{{ File.properties.agendaItem.description }}", "type": "array", "references": "AgendaItem", "items": { @@ -107,7 +107,7 @@ } }, "paper": { - "description": "Rückreferenzen auf Paper-Objekte. Wird nur dann ausgegeben, wenn das File-Objekt nicht als eingebettetes Objekt aufgerufen wird.", + "description": "{{ File.properties.paper.description }}", "type": "array", "references": "Paper", "items": { @@ -140,4 +140,4 @@ "type": "boolean" } } -} +} \ No newline at end of file diff --git a/schema/LegislativeTerm.json b/schema/LegislativeTerm.json index feec2e9..d2bc190 100644 --- a/schema/LegislativeTerm.json +++ b/schema/LegislativeTerm.json @@ -1,6 +1,6 @@ { "title": "LegislativeTerm", - "description": "Dieser Objekttyp dient der Beschreibung einer Wahlperiode.", + "description": "{{ LegislativeTerm.description }}", "type": "object", "required": [ "id", @@ -18,20 +18,20 @@ "body": { "type": "string", "format": "url", - "description": "Rückreferenz auf die Körperschaft, welche nur dann ausgegeben werden muss, wenn das LegislativeTerm-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist.", + "description": "{{ LegislativeTerm.properties.body.description }}", "references": "Body" }, "name": { - "description": "Nutzerfreundliche Bezeichnung der Wahlperiode.", + "description": "{{ LegislativeTerm.properties.name.description }}", "type": "string" }, "startDate": { - "description": "Der erste Tag der Wahlperiode.", + "description": "{{ LegislativeTerm.properties.startDate.description }}", "type": "string", "format": "date" }, "endDate": { - "description": "Der letzte Tag der Wahlperiode.", + "description": "{{ LegislativeTerm.properties.endDate.description }}", "type": "string", "format": "date" }, @@ -49,4 +49,4 @@ "format": "url" } } -} +} \ No newline at end of file diff --git a/schema/Location.json b/schema/Location.json index 4987187..1aee55d 100644 --- a/schema/Location.json +++ b/schema/Location.json @@ -1,6 +1,6 @@ { "title": "Location", - "description": "Dieser Objekttyp dient dazu, einen Ortsbezug formal abzubilden. Ortsangaben können sowohl aus Textinformationen bestehen (beispielsweise dem Namen einer Straße/eines Platzes oder eine genaue Adresse) als auch aus Geodaten. Ortsangaben sind auch nicht auf einzelne Positionen beschränkt, sondern können eine Vielzahl von Positionen, Flächen, Strecken etc. abdecken.", + "description": "{{ Location.description }}", "type": "object", "required": [ "id", @@ -16,35 +16,35 @@ "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\\/1\\.1\\/Location$" }, "description": { - "description": "Textuelle Beschreibung eines Orts, z. B. in Form einer Adresse.", + "description": "{{ Location.properties.description.description }}", "type": "string" }, "geojson": { - "description": "Geodaten-Repräsentation des Orts. Der Wert dieser Eigenschaft **muss** der Spezifikation von GeoJSON entsprechen, d.h. es **muss** ein vollständiges `Feature`-Objekt ausgegeben werden.", + "description": "{{ Location.properties.geojson.description }}", "type": "object" }, "streetAddress": { - "description": "Straße und Hausnummer der Anschrift.", + "description": "{{ Location.properties.streetAddress.description }}", "type": "string" }, "room": { - "description": "Raumangabe der Anschrift", + "description": "{{ Location.properties.room.description }}", "type": "string" }, "postalCode": { - "description": "Postleitzahl der Anschrift.", + "description": "{{ Location.properties.postalCode.description }}", "type": "string" }, "subLocality": { - "description": "Untergeordnete Ortsangabe der Anschrift, z.B. Stadtbezirk, Ortsteil oder Dorf.", + "description": "{{ Location.properties.subLocality.description }}", "type": "string" }, "locality": { - "description": "Ortsangabe der Anschrift.", + "description": "{{ Location.properties.locality.description }}", "type": "string" }, "bodies": { - "description": "Rückreferenzen auf Body-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt nicht als eingebettetes Objekt aufgerufen wird.", + "description": "{{ Location.properties.bodies.description }}", "type": "array", "items": { "type": "string", @@ -53,7 +53,7 @@ } }, "organizations": { - "description": "Rückreferenzen auf Organization-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt nicht als eingebettetes Objekt aufgerufen wird.", + "description": "{{ Location.properties.organizations.description }}", "type": "array", "items": { "type": "string", @@ -62,7 +62,7 @@ } }, "persons": { - "description": "Rückreferenzen auf Person-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt nicht als eingebettetes Objekt aufgerufen wird.", + "description": "{{ Location.properties.person.description }}", "type": "array", "items": { "type": "string", @@ -71,7 +71,7 @@ } }, "meetings": { - "description": "Rückreferenzen auf Meeting-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt nicht als eingebettetes Objekt aufgerufen wird.", + "description": "{{ Location.properties.meetings.description }}", "type": "array", "items": { "type": "string", @@ -80,7 +80,7 @@ } }, "papers": { - "description": "Rückreferenzen auf Paper-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt nicht als eingebettetes Objekt aufgerufen wird.", + "description": "{{ Location.properties.papers.description }}", "type": "array", "items": { "type": "string", diff --git a/schema/Meeting.json b/schema/Meeting.json index 8bff4b3..303300b 100644 --- a/schema/Meeting.json +++ b/schema/Meeting.json @@ -1,6 +1,6 @@ { "title": "Meeting", - "description": "Eine Sitzung ist die Versammlung einer oder mehrerer Gruppierungen (oparl:Organization) zu einem bestimmten Zeitpunkt an einem bestimmten Ort.\n\nDie geladenen Teilnehmer der Sitzung sind jeweils als Objekte vom Typ oparl:Person, die in entsprechender Form referenziert werden. Verschiedene Dateien (Einladung, Ergebnis- und Wortprotokoll, sonstige Anlagen) können referenziert werden.\n\nDie Inhalte einer Sitzung werden durch Tagesordnungspunkte (oparl:AgendaItem) abgebildet.", + "description": "{{ Meeting.description }}", "type": "object", "required": [ "id", @@ -16,34 +16,34 @@ "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\\/1\\.1\\/Meeting$" }, "name": { - "description": "Name der Sitzung.", + "description": "{{ Meeting.properties.name.description }}", "type": "string" }, "meetingState": { - "description": "Aktueller Status der Sitzung. **Empfohlen** ist die Verwendung von `terminiert` (geplant), `eingeladen` (vor der Sitzung bis zur Freigabe des Protokolls) und `durchgeführt` (nach Freigabe des Protokolls).", + "description": "{{ Meeting.properties.meetingState.description }}", "type": "string" }, "cancelled": { - "description": "Wenn die Sitzung ausfällt, wird cancelled auf true gesetzt.", + "description": "{{ Meeting.properties.cancelled.description }}", "type": "boolean" }, "start": { - "description": "Datum und Uhrzeit des Anfangszeitpunkts der Sitzung. Bei einer zukünftigen Sitzung ist dies der geplante Zeitpunkt, bei einer stattgefundenen **kann** es der tatsächliche Startzeitpunkt sein.", + "description": "{{ Meeting.properties.start.description }}", "type": "string", "format": "date-time" }, "end": { - "description": "Endzeitpunkt der Sitzung als Datum/Uhrzeit. Bei einer zukünftigen Sitzung ist dies der geplante Zeitpunkt, bei einer stattgefundenen **kann** es der tatsächliche Endzeitpunkt sein.", + "description": "{{ Meeting.properties.end.description }}", "type": "string", "format": "date-time" }, "location": { - "description": "Sitzungsort.", + "description": "{{ Meeting.properties.location.description }}", "type": "object", "schema": "Location.json" }, "organization": { - "description": "Gruppierungen, denen die Sitzung zugeordnet ist. Im Regelfall wird hier eine Gruppierung verknüpft sein, es kann jedoch auch gemeinsame Sitzungen mehrerer Gruppierungen geben. Das erste Element **sollte** dann das federführende Gremium sein.", + "description": "{{ Meeting.properties.organization.description }}", "references": "Organization", "backreference": "meeting", "cardinality": "n:m", @@ -54,7 +54,7 @@ } }, "participant": { - "description": "Personen, die an der Sitzung teilgenommen haben (d.h. nicht nur die eingeladenen Personen, sondern die tatsächlich anwesenden). Diese Eigenschaft kann selbstverständlich erst nach dem Stattfinden der Sitzung vorkommen.", + "description": "{{ Meeting.properties.participant.description }}", "references": "Person", "cardinality": "n:m", "type": "array", @@ -64,22 +64,22 @@ } }, "invitation": { - "description": "Einladungsdokument zur Sitzung.", + "description": "{{ Meeting.properties.invitation.description }}", "type": "object", "schema": "File.json" }, "resultsProtocol": { - "description": "Ergebnisprotokoll zur Sitzung. Diese Eigenschaft kann selbstverständlich erst nachdem Stattfinden der Sitzung vorkommen.", + "description": "{{ Meeting.properties.resultsProtocol.description }}", "type": "object", "schema": "File.json" }, "verbatimProtocol": { - "description": "Wortprotokoll zur Sitzung. Diese Eigenschaft kann selbstverständlich erst nach dem Stattfinden der Sitzung vorkommen.", + "description": "{{ Meeting.properties.verbatimProtocol.description }}", "type": "object", "schema": "File.json" }, "auxiliaryFile": { - "description": "Dateianhang zur Sitzung. Hiermit sind Dateien gemeint, die üblicherweise mit der Einladung zu einer Sitzung verteilt werden, und die nicht bereits über einzelne Tagesordnungspunkte referenziert sind.", + "description": "{{ Meeting.properties.auxiliaryFile.description }}", "type": "array", "items": { "type": "object", @@ -87,12 +87,12 @@ } }, "agendaItem": { - "description": "Tagesordnungspunkte der Sitzung. Die Reihenfolge ist relevant. Es kann Sitzungen ohne TOPs geben.", - "type": "array", - "items": { - "type": "object", - "schema": "AgendaItem.json" - } + "description": "{{ Meeting.properties.agendaItem.description }}", + "type": "array", + "items": { + "type": "object", + "schema": "AgendaItem.json" + } }, "license": { "type": "string" @@ -119,4 +119,4 @@ "type": "boolean" } } -} +} \ No newline at end of file diff --git a/schema/Membership.json b/schema/Membership.json index 3bbcc96..dfb8e0f 100644 --- a/schema/Membership.json +++ b/schema/Membership.json @@ -1,6 +1,6 @@ { "title": "Membership", - "description": "Über Objekte diesen Typs wird die Mitgliedschaft von Personen in Gruppierungen dargestellt. Diese Mitgliedschaften können zeitlich begrenzt sein. Zudem kann abgebildet werden, dass eine Person eine bestimmte Rolle bzw. Position innerhalb der Gruppierung inne hat, beispielsweise den Vorsitz einer Fraktion.", + "description": "{{ Membership.description }}", "type": "object", "required": [ "id", @@ -18,36 +18,36 @@ "person": { "type": "string", "format": "url", - "description": "Rückreferenz auf Person, welches nur dann ausgegeben werden muss, wenn das Membership-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist.", + "description": "{{ Membership.properties.person.description }}", "references": "Person" }, "organization": { - "description": "Die Gruppierung, in der die Person Mitglied ist oder war.", + "description": "{{ Membership.properties.organization.description }}", "references": "Organization", "cardinality": "n:1", "type": "string", "format": "url" }, "role": { - "description": "Rolle der Person für die Gruppierung. Kann genutzt werden, um verschiedene Arten von Mitgliedschaften zum Beispiel in Gremien zu unterscheiden.", + "description": "{{ Membership.properties.role.description }}", "type": "string" }, "votingRight": { - "description": "Gibt an, ob die Person in der Gruppierung stimmberechtigtes Mitglied ist.", + "description": "{{ Membership.properties.votingRight.description }}", "type": "boolean" }, "startDate": { - "description": "Datum, an dem die Mitgliedschaft beginnt.", + "description": "{{ Membership.properties.startDate.description }}", "type": "string", "format": "date" }, "endDate": { - "description": "Datum, an dem die Mitgliedschaft endet.", + "description": "{{ Membership.properties.endDate.description }}", "type": "string", "format": "date" }, "onBehalfOf": { - "description": "Die Gruppierung, für die die Person in der unter `organization` angegebenen Organisation sitzt. Beispiel: Mitgliedschaft als Vertreter einer Ratsfraktion, einer Gruppierung oder einer externen Organisation.", + "description": "{{ Membership.properties.onBehalfOf.description }}", "references": "Organization", "cardinality": "n:1", "type": "string", @@ -67,4 +67,4 @@ "format": "url" } } -} +} \ No newline at end of file diff --git a/schema/Organization.json b/schema/Organization.json index 2901c0f..15ac8e5 100644 --- a/schema/Organization.json +++ b/schema/Organization.json @@ -1,6 +1,6 @@ { "title": "Organization", - "description": "Dieser Objekttyp dient dazu, Gruppierungen von Personen abzubilden, die in der parlamentarischen Arbeit eine Rolle spielen. Dazu zählen in der Praxis insbesondere Fraktionen und Gremien.", + "description": "{{ Organization.description }}", "type": "object", "required": [ "id", @@ -16,7 +16,7 @@ "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\\/1\\.1\\/Organization$" }, "body": { - "description": "Körperschaft, zu der diese Gruppierung gehört.", + "description": "{{ Organization.properties.body.description }}", "references": "Body", "backreference": "organization", "cardinality": "n:1", @@ -24,11 +24,11 @@ "format": "url" }, "name": { - "description": "Offizielle (lange) Form des Namens der Gruppierung.", + "description": "{{ Organization.properties.name.description }}", "type": "string" }, "membership": { - "description": "Mitgliedschaften dieser Gruppierung.", + "description": "{{ Organization.properties.membership.description }}", "references": "Membership", "cardinality": "1:n", "backreference": "organization", @@ -39,7 +39,7 @@ } }, "meeting": { - "description": "URL auf eine externe Objektliste mit den Sitzungen dieser Gruppierung. Invers zur Eigenschaft `organization` der Klasse `oparl:Meeting`", + "description": "{{ Organization.properties.meeting.description }}", "type": "string", "format": "url", "references": "externalList", @@ -63,53 +63,53 @@ "cardinality": "n:m" }, "shortName": { - "description": "Der Name der Gruppierung als Kurzform.", + "description": "{{ Organization.properties.shortName.description }}", "type": "string" }, "post": { - "description": "Positionen, die für diese Gruppierung vorgesehen sind.", + "description": "{{ Organization.properties.post.description }}", "type": "array", "items": { "type": "string" } }, "subOrganizationOf": { - "description": "URL einer eventuellen übergeordneten Gruppierung.", + "description": "{{ Organization.properties.subOrganizationOf.description }}", "references": "Organization", "cardinality": "n:1", "type": "string", "format": "url" }, "organizationType": { - "description": "Grobe Kategorisierung der Gruppierung. Mögliche Werte sind \"Gremium\", \"Partei\", \"Fraktion\", \"Verwaltungsbereich\", \"externes Gremium\", \"Institution\" und \"Sonstiges\".", + "description": "{{ Organization.properties.organizationType.description }}", "type": "string" }, "classification": { - "description": "Die Art der Gruppierung. In Frage kommen z.B. \"Parlament\", \"Ausschuss\", \"Beirat\", \"Projektbeirat\", \"Kommission\", \"AG\", \"Verwaltungsrat\", \"Fraktion\" oder \"Partei\". Die Angabe **sollte** möglichst präzise erfolgen. Außerdem **sollten** Abkürzungen vermieden werden. Für die höchste demokratische Instanz in der Kommune **sollte** immer der Begriff \"Parlament\" verwendet werden, nicht \"Rat\" oder \"Hauptausschuss\".", + "description": "{{ Organization.properties.classification.description }}", "type": "string" }, "startDate": { - "description": "Gründungsdatum der Gruppierung. Kann z. B. das Datum der konstituierenden Sitzung sein.", + "description": "{{ Organization.properties.startDate.description }}", "type": "string", "format": "date" }, "endDate": { - "description": "Datum des letzten Tages der Existenz der Gruppierung.", + "description": "{{ Organization.properties.endDate.description }}", "type": "string", "format": "date" }, "website": { - "description": "Allgemeine Website der Gruppierung.", + "description": "{{ Organization.properties.website.description }}", "type": "string", "format": "url" }, "location": { - "description": "Ort, an dem die Organisation beheimatet ist", + "description": "{{ Organization.properties.location.description }}", "type": "object", "schema": "Location.json" }, "externalBody": { - "description": "Externer OParl Body, der dieser Organisation entspricht. Diese Eigenschaft ist dafür gedacht auf eventuelle konkretere OParl-Schnittstellen zu verweisen. Ein Beispiel hierfür wäre eine Stadt, die sowohl ein übergreifendes parlamentarisches Informationssystem, als auch bezirksspezifische Systeme hat.", + "description": "{{ Organization.properties.externalBody.description }}", "references": "Body", "cardinality": "n:1", "type": "string", @@ -140,4 +140,4 @@ "type": "boolean" } } -} +} \ No newline at end of file diff --git a/schema/Paper.json b/schema/Paper.json index ead2376..7dba67f 100644 --- a/schema/Paper.json +++ b/schema/Paper.json @@ -1,6 +1,6 @@ { "title": "Paper", - "description": "Dieser Objekttyp dient der Abbildung von Drucksachen in der parlamentarischen Arbeit, wie zum Beispiel Anfragen, Anträgen und Beschlussvorlagen.\n\nDrucksachen werden in Form einer Beratung (oparl:Consultation) im Rahmen eines Tagesordnungspunkts (oparl:AgendaItem) einer Sitzung (oparl:Meeting) behandelt.\n\nDrucksachen spielen in der schriftlichen wie mündlichen Kommunikation eine besondere Rolle, da in vielen Texten auf bestimmte Drucksachen Bezug genommen wird. Hierbei kommen in parlamentarischen Informationssystemen in der Regel unveränderliche Kennungen der Drucksachen zum Einsatz.", + "description": "{{ Paper.description }}", "type": "object", "required": [ "id", @@ -16,7 +16,7 @@ "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\\/1\\.1\\/Paper$" }, "body": { - "description": "Körperschaft, zu der die Drucksache gehört.", + "description": "{{ Paper.properties.body.description }}", "references": "Body", "backreference": "meeting", "cardinality": "n:1", @@ -24,24 +24,24 @@ "format": "url" }, "name": { - "description": "Titel der Drucksache.", + "description": "{{ Paper.properties.name.description }}", "type": "string" }, "reference": { - "description": "Kennung bzw. Aktenzeichen der Drucksache, mit der sie in der parlamentarischen Arbeit eindeutig referenziert werden kann.", + "description": "{{ Paper.properties.reference.description }}", "type": "string" }, "date": { - "description": "Datum, welches als Startpunkt für Fristen u.ä. verwendet ist.", + "description": "{{ Paper.properties.date.description }}", "type": "string", "format": "date" }, "paperType": { - "description": "Art der Drucksache, z. B. Beantwortung einer Anfrage.", + "description": "{{ Paper.properties.paperType.description }}", "type": "string" }, "relatedPaper": { - "description": "Inhaltlich verwandte Drucksachen.", + "description": "{{ Paper.properties.relatedPaper.description }}", "references": "Paper", "cardinality": "1:n", "type": "array", @@ -51,7 +51,7 @@ } }, "superordinatedPaper": { - "description": "Übergeordnete Drucksachen.", + "description": "{{ Paper.properties.superordinatedPaper.description }}", "references": "Paper", "cardinality": "1:n", "type": "array", @@ -61,7 +61,7 @@ } }, "subordinatedPaper": { - "description": "Untergeordnete Drucksachen.", + "description": "{{ Paper.properties.subordinatedPaper.description }}", "references": "Paper", "cardinality": "1:n", "type": "array", @@ -71,12 +71,12 @@ } }, "mainFile": { - "description": "Die Hauptdatei zu dieser Drucksache. Beispiel: Die Drucksache repräsentiert eine Beschlussvorlage und die Hauptdatei enthält den Text der Beschlussvorlage. Sollte keine eindeutige Hauptdatei vorhanden sein, wird diese Eigenschaft nicht ausgegeben.", + "description": "{{ Paper.properties.mainFile.description }}", "type": "object", "schema": "File.json" }, "auxiliaryFile": { - "description": "Alle weiteren Dateien zur Drucksache ausgenommen der gegebenenfalls in `mainFile` angegebenen.", + "description": "{{ Paper.properties.auxiliaryFile.description }}", "type": "array", "items": { "type": "object", @@ -84,7 +84,7 @@ } }, "location": { - "description": "Sofern die Drucksache einen inhaltlichen Ortsbezug hat, beschreibt diese Eigenschaft den Ort in Textform und/oder in Form von Geodaten.", + "description": "{{ Paper.properties.location.description }}", "type": "array", "items": { "type": "object", @@ -92,7 +92,7 @@ } }, "originatorPerson": { - "description": "Urheber der Drucksache, falls der Urheber eine Person ist. Es können auch mehrere Personen angegeben werden.", + "description": "{{ Paper.properties.originatorPerson.description }}", "references": "Person", "cardinality": "n:m", "type": "array", @@ -102,7 +102,7 @@ } }, "underDirectionOf": { - "description": "Federführung. Amt oder Abteilung, für die Inhalte oder Beantwortung der Drucksache verantwortlich.", + "description": "{{ Paper.properties.underDirectionOf.description }}", "references": "Organization", "cardinality": "n:m", "type": "array", @@ -112,7 +112,7 @@ } }, "originatorOrganization": { - "description": "Urheber der Drucksache, falls der Urheber eine Gruppierung ist. Es können auch mehrere Gruppierungen angegeben werden.", + "description": "{{ Paper.properties.originatorOrganization.description }}", "references": "Organization", "cardinality": "n:m", "type": "array", @@ -122,7 +122,7 @@ } }, "consultation": { - "description": "Beratungen der Drucksache.", + "description": "{{ Paper.properties.consultation.description }}", "type": "array", "items": { "type": "object", @@ -154,4 +154,4 @@ "type": "boolean" } } -} +} \ No newline at end of file diff --git a/schema/Person.json b/schema/Person.json index b2c0234..39f44a4 100644 --- a/schema/Person.json +++ b/schema/Person.json @@ -1,6 +1,6 @@ { "title": "Person", - "description": "Jede natürliche Person, die in der parlamentarischen Arbeit tätig und insbesondere Mitglied in einer Gruppierung ([oparl:Organization](#oparl_organization)) ist, wird mit einem Objekt vom Typ `oparl:Person` abgebildet.", + "description": "{{ Person.description }}", "type": "object", "required": [ "id", @@ -16,7 +16,7 @@ "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\\/1\\.1\\/Person$" }, "body": { - "description": "Körperschaft, zu der die Person gehört.", + "description": "{{ Person.properties.body.description }}", "references": "Body", "backreference": "person", "cardinality": "n:1", @@ -24,52 +24,52 @@ "format": "url" }, "name": { - "description": "Der vollständige Name der Person mit akademischem Grad und dem gebräuchlichen Vornamen, wie er zur Anzeige durch den Client genutzt werden kann.", + "description": "{{ Person.properties.name.description }}", "type": "string" }, "familyName": { - "description": "Familienname bzw. Nachname.", + "description": "{{ Person.properties.familyName.description }}", "type": "string" }, "givenName": { - "description": "Vorname bzw. Taufname.", + "description": "{{ Person.properties.givenName.description }}", "type": "string" }, "formOfAddress": { - "description": "Anrede.", + "description": "{{ Person.properties.formOfAddress.description }}", "type": "string" }, "affix": { - "description": "Namenszusatz (z.B. `jun.` oder `MdL.`)", + "description": "{{ Person.properties.affix.description }}", "type": "string" }, "title": { - "description": "Akademische Titel", + "description": "{{ Person.properties.title.description }}", "items": { "type": "string" }, "type": "array" }, "gender": { - "description": "Geschlecht. Empfohlene Werte sind `female`, `male` und `other`. Für den Fall, dass das Geschlecht der Person unbekannt ist, **sollte** die Eigenschaft nicht ausgegeben werden.", + "description": "{{ Person.properties.gender.description }}", "type": "string" }, "phone": { - "description": "Telefonnummern der Person.", + "description": "{{ Person.properties.phone.description }}", "items": { "type": "string" }, "type": "array" }, "email": { - "description": "E-Mail-Adressen der Person.", + "description": "{{ Person.properties.email.description }}", "items": { "type": "string" }, "type": "array" }, "location": { - "description": "Referenz der Kontakt-Anschrift der Person.", + "description": "{{ Person.properties.location.description }}", "references": "Location", "backreference": "person", "cardinality": "n:1", @@ -77,19 +77,19 @@ "format": "url" }, "locationObject": { - "description": "Kontakt-Anschrift der Person. Wenn diese Eigenschaft ausgegeben wird, dann **muss** auch die Eigenschaft `location` ausgegeben werden und auf das gleiche Location-Objekt verweisen. Dies sollte die eigentliche Ausgabeform von `location` in OParl 1.0 werden, was jedoch auf Grund eines Fehlers nicht geschehen ist. s. https://github.com/OParl/spec/issues/373. Neu in OParl 1.1", + "description": "{{ Person.properties.locationObject.description }}", "type": "object", "schema": "Location.json" }, "status": { - "description": "Status, d.h. Rollen in der Kommune.", + "description": "{{ Person.properties.status.description }}", "items": { "type": "string" }, "type": "array" }, "membership": { - "description": "Mitgliedschaften der Person in Gruppierungen, z. B. Gremien und Fraktionen. Es **sollen** sowohl aktuelle als auch vergangene Mitgliedschaften angegeben werden", + "description": "{{ Person.properties.membership.description }}", "type": "array", "items": { "type": "object", @@ -97,11 +97,11 @@ } }, "life": { - "description": "Kurzer Informationstext zur Person. Eine Länge von weniger als 300 Zeichen ist **empfohlen**", + "description": "{{ Person.properties.life.description }}", "type": "string" }, "lifeSource": { - "description": "Angabe der Quelle, aus der die Informationen für `life` stammen. Bei Angabe von `life` ist diese Eigenschaft **empfohlen**", + "description": "{{ Person.properties.lifeSource.description }}", "type": "string" }, "license": { diff --git a/schema/System.json b/schema/System.json index 40b0011..6740067 100644 --- a/schema/System.json +++ b/schema/System.json @@ -1,6 +1,6 @@ { "title": "System", - "description": "Ein `oparl:System`-Objekt repräsentiert eine OParl-Schnittstelle für eine bestimmte OParl-Version. Es ist außerdem der Startpunkt für Clients beim Zugriff auf einen Server.\n\nMöchte ein Server mehrere zueinander inkompatible OParl-Versionen unterstützen, dann **muss** der Server für jede Version eine eigenen OParl-Schnittstelle mit einem eigenen `System`-Objekt ausgeben.", + "description": "{{ System.description }}", "type": "object", "required": [ "id", @@ -19,11 +19,11 @@ }, "oparlVersion": { "type": "string", - "pattern": "^https\\:\\/\\/schema\\.oparl\\.org\/1\\.(0|1)\\/$", - "description": "Die URL der OParl-Spezifikation, die von diesem Server unterstützt wird. Aktuell kommt hier nur ein Wert in Frage. Mit zukünftigen OParl-Versionen kommen weitere mögliche URLs hinzu. Wert: `https://schema.oparl.org/1.1/`" + "pattern": "^https\\:\\/\\/schema\\.oparl\\.org/1\\.(0|1)\\/$", + "description": "{{ System.properties.oparlVersion.description }}" }, "otherOparlVersions": { - "description": "Dient der Angabe von System-Objekten mit anderen OParl-Versionen.", + "description": "{{ System.properties.otherOparlVersions.description }}", "references": "System", "items": { "type": "string", @@ -32,12 +32,12 @@ "type": "array" }, "license": { - "description": "Lizenz, unter der durch diese API abrufbaren Daten stehen, sofern nicht am einzelnen Objekt anders angegeben. Siehe [`license`](#eigenschaft_license).", + "description": "{{ System.properties.license.description }}", "type": "string", "format": "url" }, "body": { - "description": "Link zur [Objektliste](#objektlisten) mit allen Körperschaften, die auf dem System existieren.", + "description": "{{ System.properties.body.description }}", "type": "string", "format": "url", "references": "externalList", @@ -47,29 +47,29 @@ } }, "name": { - "description": "Nutzerfreundlicher Name für das System, mit dessen Hilfe Nutzerinnen und Nutzer das System erkennen und von anderen unterscheiden können. Falls ein System nur einen `oparl:Body` enthält, SOLLTE der Name des Systems dem Name des Body entsprechen.", + "description": "{{ System.properties.name.description }}", "type": "string" }, "contactEmail": { - "description": "E-Mail-Adresse für Anfragen zur OParl-API. Die Angabe einer E-Mail-Adresse dient sowohl NutzerInnen wie auch Entwicklerinnen von Clients zur Kontaktaufnahme mit dem Betreiber.", + "description": "{{ System.properties.contactEmail.description }}", "type": "string" }, "contactName": { - "description": "Name der Ansprechpartnerin bzw. des Ansprechpartners oder der Abteilung, die über die in `contactEmail` angegebene Adresse erreicht werden kann.", + "description": "{{ System.properties.contactName.description }}", "type": "string" }, "website": { - "description": "URL der Website des parlamentarischen Informationssystems", + "description": "{{ System.properties.website.description }}", "type": "string", "format": "url" }, "vendor": { - "description": "URL der Website des Softwareanbieters, von dem die OParl-Server-Software stammt.", + "description": "{{ System.properties.vendor.description }}", "type": "string", "format": "url" }, "product": { - "description": "URL zu Informationen über die auf dem System genutzte OParl-Server-Software", + "description": "{{ System.properties.product.description }}", "type": "string", "format": "url" }, @@ -89,4 +89,4 @@ "type": "boolean" } } -} +} \ No newline at end of file diff --git a/schema/strings.yml b/schema/strings.yml new file mode 100644 index 0000000..200e8d1 --- /dev/null +++ b/schema/strings.yml @@ -0,0 +1,237 @@ +de: + AgendaItem.description: | + Tagesordnungspunkte sind die Bestandteile von Sitzungen (`oparl:Meeting`). + Jeder Tagesordnungspunkt widmet sich inhaltlich einem bestimmten Thema, wozu + in der Regel auch die Beratung bestimmter Drucksachen gehört. + + Die Beziehung zwischen einem Tagesordnungspunkt und einer Drucksache wird + über ein Objekt vom Typ `oparl:Consultation` hergestellt, das über die + Eigenschaft `consultation` referenziert werden kann. + AgendaItem.properties.meeting.description: | + Rückreferenz auf das Meeting, welches nur dann ausgegeben werden muss, + wenn das agendaItem-Objekt einzeln abgerufen wird, d.h. nicht Teil einer + internen Ausgabe ist. + AgendaItem.properties.number.description: | + Gliederungs-"Nummer" des Tagesordnungspunktes. Eine beliebige Zeichenkette, + wie z. B. "10.", "10.1", "C", "c)" o. ä. Die Reihenfolge wird nicht dadurch, + sondern durch die Reihenfolge der TOPs im `agendaItem`-Attribut von `oparl:Meeting` + festgelegt, **sollte** allerdings zu dieser identisch sein. + AgendaItem.properties.name.description: Das Thema des Tagesordnungspunktes. + AgendaItem.properties.public.description: | + Kennzeichnet, ob der Tagesordnungspunkt zur Behandlung in öffentlicher Sitzung + vorgesehen ist/war. Es wird ein Wahrheitswert (`true` oder `false`) erwartet. + AgendaItem.properties.consultation.description: Beratung, die diesem Tagesordnungspunkt zugewiesen ist. + AgendaItem.properties.result.description: | + Kategorische Information darüber, welches Ergebnis die Beratung des + Tagesordnungspunktes erbracht hat, in der Bedeutung etwa "Unverändert + beschlossen" oder "Geändert beschlossen". + AgendaItem.properties.resolutionText.description: | + Falls in diesem Tagesordnungspunkt ein Beschluss gefasst wurde, kann hier ein + Text angegeben werden. Das ist besonders dann in der Praxis relevant, wenn der + gefasste Beschluss (z. B. durch Änderungsantrag) von der Beschlussvorlage abweicht. + AgendaItem.properties.resolutionFile.description: | + Falls in diesem Tagesordnungspunkt ein Beschluss gefasst wurde, kann hier eine + Datei angegeben werden. Das ist besonders dann in der Praxis relevant, wenn der + gefasste Beschluss (z. B. durch Änderungsantrag) von der Beschlussvorlage abweicht. + AgendaItem.properties.auxiliaryFile.description: Weitere Dateianhänge zum Tagesordnungspunkt. + AgendaItem.properties.start.description: | + Datum und Uhrzeit des Anfangszeitpunkts des Tagesordnungspunktes. Bei zukünftigen + Tagesordnungspunkten ist dies der geplante Zeitpunkt, bei einem stattgefundenen **kann** + es der tatsächliche Startzeitpunkt sein. + AgendaItem.properties.end.description: | + Endzeitpunkt des Tagesordnungspunktes als Datum/Uhrzeit. Bei zukünftigen + Tagesordnungspunkten ist dies der geplante Zeitpunkt, bei einer + stattgefundenen **kann** es der tatsächliche Endzeitpunkt sein. + Person.description: | + Jede natürliche Person, die in der parlamentarischen Arbeit tätig und insbesondere + Mitglied in einer Gruppierung ([oparl:Organization](#oparl_organization)) ist, wird + mit einem Objekt vom Typ `oparl:Person` abgebildet. + Person.properties.body.description: Körperschaft, zu der die Person gehört. + Person.properties.name.description: | + Der vollständige Name der Person mit akademischem Grad und dem gebräuchlichen Vornamen, + wie er zur Anzeige durch den Client genutzt werden kann. + Person.properties.familyName.description: Familienname bzw. Nachname. + Person.properties.givenName.description: Vorname bzw. Taufname. + Person.properties.formOfAddress.description: Anrede. + Person.properties.affix.description: Namenszusatz (z.B. `jun.` oder `MdL.`) + Person.properties.title.description: Akademische Titel + Person.properties.gender.description: | + Geschlecht. Empfohlene Werte sind `female`, `male` und `other`. Für den Fall, dass + das Geschlecht der Person unbekannt ist, **sollte** die Eigenschaft nicht ausgegeben werden. + Person.properties.phone.description: Telefonnummern der Person. + Person.properties.email.description: E-Mail-Adressen der Person. + Person.properties.location.description: Referenz der Kontakt-Anschrift der Person. + Person.properties.locationObject.description: | + Kontakt-Anschrift der Person. Wenn diese Eigenschaft ausgegeben wird, dann **muss** + auch die Eigenschaft `location` ausgegeben werden und auf das gleiche Location-Objekt verweisen. + Dieses Feld sollte die eigentliche Ausgabeform von `location` in OParl 1.0 werden. + vgl. https://github.com/OParl/spec/issues/373. Neu in OParl 1.1 + Person.properties.status.description: Status, d.h. Rollen in der Kommune. + Person.properties.membership.description: | + Mitgliedschaften der Person in Gruppierungen, z. B. Gremien und Fraktionen. Es **sollen** + sowohl aktuelle als auch vergangene Mitgliedschaften angegeben werden + Person.properties.life.description: Kurzer Informationstext zur Person. Eine Länge von weniger als 300 Zeichen ist **empfohlen** + Person.properties.lifeSource.description: Angabe der Quelle, aus der die Informationen für `life` stammen. Bei Angabe von `life` ist diese Eigenschaft **empfohlen** + File.description: | + Ein Objekt vom Typ `oparl:File` repräsentiert eine Datei, beispielsweise eine PDF-Datei, ein RTF- oder ODF-Dokument, + und hält Metadaten zu der Datei sowie URLs zum Zugriff auf die Datei bereit. + + Objekte vom Typ `oparl:File` können unter anderem mit Drucksachen (`oparl:Paper`) oder Sitzungen (`oparl:Meeting`) in Beziehung stehen. + Dies wird durch die Eigenschaft `paper` bzw. `meeting` angezeigt. Mehrere Objekte vom Typ `oparl:File` können mit einander in direkter + Beziehung stehen, z.B. wenn sie den selben Inhalt in unterschiedlichen technischen Formaten wiedergeben. Hierfür werden die + Eigenschaften `masterFile` bzw. `derivativeFile` eingesetzt. Das sgezeigte Beispiel-Objekt repräsentiert eine PDF-Datei + (zu erkennen an der Eigenschaft `mimeType`) und zeigt außerdem über die Eigenschaft `masterFile` an, von welcher anderen Datei es + abgeleitet wurde. Umgekehrt **kann** über die Eigenschaft `derivativeFile` angezeigt werden, welche Ableitungen einer Datei existieren. + File.properties.name.description: "Ein zur Anzeige für Endnutzer bestimmter Name für dieses Objekt. Leerzeichen **dürfen** enthalten sein, Datei-Endungen wie \".pdf\" **sollten nicht** enthalten sein." + File.properties.fileName.description: "Dateiname, unter dem die Datei in einem Dateisystem gespeichert werden kann. Beispiel: \"einedatei.pdf\". Da der Name den kompletten Unicode-Zeichenumfang nutzen kann, **sollten** Clients ggfs. selbst dafür sorgen, diesen beim Speichern in ein Dateisystem den lokalen Erfordernissen anzupassen." + File.properties.mimeType.description: "MIME-Type der Datei ^[vgl. RFC2046: ]." + File.properties.date.description: Datum, welches als Startpunkt für Fristen u.ä. verwendet ist. + File.properties.size.description: Größe der Datei in Bytes. + File.properties.sha1Checksum.description: "[Veraltet] SHA1-Prüfsumme des Dateiinhalts in Hexadezimal-Schreibweise. Sollte nicht mehr verwendet werden, da sha1 als unsicher gilt. Stattdessen sollte `sha512checksum` verwendet werden." + File.properties.sha512Checksum.description: SHA512-Prüfsumme des Dateiinhalts in Hexadezimal-Schreibweise. + File.properties.text.description: Reine Text-Wiedergabe des Dateiinhalts, sofern dieser in Textform wiedergegeben werden kann. + File.properties.accessUrl.description: URL zum allgemeinen Zugriff auf die Datei. Näheres unter [Dateizugriffe](#dateizugriff). + File.properties.downloadUrl.description: URL zum Download der Datei. Näheres unter [Dateizugriffe](#dateizugriff). + File.properties.externalServiceUrl.description: "Externe URL, welche eine zusätzliche Zugriffsmöglichkeit bietet. Beispiel: YouTube-Video." + File.properties.masterFile.description: Datei, von der das aktuelle Objekt abgeleitet wurde. Details dazu in der allgemeinen Beschreibung weiter oben. + File.properties.derivativeFile.description: Dateien, die von dem aktuellen Objekt abgeleitet wurden. Details dazu in der allgemeinen Beschreibung weiter oben. + File.properties.fileLicense.description: Lizenz, unter der die Datei angeboten wird. Wenn diese Eigenschaft nicht verwendet wird, ist der Wert von `license` beziehungsweise die Lizenz eines übergeordneten Objektes maßgeblich. Siehe [license](#eigenschaft_license) + File.properties.meeting.description: Rückreferenzen auf Meeting-Objekte. Wird nur dann ausgegeben, wenn das File-Objekt nicht als eingebettetes Objekt aufgerufen wird. + File.properties.agendaItem.description: Rückreferenzen auf AgendaItem-Objekte. Wird nur dann ausgegeben, wenn das File-Objekt nicht als eingebettetes Objekt aufgerufen wird. + File.properties.paper.description: Rückreferenzen auf Paper-Objekte. Wird nur dann ausgegeben, wenn das File-Objekt nicht als eingebettetes Objekt aufgerufen wird. + LegislativeTerm.description: Dieser Objekttyp dient der Beschreibung einer Wahlperiode. + LegislativeTerm.properties.body.description: Rückreferenz auf die Körperschaft, welche nur dann ausgegeben werden muss, wenn das LegislativeTerm-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist. + LegislativeTerm.properties.name.description: Nutzerfreundliche Bezeichnung der Wahlperiode. + LegislativeTerm.properties.startDate.description: Der erste Tag der Wahlperiode. + LegislativeTerm.properties.endDate.description: Der letzte Tag der Wahlperiode. + Body.description: | + Der Objekttyp oparl:Body dient dazu, eine Körperschaft zu repräsentieren. Eine Körperschaft ist in den meisten Fällen eine Gemeinde, eine Stadt oder ein Landkreis. + In der Regel sind auf einem OParl-Server Daten von genau einer Körperschaft gespeichert und es wird daher auch nur ein Body-Objekt ausgegeben. Sind auf dem Server jedoch Daten von mehreren Körperschaften gespeichert, **muss** für jede Körperschaft ein eigenes Body-Objekt ausgegeben werden. + Body.properties.system.description: System, zu dem dieses Objekt gehört. + Body.properties.shortName.description: Kurzer Name der Körperschaft. + Body.properties.name.description: Der offizielle lange Name der Körperschaft. + Body.properties.website.description: Allgemeine Website der Körperschaft. + Body.properties.license.description: Lizenz, unter der die Daten dieser Körperschaft stehen, sofern nicht am einzelnen Objekt anders angegeben. Siehe [`license`](#eigenschaft_license). + Body.properties.licenseValidSince.description: Zeitpunkt, seit dem die unter `license` angegebene Lizenz gilt. _Vorsicht bei Änderungen der Lizenz die zu restriktiveren Bedingungen führen!_ + Body.properties.oparlSince.description: Zeitpunkt, ab dem OParl für dieses Body bereitgestellt wurde. Dies hilft, um die Datenqualität einzuschätzen, denn erst ab der Einrichtung für OParl kann sichergestellt werden, dass sämtliche Werte korrekt in der Original-Quelle vorliegen. + Body.properties.ags.description: Der achtstellige Amtliche Gemeindeschlüssel^[Amtliche Gemeindeschlüssel können im [Gemeindeverzeichnis (GV-ISys) des Statistischen Bundesamtes](https://www.destatis.de/DE/ZahlenFakten/LaenderRegionen/Regionales/Gemeindeverzeichnis/Gemeindeverzeichnis.html) eingesehen werden]. + Body.properties.rgs.description: Der zwölfstellige Regionalschlüssel. + Body.properties.equivalent.description: Dient der Angabe zusätzlicher URLs, die dieselbe Körperschaft repräsentieren. Hier können beispielsweise der entsprechende Eintrag der gemeinsamen Normdatei der Deutschen Nationalbibliothek^[Gemeinsame Normdatei ], der DBPedia^[DBPedia ] oder der Wikipedia^[Wikipedia ] angegeben werden. Body- oder System-Objekte mit anderen OParl-Versionen **dürfen nicht** Teil der Liste sein. + Body.properties.contactEmail.description: Dient der Angabe einer Kontakt-E-Mail-Adresse. Die Adresse soll die Kontaktaufnahme zu einer für die Körperschaft und idealerweise das parlamentarische Informationssystem zuständigen Stelle ermöglichen. + Body.properties.contactName.description: Name oder Bezeichnung der mit `contactEmail` erreichbaren Stelle. + Body.properties.organization.description: Link zur [Objektliste](#objektlisten) mit allen Gruppierungen der Körperschaft. + Body.properties.person.description: Link zur [Objektliste](#objektlisten) mit allen Personen der Körperschaft. + Body.properties.meeting.description: Link zur [Objektliste](#objektlisten) mit allen Sitzungen der Körperschaft. + Body.properties.paper.description: Link zur [Objektliste](#objektlisten) mit allen Drucksachen der Körperschaft. + Body.properties.legislativeTerm.description: "[Objektliste](#objektlisten) mit den Wahlperioden der Körperschaft." + Body.properties.classification.description: Art der Körperschaft. + Body.properties.location.description: Ort, an dem die Körperschaft beheimatet ist. + Consultation.description: | + Der Objekttyp `oparl:Consultation` dient dazu, die Beratung einer Drucksache ([`oparl:Paper`](#oparl_paper)) in einer Sitzung abzubilden. Dabei ist es nicht entscheidend, ob diese Beratung in der Vergangenheit stattgefunden hat oder diese für die Zukunft geplant ist. + Die Gesamtheit aller Objekte des Typs `oparl:Consultation` zu einer bestimmten Drucksache bildet das ab, was in der Praxis als "Beratungsfolge" der Drucksache bezeichnet wird. + Consultation.properties.paper.description: Referenz auf das Paper, welche nur dann ausgegeben werden muss, wenn das Consultation-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist. + Consultation.properties.agendaItem.description: Referenz auf den Tagesordnungspunkt, unter dem die Drucksache beraten wird, welcher nur dann ausgegeben werden muss, wenn das Consultation-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist. + Consultation.properties.meeting.description: Referenz auf die Sitzung, in der die Drucksache beraten wird oder wurde, welche nur dann ausgegeben werden muss, wenn das Consultation-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist. + Consultation.properties.organization.description: Gremium, in dem die Drucksache beraten wird. Hier kann auch eine mit Liste von Gremien angegeben werden (die verschiedenen `oparl:Body` und `oparl:System` angehören können). Die Liste ist dann geordnet. Das erste Gremium der Liste ist federführend. + Consultation.properties.authoritative.description: Drückt aus, ob bei dieser Beratung ein Beschluss zu der Drucksache gefasst wird oder wurde (`true`) oder nicht (`false`). + Consultation.properties.role.description: Rolle oder Funktion der Beratung. Zum Beispiel Anhörung, Entscheidung, Kenntnisnahme, Vorberatung usw. + Location.description: Dieser Objekttyp dient dazu, einen Ortsbezug formal abzubilden. Ortsangaben können sowohl aus Textinformationen bestehen (beispielsweise dem Namen einer Straße/eines Platzes oder eine genaue Adresse) als auch aus Geodaten. Ortsangaben sind auch nicht auf einzelne Positionen beschränkt, sondern können eine Vielzahl von Positionen, Flächen, Strecken etc. abdecken. + Location.properties.description.description: Textuelle Beschreibung eines Orts, z. B. in Form einer Adresse. + Location.properties.geojson.description: | + Geodaten-Repräsentation des Orts. Der Wert dieser Eigenschaft **muss** der Spezifikation + von GeoJSON entsprechen, d.h. es **muss** ein vollständiges `Feature`-Objekt ausgegeben werden. + Location.properties.streetAddress.description: Straße und Hausnummer der Anschrift. + Location.properties.room.description: Raumangabe der Anschrift + Location.properties.postalCode.description: Postleitzahl der Anschrift. + Location.properties.subLocality.description: Untergeordnete Ortsangabe der Anschrift, z.B. Stadtbezirk, Ortsteil oder Dorf. + Location.properties.locality.description: Ortsangabe der Anschrift. + Location.properties.bodies.description: | + Rückreferenzen auf Body-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt + nicht als eingebettetes Objekt aufgerufen wird. + Location.properties.organizations.description: | + Rückreferenzen auf Organization-Objekte. Wird nur dann ausgegeben, + wenn das Location-Objekt nicht als eingebettetes Objekt aufgerufen wird. + Location.properties.meetings.description: | + Rückreferenzen auf Meeting-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt + nicht als eingebettetes Objekt aufgerufen wird. + Location.properties.papers.description: | + Rückreferenzen auf Paper-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt + nicht als eingebettetes Objekt aufgerufen wird. + Location.properties.persons.description: | + Rückreferenzen auf Person-Objekte. Wird nur dann ausgegeben, wenn das Location-Objekt + nicht als eingebettetes Objekt aufgerufen wird. + Organization.description: Dieser Objekttyp dient dazu, Gruppierungen von Personen abzubilden, die in der parlamentarischen Arbeit eine Rolle spielen. Dazu zählen in der Praxis insbesondere Fraktionen und Gremien. + Organization.properties.body.description: Körperschaft, zu der diese Gruppierung gehört. + Organization.properties.name.description: Offizielle (lange) Form des Namens der Gruppierung. + Organization.properties.membership.description: Mitgliedschaften dieser Gruppierung. + Organization.properties.meeting.description: URL auf eine externe Objektliste mit den Sitzungen dieser Gruppierung. Invers zur Eigenschaft `organization` der Klasse `oparl:Meeting` + Organization.properties.shortName.description: Der Name der Gruppierung als Kurzform. + Organization.properties.post.description: Positionen, die für diese Gruppierung vorgesehen sind. + Organization.properties.subOrganizationOf.description: URL einer eventuellen übergeordneten Gruppierung. + Organization.properties.organizationType.description: Grobe Kategorisierung der Gruppierung. Mögliche Werte sind "Gremium", "Partei", "Fraktion", "Verwaltungsbereich", "externes Gremium", "Institution" und "Sonstiges". + Organization.properties.classification.description: Die Art der Gruppierung. In Frage kommen z.B. "Parlament", "Ausschuss", "Beirat", "Projektbeirat", "Kommission", "AG", "Verwaltungsrat", "Fraktion" oder "Partei". Die Angabe **sollte** möglichst präzise erfolgen. Außerdem **sollten** Abkürzungen vermieden werden. Für die höchste demokratische Instanz in der Kommune **sollte** immer der Begriff "Parlament" verwendet werden, nicht "Rat" oder "Hauptausschuss". + Organization.properties.startDate.description: Gründungsdatum der Gruppierung. Kann z. B. das Datum der konstituierenden Sitzung sein. + Organization.properties.endDate.description: Datum des letzten Tages der Existenz der Gruppierung. + Organization.properties.website.description: Allgemeine Website der Gruppierung. + Organization.properties.location.description: Ort, an dem die Organisation beheimatet ist + Organization.properties.externalBody.description: Externer OParl Body, der dieser Organisation entspricht. Diese Eigenschaft ist dafür gedacht auf eventuelle konkretere OParl-Schnittstellen zu verweisen. Ein Beispiel hierfür wäre eine Stadt, die sowohl ein übergreifendes parlamentarisches Informationssystem, als auch bezirksspezifische Systeme hat. + Membership.description: Über Objekte diesen Typs wird die Mitgliedschaft von Personen in Gruppierungen dargestellt. Diese Mitgliedschaften können zeitlich begrenzt sein. Zudem kann abgebildet werden, dass eine Person eine bestimmte Rolle bzw. Position innerhalb der Gruppierung inne hat, beispielsweise den Vorsitz einer Fraktion. + Membership.properties.person.description: Rückreferenz auf Person, welches nur dann ausgegeben werden muss, wenn das Membership-Objekt einzeln abgerufen wird, d.h. nicht Teil einer internen Ausgabe ist. + Membership.properties.organization.description: Die Gruppierung, in der die Person Mitglied ist oder war. + Membership.properties.role.description: Rolle der Person für die Gruppierung. Kann genutzt werden, um verschiedene Arten von Mitgliedschaften zum Beispiel in Gremien zu unterscheiden. + Membership.properties.votingRight.description: Gibt an, ob die Person in der Gruppierung stimmberechtigtes Mitglied ist. + Membership.properties.startDate.description: Datum, an dem die Mitgliedschaft beginnt. + Membership.properties.endDate.description: Datum, an dem die Mitgliedschaft endet. + Membership.properties.onBehalfOf.description: "Die Gruppierung, für die die Person in der unter `organization` angegebenen Organisation sitzt. Beispiel: Mitgliedschaft als Vertreter einer Ratsfraktion, einer Gruppierung oder einer externen Organisation." + Meeting.description: | + Eine Sitzung ist die Versammlung einer oder mehrerer Gruppierungen (oparl:Organization) zu einem bestimmten Zeitpunkt an einem bestimmten Ort. + + Die geladenen Teilnehmer der Sitzung sind jeweils als Objekte vom Typ oparl:Person, die in entsprechender Form referenziert werden. Verschiedene Dateien (Einladung, Ergebnis- und Wortprotokoll, sonstige Anlagen) können referenziert werden. + Die Inhalte einer Sitzung werden durch Tagesordnungspunkte (oparl:AgendaItem) abgebildet. + Meeting.properties.name.description: Name der Sitzung. + Meeting.properties.meetingState.description: Aktueller Status der Sitzung. **Empfohlen** ist die Verwendung von `terminiert` (geplant), `eingeladen` (vor der Sitzung bis zur Freigabe des Protokolls) und `durchgeführt` (nach Freigabe des Protokolls). + Meeting.properties.cancelled.description: Wenn die Sitzung ausfällt, wird cancelled auf true gesetzt. + Meeting.properties.start.description: Datum und Uhrzeit des Anfangszeitpunkts der Sitzung. Bei einer zukünftigen Sitzung ist dies der geplante Zeitpunkt, bei einer stattgefundenen **kann** es der tatsächliche Startzeitpunkt sein. + Meeting.properties.end.description: Endzeitpunkt der Sitzung als Datum/Uhrzeit. Bei einer zukünftigen Sitzung ist dies der geplante Zeitpunkt, bei einer stattgefundenen **kann** es der tatsächliche Endzeitpunkt sein. + Meeting.properties.location.description: Sitzungsort. + Meeting.properties.organization.description: Gruppierungen, denen die Sitzung zugeordnet ist. Im Regelfall wird hier eine Gruppierung verknüpft sein, es kann jedoch auch gemeinsame Sitzungen mehrerer Gruppierungen geben. Das erste Element **sollte** dann das federführende Gremium sein. + Meeting.properties.participant.description: Personen, die an der Sitzung teilgenommen haben (d.h. nicht nur die eingeladenen Personen, sondern die tatsächlich anwesenden). Diese Eigenschaft kann selbstverständlich erst nach dem Stattfinden der Sitzung vorkommen. + Meeting.properties.invitation.description: Einladungsdokument zur Sitzung. + Meeting.properties.resultsProtocol.description: Ergebnisprotokoll zur Sitzung. Diese Eigenschaft kann selbstverständlich erst nachdem Stattfinden der Sitzung vorkommen. + Meeting.properties.verbatimProtocol.description: Wortprotokoll zur Sitzung. Diese Eigenschaft kann selbstverständlich erst nach dem Stattfinden der Sitzung vorkommen. + Meeting.properties.auxiliaryFile.description: Dateianhang zur Sitzung. Hiermit sind Dateien gemeint, die üblicherweise mit der Einladung zu einer Sitzung verteilt werden, und die nicht bereits über einzelne Tagesordnungspunkte referenziert sind. + Meeting.properties.agendaItem.description: Tagesordnungspunkte der Sitzung. Die Reihenfolge ist relevant. Es kann Sitzungen ohne TOPs geben. + System.description: | + Ein `oparl:System`-Objekt repräsentiert eine OParl-Schnittstelle für eine bestimmte OParl-Version. Es ist außerdem der Startpunkt für Clients beim Zugriff auf einen Server. + + Möchte ein Server mehrere zueinander inkompatible OParl-Versionen unterstützen, dann **muss** der Server für jede Version eine eigenen OParl-Schnittstelle mit einem eigenen `System`-Objekt ausgeben. + System.properties.oparlVersion.description: "Die URL der OParl-Spezifikation, die von diesem Server unterstützt wird. Aktuell kommt hier nur ein Wert in Frage. Mit zukünftigen OParl-Versionen kommen weitere mögliche URLs hinzu. Wert: `https://schema.oparl.org/1.1/`" + System.properties.otherOparlVersions.description: Dient der Angabe von System-Objekten mit anderen OParl-Versionen. + System.properties.license.description: Lizenz, unter der durch diese API abrufbaren Daten stehen, sofern nicht am einzelnen Objekt anders angegeben. Siehe [`license`](#eigenschaft_license). + System.properties.body.description: Link zur [Objektliste](#objektlisten) mit allen Körperschaften, die auf dem System existieren. + System.properties.name.description: Nutzerfreundlicher Name für das System, mit dessen Hilfe Nutzerinnen und Nutzer das System erkennen und von anderen unterscheiden können. + System.properties.contactEmail.description: E-Mail-Adresse für Anfragen zur OParl-API. Die Angabe einer E-Mail-Adresse dient sowohl NutzerInnen wie auch Entwicklerinnen von Clients zur Kontaktaufnahme mit dem Betreiber. + System.properties.contactName.description: Name der Ansprechpartnerin bzw. des Ansprechpartners oder der Abteilung, die über die in `contactEmail` angegebene Adresse erreicht werden kann. + System.properties.website.description: URL der Website des parlamentarischen Informationssystems + System.properties.vendor.description: URL der Website des Softwareanbieters, von dem die OParl-Server-Software stammt. + System.properties.product.description: URL zu Informationen über die auf dem System genutzte OParl-Server-Software + Paper.description: | + Dieser Objekttyp dient der Abbildung von Drucksachen in der parlamentarischen Arbeit, wie zum Beispiel Anfragen, Anträgen und Beschlussvorlagen. + Drucksachen werden in Form einer Beratung (oparl:Consultation) im Rahmen eines Tagesordnungspunkts (oparl:AgendaItem) einer Sitzung (oparl:Meeting) behandelt. + + Drucksachen spielen in der schriftlichen wie mündlichen Kommunikation eine besondere Rolle, da in vielen Texten auf bestimmte Drucksachen Bezug genommen wird. Hierbei kommen in parlamentarischen Informationssystemen in der Regel unveränderliche Kennungen der Drucksachen zum Einsatz. + Paper.properties.body.description: Körperschaft, zu der die Drucksache gehört. + Paper.properties.name.description: Titel der Drucksache. + Paper.properties.reference.description: Kennung bzw. Aktenzeichen der Drucksache, mit der sie in der parlamentarischen Arbeit eindeutig referenziert werden kann. + Paper.properties.date.description: Datum, welches als Startpunkt für Fristen u.ä. verwendet ist. + Paper.properties.paperType.description: Art der Drucksache, z. B. Beantwortung einer Anfrage. + Paper.properties.relatedPaper.description: Inhaltlich verwandte Drucksachen. + Paper.properties.superordinatedPaper.description: Übergeordnete Drucksachen. + Paper.properties.subordinatedPaper.description: Untergeordnete Drucksachen. + Paper.properties.mainFile.description: "Die Hauptdatei zu dieser Drucksache. Beispiel: Die Drucksache repräsentiert eine Beschlussvorlage und die Hauptdatei enthält den Text der Beschlussvorlage. Sollte keine eindeutige Hauptdatei vorhanden sein, wird diese Eigenschaft nicht ausgegeben." + Paper.properties.auxiliaryFile.description: Alle weiteren Dateien zur Drucksache ausgenommen der gegebenenfalls in `mainFile` angegebenen. + Paper.properties.location.description: Sofern die Drucksache einen inhaltlichen Ortsbezug hat, beschreibt diese Eigenschaft den Ort in Textform und/oder in Form von Geodaten. + Paper.properties.originatorPerson.description: Urheber der Drucksache, falls der Urheber eine Person ist. Es können auch mehrere Personen angegeben werden. + Paper.properties.underDirectionOf.description: Federführung. Amt oder Abteilung, für die Inhalte oder Beantwortung der Drucksache verantwortlich. + Paper.properties.originatorOrganization.description: Urheber der Drucksache, falls der Urheber eine Gruppierung ist. Es können auch mehrere Gruppierungen angegeben werden. + Paper.properties.consultation.description: Beratungen der Drucksache. diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/json_schema2markdown.py b/scripts/json_schema2markdown.py index da910df..3ab9ec1 100644 --- a/scripts/json_schema2markdown.py +++ b/scripts/json_schema2markdown.py @@ -7,12 +7,7 @@ import glob import collections import argparse - -parser = argparse.ArgumentParser() -parser.add_argument("schema_folder") -parser.add_argument("examples_folder") -parser.add_argument("output_file") -args = parser.parse_args() +import yaml class OParl: # Default properties don't need a description @@ -26,6 +21,7 @@ class OParl: "keyword", "web" ] + objects = [ "System", "Body", @@ -94,7 +90,7 @@ def type_to_string(prop): return type -def schema_to_md_table(schema): +def schema_to_md_table(schema, examples_folder): # Formatting propspace = 30 typespace = 45 @@ -133,15 +129,16 @@ def schema_to_md_table(schema): # End of Table md += "-" * (propspace + typespace + descspace) + "\n\n" - md += json_examples_to_md(schema["title"]) + md += json_examples_to_md(examples_folder, schema["title"]) return md -def json_examples_to_md(name): +def json_examples_to_md(examples_folder, name): md = "" - filepath = os.path.join(args.examples_folder, name) + filepath = os.path.join(examples_folder, name) examples = glob.glob(filepath + "-[0-9][0-9].json") for nr, examplepath in enumerate(examples): + # TODO: localize examples if len(examples) == 1: md += "**Beispiel**\n\n" else: @@ -156,20 +153,55 @@ def json_examples_to_md(name): return md -def main(): - generated_schema = "" +def localize_schema(language, translations_file, schema_file): + """ + Replaces the handlebars/django style templates in the schema files with the translations stored in + `translations_file`. The keys used the templates resemble JSONPath + """ + schema = schema_file.read() + with open(translations_file) as f: + translations = yaml.load(f)["de"] + + for key in translations.keys(): + pattern = "{{ " + key + " }}" # Avoid mixing python's and our own template language + if schema.find(pattern): + translation = json.dumps(translations[key], ensure_ascii=False)[1:-1] + schema = schema.replace(pattern, translation) + + return json.loads(schema, object_pairs_hook=collections.OrderedDict) + +def schema_to_markdown(schema_folder, examples_folder, output_file, language, language_file): # Avoid missing objects - assert(len(OParl.objects) == len(os.listdir(args.schema_folder))) + # NOTE: the schema folder contains all schema files and the translations strings file + assert(len(OParl.objects) == len(os.listdir(schema_folder)) - 1) + + generated_schema = "" for obj in OParl.objects: - filepath = os.path.join(args.schema_folder, obj + ".json") - print("Processing " + filepath) - schema = schema_to_md_table(json.load(open(filepath, encoding='utf-8'), object_pairs_hook=collections.OrderedDict)) + filepath = os.path.join(schema_folder, obj + ".json") + + with open(filepath, encoding='utf-8') as file_handle: + schema_json = localize_schema(language, language_file, file_handle) + + schema = schema_to_md_table(schema_json, examples_folder) + generated_schema += schema - with open(args.output_file, "w", encoding='utf-8') as out: + with open(output_file, "w", encoding='utf-8') as out: out.write(generated_schema) if __name__ == "__main__": - main() + parser = argparse.ArgumentParser() + + parser.add_argument("schema_folder") + parser.add_argument("examples_folder") + parser.add_argument("output_file") + parser.add_argument("language") + parser.add_argument("language_file") + + args = parser.parse_args() + + schema_to_markdown(args.schema_folder, args.examples_folder, args.output_file, args.language, args.language_file) + + diff --git a/src/2-03-urls.md b/src/2-03-urls.md index 2035a1d..5a033a6 100644 --- a/src/2-03-urls.md +++ b/src/2-03-urls.md @@ -1,6 +1,6 @@ ## URLs {#urls} -![Aufbau einer URL](src/images/url.png) +![Aufbau einer URL](build/src/images/url.png) Den URLs (für _Uniform Resource Locators_) kommt eine besondere Bedeutung zu und es werden deshalb eine Reihe von Anforderungen an deren Aufbau und diff --git a/src/3-00-schema.md b/src/3-00-schema.md index ca62e44..f49ae53 100644 --- a/src/3-00-schema.md +++ b/src/3-00-schema.md @@ -5,7 +5,7 @@ die Objekttypen und ihre Eigenschaften. Darüber hinaus ist im Schema auch festgelegt, in welcher Beziehung verschiedene Objekttypen zu einander stehen. -![OParl Objekttypen: Ein Überblick. Die Zahl an den Verbindungslinien entspricht der Anzahl der Attribute, die eine oder mehrere Verknüpfungen herstellen.](src/images/objekttypen_graph.png) +![OParl Objekttypen: Ein Überblick. Die Zahl an den Verbindungslinien entspricht der Anzahl der Attribute, die eine oder mehrere Verknüpfungen herstellen.](build/src/images/objekttypen_graph.png) ## Die Objekte {#objekttypen}