This commit is contained in:
Wolfram 2025-02-08 14:01:17 +01:00
parent 21a88d4507
commit f0183bbfbe
11 changed files with 462 additions and 469 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
__pycache__ __pycache__
output/* output/*
dev.py dev*.py
maschinenliste-*.csv

View File

@ -1,4 +0,0 @@
2024.6
- **Diagrammerzeugung**
- Das Diagramm enthält jetzt eine Icon-Legende
- Unterschiedliche Icons für Administrator und Manager, um die Unterscheidung zu erleichtern.

View File

@ -1,7 +1,5 @@
MIT License MIT License
Copyright (c) 2024 Wolfram Günther
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights

View File

@ -1,256 +0,0 @@
# fabaccess-config-generator <!-- omit from toc -->
Automatische Generierung von Maschinen, Rollen, Aktoren und Aktor-Verbindungen auf Basis einer Maschinenliste im CSV-Format.
- [Funktionsumfang](#funktionsumfang)
- [Funktionsweise](#funktionsweise)
- [Bereichskonzept](#bereichskonzept)
- [Rollenkonzept \& Berechtigungen](#rollenkonzept--berechtigungen)
- [Beispielwerkstatt](#beispielwerkstatt)
- [Auszug aus der CSV](#auszug-aus-der-csv)
- [Werkstattdiagramm](#werkstattdiagramm)
- [Erklärung der Konfiguration](#erklärung-der-konfiguration)
- [Nutzung des Python-Skripts](#nutzung-des-python-skripts)
- [Anlegen von Maschinen (maschinenliste.csv)](#anlegen-von-maschinen-maschinenlistecsv)
- [Einstellungen des Skripts (settings.ini)](#einstellungen-des-skripts-settingsini)
- [Aktorenbibliothek (actors.ini)](#aktorenbibliothek-actorsini)
- [Beispiel für die Erstellung eines Aktor-Typs](#beispiel-für-die-erstellung-eines-aktor-typs)
- [Verschiedene Informationen](#verschiedene-informationen)
- [ID-Schema für Rollen, Maschinen und Aktoren](#id-schema-für-rollen-maschinen-und-aktoren)
- [Ausnahme: Alternativrollen](#ausnahme-alternativrollen)
- [Aktualisierung einer bestehenden bffh.dhall](#aktualisierung-einer-bestehenden-bffhdhall)
# Funktionsumfang
- Generierung von Maschinen
- Generierung von Rollen
- Generierung von Aktoren
- Generierung von einfachen Aktoren-Verbindungen
- Export einer gesonderten Rollenliste (interne ID & Anzeigename der Rolle)
- Abbildung der Struktur mittels Mermaid-Diagramm
- Direkte Aktualisierung einer bestehenden `bffh.dhall`
# Funktionsweise
Die CSV-Zeile enthält pro Zeile einen Eintrag für eine Maschine. Neben Angaben zur Maschine selbst (ID, Wiki-URL etc.) werden Angaben zum Bereich vermerkt, in dem sich die Maschine befindet. Aus den Angaben zu den Bereichen werden dann alle Rollen abgeleitet.
## Bereichskonzept
Innerhalb der globalen Infrastruktur existieren die folgenden Einheit:
- **Domäne**: Fasst die gesamte Werkstatt zusammen und unterteilt sich in mehrere Bereiche (=Gewerke). Bei Bedarf können auch mehrere Domänen definiert werden.
- **Bereich**: Entspricht üblicherweise einem Gewerk (z.B. Holzwerkstatt, Siebdruck), aber kann auch genutzt werden, um andere Maschinen zu gruppieren (z.B. Eingangstüren). Ein Bereich kann bei Bedarf über Unterbereiche verfügen.
- **Unterbereich**: Ein Unterbereich ermöglicht einzelne Maschinen/ Maschinengruppen separat zu behandeln.
## Rollenkonzept & Berechtigungen
| Rolle | Berechtigungen | Infrastruktur | Domäne | Bereich | Unterbereich | Spezifische Maschinen |
| --------------- | ---------------------------------------------------------------------- | ------------- | -------- | ------- | ------------ | --------------------- |
| Administrator | - *bffh.users.manage*<br> - *bffh.users.info*<br> - *bffh.users.admin* | Ja | - | - | - | - |
| Manager | - *read*<br> - *write*<br> - *disclose*<br> - *manage* | - | Optional | Ja | Optional | - |
| Benutzer | - *read*<br> - *write*<br> - *disclose* | - | - | Ja | Ja | - |
| Alternativrolle | - *read*<br> - *write*<br> - *disclose* | - | - | - | - | Ja |
- Berechtigungen werden grundsätzlich via Wildcard vergeben und gelten somit für eine gesamte Einheit (Infrastruktur/ Domäne/ Bereich/ Unterbereich).
- Berechtigungen für Bereich und Unterbereich sind getrennt. Benutzer eines Bereichs haben keinen Zugriff auf Maschinen eines Unterbereichs (und umgekehrt).
- **Ausnahme: Alternativrolle**
- Die Alternativrolle dient der Erstellung einer bereichsübergreifenden Berechtigung für einzelne Maschine. Diese wird vergeben, wenn in mehreren Bereichen die gleiche (bzw. eine ähnliche) Maschinen existieren und dafür nur eine Einweisung notwendig ist.
## Beispielwerkstatt
Die CSV-Datei `beispielwerkstatt.csv` und das Diagramm `beispielwerkstatt.svg` befinden sich im Unterordner `docs`.
### Auszug aus der CSV
| Name Domäne | Name Bereich | Name Unterbereich | Name Maschine | Manager Unterbereich | Name Alternativrolle |
| ----------------- | --------------- | ----------------- | ------------------- | -------------------- | -------------------- |
| Beispielwerkstatt | Holzwerkstatt | Bandsäge | Bandsäge | | |
| Beispielwerkstatt | Holzwerkstatt | Hobelmaschine | Hobelmaschine | | |
| Beispielwerkstatt | Holzwerkstatt | CNC-Fräse | CNC-Fräse | | |
| Beispielwerkstatt | Holzwerkstatt | | Kappsäge | | |
| Beispielwerkstatt | Holzwerkstatt | | Bandschleifer | | |
| Beispielwerkstatt | Holzwerkstatt | | Ständerbohrmaschine | | |
| Beispielwerkstatt | Textilwerkstatt | | Nähmaschine 1 | | |
| Beispielwerkstatt | Textilwerkstatt | | Nähmaschine 2 | | |
| Beispielwerkstatt | FabLab | 3D-Druck | 3D-Drucker 1 | x | |
| Beispielwerkstatt | FabLab | 3D-Druck | 3D-Drucker 2 | x | |
| Beispielwerkstatt | FabLab | Laser | Lasercutter | x | |
| Beispielwerkstatt | FabLab | Laser | Kühlung | x | |
| Beispielwerkstatt | Siebdruck | | SD-Belichter | | |
| Beispielwerkstatt | Siebdruck | | A3-Drucker | | Druckernutzung |
| Beispielwerkstatt | Büro | | Drucker | | Druckernutzung |
### Werkstattdiagramm
![Beispiel für eine Werkstattstruktur](docs/beispielwerkstatt.svg)
### Erklärung der Konfiguration
- **Textilwerkstatt**
- In der Textilwerkstatt verwaltet eine Person den gesamten Bereich.
- Eine Einweisung deckte alle Maschinen ab, daher gibt es keine Unterbereiche.
- **Holzwerkstatt**
- In der Holzwerkstatt verwaltet eine Person den gesamten Bereich.
- Es gibt unterschiedliche Einweisungen:
- Holzwerkstatt Allgemein (Kappsäge, Bandschleifer, Ständerbohrmaschine)
- Bandsäge
- Hobelmaschine
- CNC-Fräse
- Bandsäge, Hobelmaschine, CNC-Fräse verfügen jeweils über einen eigenen Unterbereich, um für jede Maschine eine eigene Berechtigung vergeben zu können.
- **FabLab**
- Im FabLab sind mehrere Personen für die Verwaltung zuständig:
- Person A ist im Allgemenien für das FabLab zuständig. Hier gib es keine Maschinen, die von von FabAccess verwaltet werden.
- Person B ist für die 3D-Drucker zuständig.
- Person C ist für den Lasercutter inkl. Kühlung zuständig.
- Beide Maschinengruppen (3D-Drucker & Laser) sind in einem eigenen Unterbereich, um eine eigene Berechtigung vergeben zu können.
- Beide Unterbereiche verfügen über einen Unterbereich-Manager, damit Person A und B ihren jeweiligen Bereich verwalten können.
- **Siebdruck & Büro**
- Es gibt eine allgemeine Drucker-Einweisung, die zur Nutzung aller Drucker in beiden Bereichen berechtigt. Die Drucker der beiden Bereiche sind mit der Alternativrolle _Druckernutzung_ verknüpft.
# Nutzung des Python-Skripts
- Eingelesen wird die Datei `maschinenliste.csv` [^1]
- Die Spaltennamen dienen der Zuordnung und dürfen nicht umbenannt werden.
- Die Reihenfolge der Spalten kann nach Belieben verändert werden.
- Zentrale Einstellungen können in der `settings.ini` vorgenommen werden,
- Aktor-Typen können in der `actors.ini` definiert
- Erzeugte Daten werden im Unterordner `output` gespeichert.
[^1]: Die Datei muss in der Enkodierung UTF-8 (ohne BOM) vorliegen.
## Anlegen von Maschinen (maschinenliste.csv)
- Verwendetes Trennzeichen: `;`
- IDs können Buchstaben und Zahlen enthalten.
- Alle Großbuchstaben werden automatisch in Kleinbuchstaben umgewandelt.
- Deutsche Sonderzeichen werden automatisch umgewandelt (ä = ae, ö = oe, ü = ue, ß = ss).
- Alle übrigen Zeichen werden automatisch entfernt.
| Feld | Info | Pflichtfeld |
| ------------------------ | --------------------------------------------------------------------- | ----------- |
| **ID Domäne** | Eindeutige ID einer Domäne. | Ja |
| **ID Bereich** | Eindeutige ID eines Bereichs. | Ja |
| **ID Unterbereich** | Eindeutige ID eines Unterbereichs. | - |
| **ID Maschine** | Eindeutige ID der Maschine. | Ja |
| **Unterbereich Manager** | Erstellung einer Manager-Rolle für den dazugehörigen Unterbereich | - |
| **Name Bereich** | Anzeigename des Bereichs. | Ja |
| **Name Unterbereich** | Anzeigename des Unterbereichs. | - |
| **Name Maschine** | Anzeigename der Maschine. | Ja |
| **Maschinbeschreibung** | Feld `description` einer Maschine in FabAccess. | - |
| **Wiki-URL** | Feld `wiki` einer Maschine in FabAccess. | - |
| **Aktor ID** | Eindeutige ID eines Aktors. | - |
| **Aktor Typ** | Definiert den Aktorentyp, der aus der Aktorenbibliothek geladen wird. | - |
| **ID Alternativrolle** | Eindeutige ID einer alternativen Rolle. | - |
| **Name Alternativrolle** | Anzeigename einer alterantiven Rolle. | - |
| **Anmerkungen** | Zusatzfeld für Anmerkungen, wird nicht verarbeitet. | - |
Hinweis zum Feld `Unterbereich Manager`:
- Für die Erstellung der Rolle muss eni Unterbereich definiert sein.
- Das Feld wird aktiv sobald ein beliebiger Inhalt eingetragen wird.
- Das Feld muss nur für eine Maschine des Unterbereichs ausgefüllt werden.
## Einstellungen des Skripts (settings.ini)
| Einstellung | Info |
| -------------------------- | -------------------------------------------------------------------------------------------------------------- |
| **multi_domains** | Verwendung mehrer Domänen. Es wird dann automatisch eine Manager-Rolle für jede Domäne erstellt. |
| **manager_schichtleitung** | Rolle "Schichtleitung" erstellen, die über Manager-Berechtigungen für alle Domänen verfügt. |
| **manager_area** | Manager-Rolle für jeden Bereich erstellen. |
| **manager_subarea** | Spalte "Unterbereich Manager" der CSV beachten (True) oder nicht (False). |
| **fa_update_dhall** | Automatische Aktualisierung einer bestehenden `bffh.dhall`. |
| **fa_dhall_file** | Pfad zur bffh.dall. |
| **generate_mermaid** | Mermaid-Code erzeugen, der Bereiche und Rolle in einem Diagramm abbildet. [^2] |
| **create_file_roles** | Erstellung einer gesonderten CSV-Datei, die jede Rollen-ID und den dazugehörigen Rollen-Name beinhaltet. |
| **show_machines** | Alle importierten Maschinen-Daten anzeigen. |
| **show_roles** | Alle erzeugten Rollen-Daten anzeigen. |
| **string_adminhandle** | Kennzeichnung von Administrator-Rollen im Anzeigename. Der String wird dem Namen der Rolle vorangestellt. [^3] |
| **string_managerhandle** | Kennzeichnung für Manager-Rollen, steht am Anfang des Namens der Rolle. [^3] |
| **string_userhandle** | Kennzeichnung von Benutzer-Rollen im Anzeigename. Der String wird dem Namen der Rolle vorangestellt. [^3] |
[^2]: Ausgabe erfolgt in die Datei `mermaid-code.txt`. Der enthaltene Code kann auf [mermaid.live](https://mermaid.live/) eingefügt werden, um das Diagramm als Grafik zu speichern.
[^3]: Der Anzeigename wird aktuell nur im Diagramm verwendet.
## Aktorenbibliothek (actors.ini)
In der Aktorenbibliothek können Vorlagen für Aktor-Typen angelegt werden. Ein bestimmter Aktor muss somit nur einmal angelegt werden und kann in der `maschinenliste.csv` angegeben werden.
Ein Aktor-Typ besteht immer aus:
- Titel des Aktors. Dieser wird in eckigen Klammern angegeben und definiert den Aktor.
- Angabe zum Feld `module` von FabAccess.
Darüber hinaus können beliebig viele eigene Parameter übergeben werden. Diese müssen mit Präfix `param_` als Parameter gekennzeichnet sein.
### Beispiel für die Erstellung eines Aktor-Typs
Angelegt wird der Aktor *shellyplus*. Für diesen wird anschließend in der `maschinenliste.csv` eine Maschine mit der Aktor-ID *test12345* angelegt.
> Groß- und Kleinschreibung spielt für die Datenverarbeitung keine Rolle. Sowohl der Aktor-Name als auch alle Parameter werden automatisch in Kleinbuchstaben umgewandelt.
<br/>
Aktor-Definition in der actors.ini
```
[shellyplus]
module = "MqttSwitch"
param_topic = "shellyplus1pm-$actor_id/rpc",
param_onMsg = "{\"id\": 1, \"src\": \"bffh\", \"method\": \"Switch.Set\", \"params\": {\"id\": 0, \"on\": true}"
param_offMsg= "{\"id\": 1, \"src\": \"bffh\", \"method\": \"Switch.Set\", \"params\": {\"id\": 0, \"on\": false}"
```
<br/>
Fertiger Aktor in der `bffh.dhall`:
```
shellyplus_test12345 =
{
module = ""MqttSwitch"",
params =
{
topic = "shellyplus1pm-bbbb/rpc",,
onmsg = "{\"id\": 1, \"src\": \"bffh\", \"method\": \"Switch.Set\", \"params\": {\"id\": 0, \"on\": true}",
offmsg = "{\"id\": 1, \"src\": \"bffh\", \"method\": \"Switch.Set\", \"params\": {\"id\": 0, \"on\": false}",
}
},
```
# Verschiedene Informationen
## ID-Schema für Rollen, Maschinen und Aktoren
| ID | Schema |
| ------------ | --------------------------------------------------------- |
| **Rolle** | domäne.bereich.bereich.rollentyp bzw. domäne.unterbereich.rollentyp |
| **Maschine** | domäne-bereich-bereich-maschinen bzw. domäne-unterbereich-maschinen |
| **Aktor** | aktortyp_aktorid |
**Auszug aus der Beispielwerkstatt: Unterbereich FabLab Laser**
- Rolle "*Manager FabLab Laser*": beispielw_fablab_laser_manager
- Rolle "*Benutzer FabLab Laser*": beispielw_fablab_laser_user
- Maschinen-IDs:
- Maschine "*Lasercutter*": beispielw-fablab-laser-laser3000
- Maschine "*Kühlung*": beispielw-fablab-laser-kuehlung3000
### Ausnahme: Alternativrollen
Bei einer Alternativrolle weicht die Rollen-ID von der Maschinen-ID ab, da es sich um eine bereichsübergreifende Rolle handelt. Die Rollen-ID beinhaltet keine Bereichszuordnung. Die Maschinen-ID beinhaltet nach wie vor eine Bereichszuordnung, um die Maschine eindeutig in der Werkstatt verorten zu können.
**Auszug aus der Beispielwerkstatt: Alternative Rolle für Druckernutzung**
- Rolle "*Benutzer Druckerbenutzung*": beispielw_drucker
- Maschinen-IDs:
- beispielw-siebdruck-a3drucker
- beispielw-buero-drucker
## Aktualisierung einer bestehenden bffh.dhall
Eine bestehende `bffh.dhall` kann auf Wunsch automatisch aktualisiert werden. Dabei wird der Inhalt der bestehenden `bffh.dhall` eingelesen und die vom Config-Generator erzeugten Daten an einer vordefinierten Stelle eingesetzt.
**Einstellungen in der settings.ini setzen**
Hierfür müssen in der `settings.ini` die folgenden Einstellungen gesetzt sein:
- `fa_update_dhall`auf `True`
- `fa_dhall_file` muss die Pfandangabe zur bffh.dhall enthalten
**bffh.dhall vorbereiten**
1. Bestehende Datenstrukturen löschen:
- roles
- maschines
- actors
- actor_connections
2. Die folgenden Zeilen einfügen.
- `-- ||| GENERATOR START`
- ` -- ||| GENERATOR END`
Das Skript fügt die erzeugten Daten automatisch zwischen beiden Platzhaltern ein. Bestehender Inhalt zwischen den Platzhaltern wird dabei überschrieben.
> &nbsp;
> **Hinweis**
> Ein Vorlage für eine entsprechend angepasste `bffh.dhall` befindet sich im Unterordner `docs`
> &nbsp;

View File

@ -1,13 +1,46 @@
# fabaccess-config-generator # fabaccess-config-generator
Automatische Generierung von Maschinen, Rollen, Aktoren und Aktor-Verbindungen auf Basis einer Maschinenliste im CSV-Format. Automatische Generierung von Maschinen, Rollen, Aktoren und Aktor-Verbindungen auf Basis einer Maschinenliste im CSV-Format.
# Funktionsumfang ## Funktionsumfang
- Generierung von Maschinen - Generierung von Maschinen
- Generierung von Rollen - Generierung von Rollen
- Generierung von Aktoren - Generierung von Aktoren
- Generierung von einfachen Aktoren-Verbindungen - Generierung von einfachen Aktoren-Verbindungen
- Export einer gesonderten Rollenliste (interne ID & Anzeigename der Rolle) - Export einer gesonderten Rollenliste (interne ID & Anzeigename der Rolle)
- Abbildung der Struktur mittels Mermaid-Diagramm - Abbildung der Struktur mittels Mermaid-Diagramm
- Direkte Aktualisierung einer bestehenden `bffh.dhall`
Dokumentation unter [https://elem74.github.io/fabaccess-config-generator-docs/](https://elem74.github.io/fabaccess-config-generator-docs/). Dokumentation unter [https://elem74.github.io/fabaccess-config-generator-docs/](https://elem74.github.io/fabaccess-config-generator-docs/).
# Changelog
## 2025.2
**Neuerungen**
- Option zur Erstellung eines Domänen-Managers (`manager_domain`).
- Option zur Erstellung eines werkstattweiten Benutzers. (`domain_user`)
- Kommandozeilen-Parameter, um die CSV-Datei mit der Maschinenliste zu definieren.
- Der verwende CSV-Delimiter wird automatisch erkannt.
- Die erzeugte Konfiguration wird in einzelnen dhall-Dateien abgelegt, die beim Start von FabAccess nachgeladen werden. Hierfür muss die `bffh.dhall` einmalig angepasst werden.
- Die FabAccess-Konfiguration in der `bffh.dhall` wird nicht mehr berührt.
- Kompatibilität mit dem offiziellen dhall-Parser (Ddie bisherigen Platzhalter zum Aktualisieren der `bffh.dhall` bleiben bei Nutzung des Parsers nicht erhalten).
**Bugfixes**
- Crash bei Verwendung der Einstellung `show_machines` behoben.
- Korrektur der erzeugten dhall-Syntax. Der letzte Eintrag einer Datenstruktur wird nicht mehr mit einem Komma abgeschlossen.
**Sonstiges**
- Die erzeugten DHALL-Dateien werden standardgemäß auch im Unterordner `/output` abgelegt.
- Admin-Berechtigungen wurden vollständig auf Wildcard-Zugriffsschema umgestellt. Zuvor wurden Berechtigungen für einzelne Bereiche vergeben.
- Schönere Darstellung der Statusinformationen, wenn das Python-Modul `rich` installiert ist.
**Änderungen in der settings.ini**
- Neue Einstellung `fa_dhall_directory`.
- Die Einstellung `manager_schichtleitung ` entfällt (wird ersetzt von `manager_domain`).
- Die Einstellung `create_file_roles` entfällt. Eine CSV-Datei mit allen Rollennamen und deren FabAcess-IDs wird jetzt standardgemäß erzeugt.
- Die Einstellung `generate_mermaid` entfällt. Eine Textdatei mit Mermaid-Code für ein Werkstattdiagramm wird jetzt standardgemäß erzeugt.
- Die Einstellungen `fa_update_dhall` und `fa_dhall_file` entfallen.
## 2024.6
**Diagrammerzeugung**
- Das Diagramm enthält jetzt eine Icon-Legende.
- Unterschiedliche Icons für Administrator und Manager, um die Unterscheidung zu erleichtern.

View File

@ -1,5 +1,7 @@
__version__ = '2024.6' __version__ = '2025.2'
import os
import sys
import time import time
time_start = time.perf_counter() time_start = time.perf_counter()
@ -7,21 +9,32 @@ from pathlib import Path
from generator.core import * from generator.core import *
from generator.helpers import * from generator.helpers import *
app_path = os.path.dirname(os.path.realpath(__file__))
input_file = 'maschinenliste.csv' input_file = 'maschinenliste.csv'
# CLI Parameter
if len(sys.argv) > 0:
for arg in sys.argv:
if 'file=' in arg:
input_file = arg.replace('file=', '')
# Output-Ordner anlegen # Output-Ordner anlegen
print('Erzeuge Konfiguration\n|')
directory = "output" directory = "output"
path = Path(directory) path = Path(directory)
path.mkdir(parents=True, exist_ok=True) path.mkdir(parents=True, exist_ok=True)
print(f' --- Datei = {input_file}') print(f'|- Datei = {input_file}')
# Maschinenliste einlesen # Maschinenliste einlesen
print(' --- Maschinen importieren:')
machines = import_machines(input_file) machines = import_machines(input_file)
# Rollen für FabAccess erzeugen # Rollen für FabAccess erzeugen
print(' --- Rollen erzeugen')
roles = generate_roles(machines) roles = generate_roles(machines)
# Finale DHALL-Daten erzeugen # Finale DHALL-Daten erzeugen
@ -32,50 +45,22 @@ export_actorconnections = generate_bffh_actorconnections(machines)
export_all = export_roles + export_machines + export_actors + export_actorconnections export_all = export_roles + export_machines + export_actors + export_actorconnections
# Anzeigen der erzeugten Daten # ------- Daten exportieren
if settings["show_machines"] == True:
for m in machines:
display_machine(m)
if settings["show_roles"] == True: # Textdatei mit komplettem dhall-Inhalt
print_dict(roles) create_singledhall(export_roles, export_machines, export_actors, export_actorconnections)
# Daten exportieren # Rollenliste als CSV
print(' --- DHALL-Daten exportieren') create_roles_csv(roles)
write_file('output/bffh-dhall-data.txt', export_all)
if settings["create_file_roles"] == True: # Einzelne DHALLs
print(' --- Rollen exportieren in roles.csv') create_multipledhalls(export_roles, export_machines, export_actors, export_actorconnections)
content = generate_csv_roles(roles)
write_file('output/roles.csv', content)
if settings["fa_update_dhall"] == True:
print(' --- Aktualisierung der bffh.dhall')
fa_dhall_file = settings["fa_dhall_file"]
# Pfadangabe "fa_dhall_file" hat Inhalt
if len(fa_dhall_file) > 0:
# Daten schreiben
dhall_content = generate_bffh_dhall(export_all)
if len(dhall_content) > 0:
write_file(fa_dhall_file, dhall_content)
# Pfadangabe "fa_dhall_file" ist leer
else:
print('Einstellung "fa_dhall_file" ist leer, es wurde kein Pfad zur bffh.dhall angegeben.')
print('Bitte das Feld ausfüllen oder "fa_update_dhall" auf "False" setzen.')
# Mermaid-Code # Mermaid-Code
if settings["generate_mermaid"] == True: create_mermaid(machines)
print(' --- Mermaid-Code erzeugen')
graphelements = graph_create_elements(machines)
mermaidcode = graph_create_mermaidcode(graphelements)
write_file('output/mermaid-code.txt', mermaidcode)
# ------------------------------------------------------------------ # ----------------------
time_end = time.perf_counter() time_end = time.perf_counter()
time_span = round(time_end - time_start, 2) time_span = round(time_end - time_start, 2)
print('-------------------------') print('---------')
print(f'Laufzeit: {time_span} Sekunden') print(f'Laufzeit: {time_span} Sekunden')

View File

@ -44,8 +44,10 @@
auditlog_path = "/tmp/bffh.audit", auditlog_path = "/tmp/bffh.audit",
-- ||| GENERATOR START roles = ./roles.dhall,
-- ||| GENERATOR END machines = ./machines.dhall,
actors = ./actors.dhall,
actor_connections = ./actorconnections.dhall,
-- Initiators are configured almost the same way as Actors, refer to actor documentation for more details -- Initiators are configured almost the same way as Actors, refer to actor documentation for more details

View File

@ -3,6 +3,27 @@ from string import Template
from generator.globals import * from generator.globals import *
from generator.helpers import * from generator.helpers import *
# Rich-Module
try:
from rich.table import Table
from rich.console import Console
from rich.text import Text
module_rich = True
except ImportError:
module_rich = False
# Settings-Dateien finden und laden
if os.path.isfile('settings.ini') == True:
settings = config_load('settings.ini', 'generator')
else:
settings = config_load('./settings.ini', 'generator')
if os.path.isfile('actors.ini') == True:
actor_library = load_actors('actors.ini')
else:
actor_library = load_actors('./actors.ini')
string_userhandle = settings["string_userhandle"] + ' ' string_userhandle = settings["string_userhandle"] + ' '
string_adminhandle = settings["string_adminhandle"] + ' ' string_adminhandle = settings["string_adminhandle"] + ' '
string_managerhandle = settings["string_managerhandle"] + ' ' string_managerhandle = settings["string_managerhandle"] + ' '
@ -15,8 +36,6 @@ class Domain:
perm_handle = domain_id + '.' perm_handle = domain_id + '.'
id_handle = perm_handle.replace('.', '_') id_handle = perm_handle.replace('.', '_')
perms_manager = [perm_handle + '*']
self.domain = { self.domain = {
"id": domain_id, "id": domain_id,
"name": domain_name "name": domain_name
@ -24,16 +43,29 @@ class Domain:
self.domain_manager = { self.domain_manager = {
"id": id_handle + 'manager', "id": id_handle + 'manager',
"name": string_managerhandle + domain_name, "name": '_' + string_managerhandle + domain_name,
"perms": perms_manager "perms": perm_handle + '*'
} }
self.domain_user = {
"id": id_handle + 'user',
"name": '_' + string_userhandle + domain_name,
"perms": []
}
def get_domain(self): def get_domain(self):
return self.domain return self.domain
def get_domain_perms(self):
return self.domain_manager["perms"]
def get_domain_manager(self): def get_domain_manager(self):
return self.domain_manager return self.domain_manager
def get_domain_user(self):
return self.domain_user
class Area(Domain): class Area(Domain):
def __init__(self, domain_id, domain_name, area_id, area_name): def __init__(self, domain_id, domain_name, area_id, area_name):
@ -273,12 +305,14 @@ class GraphElement:
# Maschinen aus der CSV-importieren # Maschinen aus der CSV-importieren
def import_machines(file): def import_machines(file):
print('|- Maschinen importieren:')
machines = {} machines = {}
data = csv_listdict(file, csv_match) data = csv_listdict(file, csv_match)
count = 2 count = 2
print(f'{"Zeile": ^8} | {"Status": ^24} | {"Zusatzinformation": ^20}')
print(f'{"1": ^8} | {"Kopfzeile": ^24} | {"Kopfzeile wird nicht verarbeitet.": ^20}') feedback = []
for entry in data: for entry in data:
@ -286,7 +320,6 @@ def import_machines(file):
errors = [] errors = []
# Pflichtfelder # Pflichtfelder
for el in importcheck["single"].keys(): for el in importcheck["single"].keys():
# Einzelfeld ist leer? # Einzelfeld ist leer?
@ -305,18 +338,34 @@ def import_machines(file):
field2_name = key field2_name = key
if len(entry[field1]) > 0 and len(entry[field2]) == 0: if len(entry[field1]) > 0 and len(entry[field2]) == 0:
errors.append(f'Optionales Felderpaar unvollständig: Feld "{field1_name}" ist ausgefüllt, aber Feld "{field2_name}" ist leer.') errors.append(f' |- Felderpaar unvollständig: Feld "{field1_name}" ist ausgefüllt, aber Feld "{field2_name}" ist leer.')
if len(entry[field2]) > 0 and len(entry[field1]) == 0: if len(entry[field2]) > 0 and len(entry[field1]) == 0:
errors.append(f'Optionales Felderpaar unvollständig: Feld "{field2_name}" ist ausgefüllt, aber Feld "{field1_name}" ist leer.') errors.append(f' |- Felderpaar unvollständig: Feld "{field2_name}" ist ausgefüllt, aber Feld "{field1_name}" ist leer.')
status = 'Eintrag übersprungen'
info = f'Fehlerhafte Konfiguration. ID = {entry["machine_id"]}'
if len(errors) > 0: if len(errors) > 0:
print(f'{count: ^8} | {status: ^24} | {info: ^20}')
feedback.append(
{
"count": str(count),
"status": 'Übersprungen',
"info": 'Konfigurationsfehler',
"details": f'ID: {entry["machine_id"]}',
}
)
for e in errors: for e in errors:
print(f'{"":>36}| ' + e) feedback.append(
{
"count": '',
"status": '',
"info": '',
"details": e,
}
)
count += 1 count += 1
continue continue
# Maschine anlegen # Maschine anlegen
@ -328,17 +377,74 @@ def import_machines(file):
f'{fa_id}': Machine(entry) f'{fa_id}': Machine(entry)
}) })
status = 'Maschine angelegt' feedback.append(
info = f'FA_ID = {fa_id}' {
"count": str(count),
"status": 'OK',
"info": 'Maschine angelegt',
"details": f'ID: {entry["machine_id"]}',
}
)
print(f'{count: ^8} | {status: ^24} | {info: ^20}')
else: else:
status = 'Eintrag übersprungen'
info = f'ID bereits vergeben. ID = {entry["machine_id"]}' feedback.append(
print(f'{count: ^8} | {status: ^24} | {info: ^20}') {
"count": str(count),
"status": 'Übersprungen',
"info": 'Doppelte Maschinen-ID',
"details": f'ID: {entry["machine_id"]}',
}
)
count += 1 count += 1
# rich-switch
if module_rich == True:
console = Console()
table = Table(highlight="pale_green3")
table.add_column("Zeile", justify="right")
table.add_column("Status")
table.add_column("Info")
table.add_column("Details")
status = Text('OK')
status.stylize("green")
table.add_row("1", status, "Kopfzeile", "Kopfzeile wird nicht verarbeitet.")
for f in feedback:
if 'OK' in f["status"]:
status = Text(f["status"])
status.stylize("green")
else:
if 'Übersprungen' in f["status"]:
status = Text(f["status"])
status.stylize("dark_orange")
else:
status = Text(f["status"])
table.add_row(f["count"], status, f["info"], f["details"])
console.print(table)
else:
print(f'{"Zeile": ^8} | {"Status": ^24} | {"Details": ^20}')
print(f'{"1": ^8} | {"Kopfzeile": ^24} | {"Kopfzeile wird nicht verarbeitet.": <20}')
for f in feedback:
print(f'{f["count"]: ^8} | {f["status"]: ^24} | {f["details"]: <20}')
# Datenanzeige
if settings["show_machines"] == True:
for m in machines.values():
display_machine(m)
return machines return machines
@ -347,6 +453,8 @@ def import_machines(file):
# Rollen erstellen # Rollen erstellen
def generate_roles(machines): def generate_roles(machines):
print('|- Rollen erzeugen')
roles = {} roles = {}
# Globalen Admin erstellen # Globalen Admin erstellen
@ -355,28 +463,28 @@ def generate_roles(machines):
if roledata["id"] not in roles.keys(): if roledata["id"] not in roles.keys():
roles[roledata["id"]] = roledata roles[roledata["id"]] = roledata
# Schichtleitung anlegen
if settings["manager_schichtleitung"] == True:
roledata = manager_schichtleitung
if roledata["id"] not in roles.keys():
roles[roledata["id"]] = roledata
# Domänen durchlaufen # Domänen durchlaufen
for id, m in machines.items(): for id, m in machines.items():
# Domänen-Berechtigung an Manager & Schichtleitung vergeben # Domänen-Berechtigung an Admin & Manager vergeben
roledata = m.get_domain_manager()
for perm in roledata["perms"]:
if perm not in roles[admin_global["id"]]["perms"]:
roles[admin_global["id"]]["perms"].append(perm)
if settings["manager_schichtleitung"] == True: # 2do: Admin - Überflüssige Berechtigungen?
for perm in roledata["perms"]: # for perm in roledata["perms"]:
if perm not in roles[manager_schichtleitung["id"]]["perms"]:
roles[manager_schichtleitung["id"]]["perms"].append(perm) # if perm not in roles[admin_global["id"]]["perms"]:
# roles[admin_global["id"]]["perms"].append(perm)
# 2do - end
perm = m.get_domain_perms()
if perm not in roles[admin_global["id"]]["perms"]:
roles[admin_global["id"]]["perms"].append(perm)
if settings["manager_domain"] == True:
if roledata["id"] not in roles.keys():
roles[roledata["id"]] = roledata
# Manager: Domain # Manager: Domain
if settings["multi_domains"] == True: if settings["multi_domains"] == True:
@ -385,6 +493,10 @@ def generate_roles(machines):
if roledata["id"] not in roles.keys(): if roledata["id"] not in roles.keys():
roles[roledata["id"]] = roledata roles[roledata["id"]] = roledata
for perm in roledata["perms"]:
if perm not in roles[manager_domain["id"]]["perms"]:
roles[manager_domain["id"]]["perms"].append(perm)
# Manager: Area # Manager: Area
if settings["manager_area"] == True: if settings["manager_area"] == True:
roledata = m.get_area_manager() roledata = m.get_area_manager()
@ -403,30 +515,53 @@ def generate_roles(machines):
# Benutzer: Daten abrufen # Benutzer: Daten abrufen
if m.has_customrole() == True: if settings["domain_user"] == True:
# Extrarolle # Domäne-Benutzer
roledata = m.get_customrole() roledata = m.get_domain_user()
if roledata["id"] in roles.keys():
# Extrarolle vorhanden --> Berechtigungen hinzufügen
for p in roledata["perms"]:
roles[roledata["id"]]["perms"].append(p)
else: else:
# Kein Domäne-Benutzer
if m.has_customrole() == True:
# Extrarolle
roledata = m.get_customrole()
if roledata["id"] in roles.keys():
# Extrarolle vorhanden --> Berechtigungen hinzufügen
for p in roledata["perms"]:
roles[roledata["id"]]["perms"].append(p)
if m.has_subarea() == True:
# Unterbereich
roledata = m.get_subarea_user()
else: else:
# Bereich
roledata = m.get_area_user()
# print_dict(roledata) if m.has_subarea() == True:
# Unterbereich
roledata = m.get_subarea_user()
else:
# Bereich
roledata = m.get_area_user()
# Benutzer: Hinzufügen # Benutzer: Hinzufügen
if roledata["id"] not in roles.keys(): if roledata["id"] not in roles.keys():
roles[roledata["id"]] = roledata roles[roledata["id"]] = roledata
# Domänen-Benutzer: Berechtigungen hinzufügen
if settings["domain_user"] == True:
if m.has_subarea() == True:
# Unterbereich
perms = m.get_subarea_user()["perms"]
else:
# Bereich
perms = m.get_area_user()["perms"]
for p in perms:
if p not in roles[roledata["id"]]["perms"]:
roles[roledata["id"]]["perms"].append(p)
# Datenanzeige
if settings["show_roles"] == True:
print_dict(roles)
return roles return roles
@ -434,19 +569,38 @@ def generate_bffh_roles(roles):
data = [] data = []
# Rollen # Anfang Datenstruktur
data.append(space + 'roles = {') data.append('{')
# Inhalt
last_role = len(roles) - 1
for index_role, role in enumerate(roles):
data.append(space * 1 + f'{role}' + ' =')
data.append(space * 1 + '{')
data.append(space * 2 + 'permissions = [')
last_perm = len(roles[role]["perms"]) - 1
for index_perm, (perm) in enumerate(roles[role]["perms"]):
if index_perm < last_perm:
data.append(space * 4 + f'"{perm}",')
else:
data.append(space * 4 + f'"{perm}"')
data.append(space * 2 + ']')
if index_role == last_role:
data.append(space * 1 + '}')
else:
data.append(space * 1 + '},')
for role in roles:
data.append(space * 2 + f'{role}' + ' = {')
data.append(space * 3 + 'permissions = [')
for perm in roles[role]["perms"]:
data.append(space * 4 + f'"{perm}",')
data.append(space * 3 + ']')
data.append(space * 2 + '},')
data.append(' ') data.append(' ')
data.append(space + '},') # Ende Datenstruktur
data.append('}')
return data return data
@ -455,22 +609,45 @@ def generate_bffh_machines(machines):
data = [] data = []
data.append(space + 'machines = {') # Anfang Datenstruktur
for id, m in machines.items(): data.append('{')
# Inhalt
last_machine = len(machines) - 1
for index_machine, (id, m) in enumerate(machines.items()):
specs = m.get_machine() specs = m.get_machine()
data.append(space * 2 + f'{specs["fa_id"]}' + ' = {') data.append(space * 1 + f'{specs["fa_id"]}' + ' =')
data.append(space * 3 + f'name = "{specs["name"]}",') data.append(space * 1 + '{')
data.append(space * 3 + f'description = "{specs["desc"]}",') data.append(space * 2 + f'name = "{specs["name"]}",')
data.append(space * 3 + f'wiki = "{specs["wikiurl"]}",') data.append(space * 2 + f'description = "{specs["desc"]}",')
data.append(space * 3 + f'category = "{specs["category"]}",') data.append(space * 2 + f'wiki = "{specs["wikiurl"]}",')
data.append(space * 2 + f'category = "{specs["category"]}",')
for i in range(len(specs["perms"])): permcount = len(specs["perms"])
data.append(space * 3 + f'{specs["perms_names"][i]} = "{specs["perms"][i]}",') last_perm = permcount - 1
for i in range(permcount):
if i < last_perm:
data.append(space * 2 + f'{specs["perms_names"][i]} = "{specs["perms"][i]}",')
else:
data.append(space * 2 + f'{specs["perms_names"][i]} = "{specs["perms"][i]}"')
if index_machine == last_machine:
data.append(space * 1 + '}')
state = 'last'
else:
data.append(space * 1 + '},')
state = 'not last'
data.append(space * 2 + '},')
data.append(' ') data.append(' ')
data.append(space + '},') index_machine +=1
# Ende Datenstruktur
data.append('}')
return data return data
@ -479,9 +656,13 @@ def generate_bffh_actors(machines):
data = [] data = []
data.append(space + 'actors = {') # Anfang Datenstruktur
data.append('{')
for id, m in machines.items(): # Inhalt
last_actor = len(machines) - 1
for index_actor, (id, m) in enumerate(machines.items()):
specs = m.get_machine() specs = m.get_machine()
if len(specs["actor_id"]) > 0 and len(specs["actor_type"]) > 0: if len(specs["actor_id"]) > 0 and len(specs["actor_type"]) > 0:
@ -489,25 +670,39 @@ def generate_bffh_actors(machines):
# 2do Actor Library Funktionalität # 2do Actor Library Funktionalität
data.append(f' {actor_handle} =') data.append(space * 1 + f'{actor_handle} =')
data.append(' {') data.append(space * 1 + '{')
data.append(f' module = "{actor_library[specs["actor_type"]]["module"]}",') data.append(space * 2 + f'module = "{actor_library[specs["actor_type"]]["module"]}",')
data.append(' params =') data.append(space * 2 + 'params =')
data.append(' {') data.append(space * 2 + '{')
# Aktor-ID der aktuellen Maschine speichern # Aktor-ID der aktuellen Maschine speichern
replace = { replace = {
"actor_id": specs["actor_id"] "actor_id": specs["actor_id"]
} }
for key, value in actor_library[specs["actor_type"]]["params"].items(): last_param = len(actor_library[specs["actor_type"]]["params"]) - 1
for index_param, (key, value) in enumerate(actor_library[specs["actor_type"]]["params"].items()):
template = Template(value) template = Template(value)
string = template.substitute(replace) string = template.substitute(replace)
data.append(f' {key} = {string},')
data.append(' }') if index_param < last_param:
data.append(' },') data.append(space * 3 + f'{key} = {string},')
else:
data.append(space * 3 + f'{key} = {string}')
data.append(space * 2 + '}')
if index_actor == last_actor:
data.append(space * 1 + '}')
else:
data.append(space * 1 + '},')
data.append(' ') data.append(' ')
data.append(space + '}, ')
# Ende Datenstruktur
data.append('}')
return data return data
@ -517,81 +712,126 @@ def generate_bffh_actorconnections(machines):
data = [] data = []
data.append(space + 'actor_connections = [') # Anfang Datenstruktur
data.append('[')
for id, m in machines.items(): # Inhalt
last = len(machines) - 1
for index, (id, m) in enumerate(machines.items()):
specs = m.get_machine() specs = m.get_machine()
if len(specs["actor_id"]) > 0 and len(specs["actor_type"]) > 0: if len(specs["actor_id"]) > 0 and len(specs["actor_type"]) > 0:
actor_fullid = specs["actor_type"] + '_' + specs["actor_id"] actor_fullid = specs["actor_type"] + '_' + specs["actor_id"]
data.append(space * 2 + '{ ' + f'machine = "{specs["fa_id"]}", actor = "{actor_fullid}"' + ' },')
data.append(space + '],') if index == last:
data.append(space * 1 + '{ ' + f'machine = "{specs["fa_id"]}", actor = "{actor_fullid}"' + ' }')
else:
data.append(space * 1 + '{ ' + f'machine = "{specs["fa_id"]}", actor = "{actor_fullid}"' + ' },')
# Ende Datenstruktur
data.append(']')
return data return data
# CSV-Rollenliste # CSV-Rollenliste
def generate_csv_roles(roles): def create_roles_csv(roles):
print('|- Rollenliste exportieren')
data = [] data = []
data.append('ID der Rolle; Name der Rolle') data.append('ID der Rolle; Name der Rolle')
for id, values in roles.items(): for id, values in roles.items():
string = id + ';' + values["name"] string = id + ';' + values["name"]
data.append(string) data.append(string)
return data write_file('output/roles.csv', data)
# dhall-Dateien erzeugen
def create_singledhall(export_roles, export_machines, export_actors, export_actorconnections):
print('|- Gesamten DHALL-Output exportieren')
input = [export_roles, export_machines, export_actors, export_actorconnections]
data = []
# Rollen
index_input = 0
for i in input:
match(index_input):
case 0: data.append('roles =')
case 1: data.append('machines =')
case 2: data.append('actors =')
case 3: data.append('export_actorconnections =')
last = len(input[index_input]) - 1
for index_seg, (el) in enumerate(i):
if index_seg == last:
data.append(el + ',')
else:
data.append(el)
index_input += 1
write_file('output/bffh-dhall-data.txt', data)
def create_multipledhalls(export_roles, export_machines, export_actors, export_actorconnections):
# bffh.dhall aktualisieren input = [export_roles, export_machines, export_actors, export_actorconnections]
def generate_bffh_dhall(generated_content): fa_dhall_directory = settings["fa_dhall_directory"].replace('\\', '/')
dhall_file = settings["fa_dhall_file"]
reader = open(dhall_file, "r", encoding='utf-8') print('|- Einzelne DHALLs exportieren')
data_write = [] if fa_dhall_directory != '':
print(f'|- Ablegen der DHALL-Dateien in: "{fa_dhall_directory}"')
inside_generator_block = False index_input = 0
found_generator_block = False
count = 1 for i in input:
# bffh.dhall zeilenweise durchlaufen match(index_input):
for line in reader: case 0: target_file = 'roles.dhall'
case 1: target_file = 'machines.dhall'
case 2: target_file = 'actors.dhall'
case 3: target_file = 'actorconnections.dhall'
# Beginn des Generator-Blocks gefunden --> Erzeugte Daten anhängen, Variablen umschalten print(f' |- Erzeuge {target_file}')
if 'GENERATOR START' in line:
found_generator_block = True
inside_generator_block = True
data_write.append(line.replace('\n', ''))
data_write.append(' ')
data_write += generated_content
data_write.append(' ')
added_generated_content = True
# print(f'{count} Generatorblock-Anfang gefunden')
# Beginn des Generator-Blocks gefunden --> Variable umschalten # Im Output-Ordner
if 'GENERATOR END' in line: target = 'output/' + target_file
inside_generator_block = False write_file(target, i)
# print(f'{count} Generatorblock-Ende gefunden')
# Zeile liegt außerhalb des Generator-Blocks --> Zeile übernehmen
if inside_generator_block == False:
data_write.append(line.replace('\n', ''))
# Zeile liegt innerhalb des Generator-Blocks --> Zeile übernehmen # Im zusätzlichen Ordner
if inside_generator_block == True: if fa_dhall_directory != '':
# Einfügung wurden vorgenommen, Zeile aus bffh.dhall ignorieren target = fa_dhall_directory + '/' + target_file
continue target = target.replace('//', '/')
write_file(target, i)
if found_generator_block == True: index_input += 1
return data_write
else:
print('Datei "bffh.dhall" enthält keinen Platzhalter zum automatischen Einfügen.') def create_mermaid(machines):
return [] print('|- Mermaid-Code erzeugen')
graphelements = graph_create_elements(machines)
mermaidcode = graph_create_mermaidcode(graphelements)
write_file('output/mermaid-code.txt', mermaidcode)
# Maschine vollständig ausgeben # Maschine vollständig ausgeben
@ -686,8 +926,8 @@ def graph_create_elements(machines):
data = {} data = {}
data["_root"] = GraphElement("root", "Infrastruktur", '') data["_root"] = GraphElement("root", "Infrastruktur", '')
data["_root"].add_role(f'{icon_admin}{admin_global["name"]}') data["_root"].add_role(f'{icon_admin}{admin_global["name"]}')
if settings["manager_schichtleitung"] == True: if settings["manager_domain"] == True:
data["_root"].add_role(f'{icon_manager}{manager_schichtleitung["name"]}') data["_root"].add_role(f'{icon_manager}{manager_domain["name"]}')
for key, m in machines.items(): for key, m in machines.items():

View File

@ -1,9 +1,7 @@
from generator.helpers import config_load from generator.helpers import config_load
from generator.helpers import load_actors from generator.helpers import load_actors
# Daten für Generator # Icons für Mermaid-Code
settings = config_load('settings.ini', 'generator')
actor_library = load_actors('actors.ini')
icon_admin = "👑" icon_admin = "👑"
icon_manager = "🛠️" icon_manager = "🛠️"
@ -12,13 +10,14 @@ icon_user = "👷‍♂️"
icon_custom = '👩‍🚀' icon_custom = '👩‍🚀'
# Daten für den zentrale Rollen
admin_global = { admin_global = {
"id": "Admin", "id": "Admin",
"name": "_Admin FabAccess", "name": "_Admin FabAccess",
"perms": ["bffh.users.manage", "bffh.users.info", "bffh.users.admin"] "perms": ["bffh.users.manage", "bffh.users.info", "bffh.users.admin"]
} }
manager_schichtleitung = { manager_domain = {
"id": "_manager_schichtleitung", "id": "_manager_schichtleitung",
"name": "_Manager Schichtleitung", "name": "_Manager Schichtleitung",
"perms": [] "perms": []

View File

@ -49,9 +49,17 @@ def list_join(my_list, insert):
my_string = f'{insert}'.join(str(element) for element in my_list) my_string = f'{insert}'.join(str(element) for element in my_list)
return my_string return my_string
# CSV-Delimiter ermitteln
def csv_getdelimiter(file: str) -> str:
with open(file, 'r') as csvfile:
delimiter = str(csv.Sniffer().sniff(csvfile.read()).delimiter)
return delimiter
# CSV einlesen: Erzeugt eine Liste, die für jede Zeile ein Dictionary mit Header und Value ausgibt # CSV einlesen: Erzeugt eine Liste, die für jede Zeile ein Dictionary mit Header und Value ausgibt
def csv_listdict(filename, replacedict = {}): def csv_listdict(filename, replacedict = {}):
csv_delimiter = csv_getdelimiter(filename)
csvfile = open(filename, 'r', encoding='utf-8-sig') csvfile = open(filename, 'r', encoding='utf-8-sig')
tempfile = '' tempfile = ''
@ -75,7 +83,7 @@ def csv_listdict(filename, replacedict = {}):
# Dictionary bilden # Dictionary bilden
csvfile = open(filename, mode='r', encoding='utf-8-sig') csvfile = open(filename, mode='r', encoding='utf-8-sig')
reader = csv.DictReader(csvfile, delimiter=';') reader = csv.DictReader(csvfile, delimiter=csv_delimiter)
finaldata = [] finaldata = []
@ -88,6 +96,7 @@ def csv_listdict(filename, replacedict = {}):
return finaldata return finaldata
# Datei schreiben # Datei schreiben
def write_file(filename, content): def write_file(filename, content):
f = open(filename, "w", encoding='utf-8', newline='\n') f = open(filename, "w", encoding='utf-8', newline='\n')
@ -181,12 +190,6 @@ def config_load(file, section = 'all'):
return dict_settings return dict_settings
# ------------------ ALT ---------------
# Maschinen-Dictionary sortieren
# Actor-Library einlesen # Actor-Library einlesen
def load_actors(file): def load_actors(file):
dict_actors = {} dict_actors = {}

View File

@ -3,31 +3,23 @@
; Einstellung inkativ = False ; Einstellung inkativ = False
[generator] [generator]
; Verwendung mehrer Domänen. Bei Verwendung mehrer Domänen werden einzelne Admins nur für die Domäne erstellt ; Verwendung mehrer Domänen. Bei Verwendung mehrer Domänen werden wird für jede Domäne ein Manager erstellt
multi_domains = False multi_domains = False
; Rolle "Schichtleitung" erstellen, die über Manager-Berechtigungen für alle Domänen verfügt ; Erstellung einer Benutzerrolle für die gesamte Werkstatt. (Es werden keine Benutzerrollen für Unterbereiche/ Bereiche erstellt)
manager_schichtleitung = True domain_user = True
; Manager-Rolle für jeden Bereich erstellen ; Manager-Rolle für die Domäne erstellen.
manager_area = True manager_domain = True
; Manager-Rolle für jeden Bereich erstellen.
manager_area = False
; Spalte "Unterbereich Manager" der CSV beachten (True) der nicht (False). ; Spalte "Unterbereich Manager" der CSV beachten (True) der nicht (False).
manager_subarea = True manager_subarea = False
; Automatisches Einfügen aller erzeugten Daten (Maschinen, Rolle, Aktoren, Aktor-Verbindungen) in die bffh.dhall ; Erzeugt DHALL-Dateien für Rollen, Maschinen, Aktoren und Aktorenverbindungen
; Die Datei muss über Platzhalter verfügen, siehe Beispieldatei ( /docs/bffh-vorlage.dhall ) fa_dhall_directory = F:\fabaccess-docker\config\bffh\
fa_update_dhall = False
; Pfad zur bffh.dall von FabAccess. Der Pfad muss vollständig sein und die bffh.dhall beinhalten.
; Beispiel: D:\FabAccess\config\bffh\bffh.dhall bzw. /home/fabaccess/bffh/bffh.dhall
fa_dhall_file =
; Mermaid-Code erzeugen
generate_mermaid = True
; Gesonderte Datei die eine Liste aller Rollen enthält
create_file_roles = True
; Anzeige aller erzeugten Maschinendaten ; Anzeige aller erzeugten Maschinendaten
show_machines = False show_machines = False