praktikum 3

This commit is contained in:
darthsandmann 2017-01-16 23:32:28 +01:00
parent 41af35a624
commit 0ef842e09e
171 changed files with 22681 additions and 27 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum1_Kai/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum1_Kai/test/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum1_Kai/test/app/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum1_Kai/webteams/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum1_Kai/webteams/app/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
Praktikum1_Kai/webteams/data/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm1/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm1/app/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm1/data/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm1/static/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm2/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm2/.vs/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm2/.vs/ppm2/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm2/app/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum2/ppm2/data/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -1,13 +1,13 @@
{
"Firma": "Apple",
"ZeitraumBis": "02.02.2003",
"ZeitraumVon": "02.02.2002",
"Beschreibung": "Praxisphase Apple",
"Firmenbetreuer": "Horst",
"Voraussetzungen": "Keine",
"Student": "11",
"id": "27",
"Lehrender": "5",
"Name": "Angebot Apple 2",
"Status": "abgeschlossen"
"Firmenbetreuer": "Horst",
"Status": "abgeschlossen",
"id": "27",
"ZeitraumVon": "02.02.2002",
"ZeitraumBis": "02.02.2003",
"Student": "11",
"Beschreibung": "Praxisphase Apple",
"Lehrender": "5"
}

View File

@ -1,13 +1,13 @@
{
"Firma": "Apple",
"ZeitraumBis": "2.2.2001",
"ZeitraumVon": "1.1.2000",
"Beschreibung": "testa",
"Firmenbetreuer": "testa",
"Voraussetzungen": "a",
"Student": "13",
"id": "28",
"Lehrender": "6",
"Name": "testa",
"Status": "abgeschlossen"
"Firmenbetreuer": "testa",
"Status": "abgeschlossen",
"id": "28",
"ZeitraumVon": "1.1.2000",
"ZeitraumBis": "2.2.2001",
"Student": "13",
"Beschreibung": "testa",
"Lehrender": "6"
}

View File

@ -0,0 +1,13 @@
{
"Firma": "Apple",
"Voraussetzungen": "kein",
"Name": "asoidajido",
"Firmenbetreuer": "sfijsdgjisgpj",
"Lehrender": "",
"Status": "Angebot",
"ZeitraumVon": "",
"Beschreibung": "sdgjosdgjs",
"Student": "",
"id": "29",
"ZeitraumBis": ""
}

View File

@ -1,13 +1,13 @@
{
"Firma": "IBM",
"ZeitraumBis": "02.02.2000",
"ZeitraumVon": "01.01.2000",
"Beschreibung": "beschreibung",
"Firmenbetreuer": "firmenbetreuer",
"Voraussetzungen": "voraussetzungen",
"Student": "12",
"id": "30",
"Lehrender": "6",
"Name": "name",
"Status": "abgeschlossen"
"Firmenbetreuer": "firmenbetreuer",
"Status": "abgeschlossen",
"id": "30",
"ZeitraumVon": "01.01.2000",
"ZeitraumBis": "02.02.2000",
"Student": "12",
"Beschreibung": "beschreibung",
"Lehrender": "6"
}

View File

@ -1 +1 @@
28
29

View File

@ -0,0 +1,6 @@
{
"Vorname": "test",
"Name": "test",
"Matrikelnummer": "test",
"id": "18"
}

View File

@ -1 +1 @@
17
18

BIN
Praktikum2/ppm2/static/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -9,7 +9,6 @@ class PPM
this.BodyDataAction();
this.TemplateManager_o = new TemplateManager_cl();
this.TemplateManager_o;
console.log("PPM LOADED");
}

BIN
Praktikum3/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum3/bt/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum3/bt/app/.DS_Store vendored Normal file

Binary file not shown.

3
Praktikum3/bt/app/__init__.py Executable file
View File

@ -0,0 +1,3 @@
# coding: utf-8
# hier können Paket-Initialisierungen eingetragen werden

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

121
Praktikum3/bt/app/application.py Executable file
View File

@ -0,0 +1,121 @@
# coding: utf-8
import json
import cherrypy
from .projekt import Projekt_cl, ProjektKomponenten_cl, Komponente_cl
from .staff import QsMitarbeiter_cl, SwEntwickler_cl
from .error import KatFehler_cl, KatUrsache_cl, Fehler_cl
from .eval import ProList_cl, KatList_cl
#----------------------------------------------------------
class Application_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
self.handler_o = {
'projekt': Projekt_cl(),
'projektkomponenten': ProjektKomponenten_cl(),
'komponente': Komponente_cl(),
'qsmitarbeiter': QsMitarbeiter_cl(),
'swentwickler': SwEntwickler_cl(),
'katfehler': KatFehler_cl(),
'katursache': KatUrsache_cl(),
'fehler': Fehler_cl(),
'prolist': ProList_cl(),
'katlist': KatList_cl()
}
# es wird keine index-Methode vorgesehen, weil stattdessen
# die Webseite index.html ausgeliefert wird (siehe Konfiguration)
#-------------------------------------------------------
def GET(self, path_spl = 'projekt', id=None):
#-------------------------------------------------------
retVal_o = {
'data': None
}
if path_spl in self.handler_o:
retVal_o = self.handler_o[path_spl].GET(id)
if retVal_o['data'] == None:
cherrypy.response.status = 404
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self, path_spl = 'projekt', **data_opl):
#-------------------------------------------------------
retVal_o = {
'id': None
}
# data_opl: Dictionary mit den gelieferten key-value-Paaren
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
if path_spl in self.handler_o:
retVal_o = self.handler_o[path_spl].POST(data_opl)
if retVal_o['id'] == None:
cherrypy.response.status = 409
return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self, path_spl = 'projekt', **data_opl):
#-------------------------------------------------------
# Sichern der Daten: jetzt wird keine vollständige Seite
# zurückgeliefert, sondern nur noch die Information, ob das
# Speichern erfolgreich war
retVal_o = {
'id': None
}
# data_opl: Dictionary mit den gelieferten key-value-Paaren
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
if path_spl in self.handler_o:
retVal_o = self.handler_o[path_spl].PUT(data_opl)
if retVal_o['id'] == None:
cherrypy.response.status = 404
return json.dumps(retVal_o)
#-------------------------------------------------------
def DELETE(self, path_spl = 'projekt', id=None):
#-------------------------------------------------------
# Eintrag löschen, nur noch Rückmeldung liefern
retVal_o = {
'id': id
}
if path_spl in self.handler_o:
retVal_o = self.handler_o[path_spl].DELETE(id)
if retVal_o['id'] == None:
cherrypy.response.status = 404
return json.dumps(retVal_o)
#-------------------------------------------------------
def default(self, *arguments, **kwargs):
#-------------------------------------------------------
msg_s = "unbekannte Anforderung: " + \
str(arguments) + \
' ' + \
str(kwargs)
raise cherrypy.HTTPError(404, msg_s)
# EOF

256
Praktikum3/bt/app/database.py Executable file
View File

@ -0,0 +1,256 @@
# coding: utf-8
import os
import os.path
import codecs
import json
#----------------------------------------------------------
class Database_cl(object):
#----------------------------------------------------------
# Daten in dieser Variante dauerhaft (persistent) speichern
# dazu jedes Element in einer Datei, die entsprechend der id benannt ist, speichern
# alle Elemente werden zur Laufzeit des Servers zur Vereinfachung auch im
# Hauptspeicher abgelegt
# die nächste zu vergebende Id wird ebenfalls dauerhaft gespeichert
# zur Vereinfachung wird hier fest vorgegebenen, dass sich die Daten
# im Unterverzeichnis "data/<type>" befinden (siehe Konstruktor)
# es wird ferner angenommen, dass die Datei "data/<type>/maxid.dat" bereits existiert
# und als einzigen Eintrag den aktuellen Wert der maximalen Id enthält
#-------------------------------------------------------
def __init__(self, type_spl):
#-------------------------------------------------------
self.type_s = type_spl
self.path_s = os.path.join('data', type_spl)
self.data_o = {}
self.readData_p()
#-------------------------------------------------------
def create_px(self, data_opl):
#-------------------------------------------------------
# Überprüfung der Datenn müsste ergänzt werden!
id_s = self.nextId_p()
# Datei erzeugen
file_o = codecs.open(os.path.join(self.path_s , id_s+'.dat'), 'w', 'utf-8')
file_o.write(json.dumps(data_opl, indent=3, ensure_ascii=True))
file_o.close()
self.data_o[id_s] = data_opl
return id_s
#-------------------------------------------------------
def read_px(self, id_spl = None):
#-------------------------------------------------------
# hier zur Vereinfachung:
# Aufruf ohne id: alle Einträge liefern
data_o = None
if id_spl == None:
data_o = self.data_o
elif id_spl == '0':
data_o = self.getDefault_px()
else:
if id_spl in self.data_o:
data_o = self.data_o[id_spl]
return data_o
#-------------------------------------------------------
def update_px(self, id_spl, data_opl):
#-------------------------------------------------------
# Überprüfung der Daten müsste ergänzt werden!
status_b = False
if id_spl in self.data_o:
# Datei aktualisieren
file_o = codecs.open(os.path.join(self.path_s, id_spl+'.dat'), 'w', 'utf-8')
file_o.write(json.dumps(data_opl, indent=3, ensure_ascii=True))
file_o.close()
self.data_o[id_spl] = data_opl
status_b = True
return status_b
#-------------------------------------------------------
def delete_px(self, id_spl):
#-------------------------------------------------------
status_b = False
if id_spl in self.data_o:
# Datei entfernen
os.remove(os.path.join(self.path_s, id_spl+'.dat'))
del self.data_o[id_spl]
status_b = True
return status_b
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
# sollte überschrieben werden!
return {}
#-------------------------------------------------------
def readData_p(self):
#-------------------------------------------------------
files_a = os.listdir(self.path_s)
for fileName_s in files_a:
if fileName_s.endswith('.dat') and fileName_s != 'maxid.dat':
file_o = codecs.open(os.path.join(self.path_s, fileName_s), 'rU', 'utf-8')
content_s = file_o.read()
file_o.close()
id_s = fileName_s[:-4]
self.data_o[id_s] = json.loads(content_s)
#-------------------------------------------------------
def nextId_p(self):
#-------------------------------------------------------
file_o = open(os.path.join(self.path_s, 'maxid.dat'), 'r+')
maxId_s = file_o.read()
maxId_s = str(int(maxId_s)+1)
file_o.seek(0)
file_o.write(maxId_s)
file_o.close()
return maxId_s
#----------------------------------------------------------
class ProjektDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('projekt')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'name': '',
'id': ''
}
#----------------------------------------------------------
class KomponenteDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('komponente')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'name': '',
'id': '',
'projekt-id': ''
}
#----------------------------------------------------------
class QsMitarbeiterDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('qsmitarbeiter')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'name': '',
'id': ''
}
#----------------------------------------------------------
class SwEntwicklerDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('swentwickler')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'name': '',
'id': ''
}
#----------------------------------------------------------
class KatfehlerDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('katfehler')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'name': '',
'id': ''
}
#----------------------------------------------------------
class KatursacheDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('katursache')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'name': '',
'id': ''
}
#----------------------------------------------------------
class FehlerDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('fehler')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'name': '',
'id': '',
'komponente-id': '',
'katfehler-id': '',
'katursache-id': '',
'qsmitarbeiter-id': '',
'swentwickler-id': '',
'status': 'offen'
}
# EOF

140
Praktikum3/bt/app/error.py Normal file
View File

@ -0,0 +1,140 @@
# coding: utf-8
import json
import cherrypy
#from .database import SourceDatabase_cl, EvaluatedDatabase_cl
# Method-Dispatching!
# Übersicht Anforderungen / Methoden
# (beachte: / relativ zu /navigation, siehe Konfiguration Server!)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/katfehler/ alle Fehlerkategorien
/katfehler/:katfehler-id
einzelne Fehlerkategorien Fehler löschen
/katfehler/+Daten neue FK speichern
/katfehler/:katfehler-id+Daten Fehler ändern
"""
#----------------------------------------------------------
class KatFehler_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def DELETE(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/katursache/ alle Fehlerkategorien
/katursache/:katursache-id
einzelne Fehlerkategorien Fehler löschen
/katursache/+Daten neue FK speichern
/katursache/:katursache-id+Daten Fehler ändern
"""
#----------------------------------------------------------
class KatUrsache_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def DELETE(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/fehler/ alle Fehler
/fehler/?type=erkannt alle erkannten Fehler
/fehler/?type=behoben alle behobenen Fehler
/fehler/:fehler-id einzelner Fehler
/fehler/+Daten Fehler speichern
Rückgabe Id
/fehler/:fehler-id+Daten Fehler ändern
"""
#----------------------------------------------------------
class Fehler_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
# EOF

64
Praktikum3/bt/app/eval.py Normal file
View File

@ -0,0 +1,64 @@
# coding: utf-8
import json
import cherrypy
#from .database import SourceDatabase_cl, EvaluatedDatabase_cl
# Method-Dispatching!
# Übersicht Anforderungen / Methoden
# (beachte: / relativ zu /navigation, siehe Konfiguration Server!)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/prolist/ Auswertung nach
Projekt/Komponente/
Status
"""
#----------------------------------------------------------
class ProList_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/katlist/ Auswertung nach
Kategorie/Status
"""
#----------------------------------------------------------
class KatList_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
# EOF

47
Praktikum3/bt/app/navigation.py Executable file
View File

@ -0,0 +1,47 @@
# coding: utf-8
import json
import cherrypy
# Method-Dispatching!
# Übersicht Anforderungen / Methoden
# (beachte: / relativ zu /navigation, siehe Konfiguration Server!)
"""
Anforderung GET PUT POST DELETE
----------------------------------------------------------------
/ Nav-Entries - - -
"""
#----------------------------------------------------------
class Navigation_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
# Hinweis: könnte man auch aus einer Datei einlesen
retVal_o = [
{'action': 'modError' , 'text': 'Bearbeitung Fehlerdaten'},
{'action': 'modProj' , 'text': 'Pflege Projekte'},
{'action': 'modComp' , 'text': 'Pflege Komponenten'},
{'action': 'modStaff' , 'text': 'Pflege Daten Mitarbeiter'},
{'action': 'modCat' , 'text': 'Pflege Kategorien'},
{'action': 'evalProj' , 'text': 'Auswertung Projekte/Fehler'},
{'action': 'evalCat' , 'text': 'Auswertung Kategorien/Fehler'}
]
return json.dumps(retVal_o)
# EOF

View File

@ -0,0 +1,181 @@
# coding: utf-8
import json
import cherrypy
from .database import ProjektDatabase_cl, KomponenteDatabase_cl
# Method-Dispatching!
# Übersicht Anforderungen / Methoden
# (beachte: / relativ zu /navigation, siehe Konfiguration Server!)
#-------------------------------------------------------
def adjustId_p(id_spl, data_opl):
#-------------------------------------------------------
if id_spl == None:
data_opl['id'] = ''
elif id_spl == '':
data_opl['id'] = ''
elif id_spl == '0':
data_opl['id'] = ''
else:
data_opl['id'] = id_spl
return data_opl
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/projekt/ alle Projekte
(Liste) anfordern
/projekt/:projekt-id einzelnes Projekt Projekt löschen
anfordern
/projekt/+Daten neues speichern
Projekt-Id Rückgabe
/projekt/:projekt-id+Daten Projekt ändern
"""
#----------------------------------------------------------
class Projekt_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
self.db_o = ProjektDatabase_cl()
#-------------------------------------------------------
def GET(self, id = None):
#-------------------------------------------------------
retVal_o = {
'data': None
}
if id == None:
# Anforderung der Liste
retVal_o['data'] = self.db_o.read_px()
else:
# Anforderung eines Dokuments
data_o = self.db_o.read_px(id)
if data_o != None:
retVal_o['data'] = adjustId_p(id, data_o)
return retVal_o
#return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def DELETE(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/projektkomponenten/:projekt-id
Komponenten liefern
"""
#----------------------------------------------------------
class ProjektKomponenten_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
self.db_o = KomponenteDatabase_cl()
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
retVal_o = {
'data': None
}
if id == None:
# Anforderung der Liste
retVal_o['data'] = self.db_o.read_px()
else:
# Anforderung eines Dokuments
data_o = self.db_o.read_px(id)
if data_o != None:
retVal_o['data'] = adjustId_p(id, data_o)
return retVal_o
#return json.dumps(retVal_o)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/komponente/ alle Komponenten
/komponente/:komponente-id
einzelne Komponente Komponente löschen
/komponente/:projekt-id+Daten neue Komponente speichern
Id Rückgabe
/komponente/:komponente-id+Daten Komponente ändern
"""
#----------------------------------------------------------
class Komponente_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
self.db_o = KomponenteDatabase_cl()
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
retVal_o = {
'data': None
}
if id == None:
# Anforderung der Liste
retVal_o['data'] = self.db_o.read_px()
else:
# Anforderung eines Dokuments
data_o = self.db_o.read_px(id)
if data_o != None:
retVal_o['data'] = adjustId_p(id, data_o)
return retVal_o
#return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def DELETE(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
# EOF

100
Praktikum3/bt/app/staff.py Normal file
View File

@ -0,0 +1,100 @@
# coding: utf-8
import json
import cherrypy
#from .database import SourceDatabase_cl, EvaluatedDatabase_cl
# Method-Dispatching!
# Übersicht Anforderungen / Methoden
# (beachte: / relativ zu /navigation, siehe Konfiguration Server!)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/qsmitarbeiter/ alle Daten anfordern
/qsmitarbeiter/:mitarbeiter-id
Daten eines einzelnen Mitarbeiters
/qsmitarbeiter/+Daten Daten speichern
Rückgabe Id
/qsmitarbeiter/:qsmitarbeiter-id+Daten Daten ändern
/qsmitarbeiter/:qsmitarbeiter-id Daten löschen
"""
#----------------------------------------------------------
class QsMitarbeiter_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def DELETE(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
"""
Anforderung GET PUT POST DELETE
-----------------------------------------------------------------------------------------
/swentwickler/ Daten aller Entwickler
/swentwickler/:swentwickler-id
Daten eines einzelnen Entwicklers Daten löschen
/swentwickler/+Daten Neuen SW-E speichern
/swentwickler/:swentwickler-id+Daten Daten ändern
"""
#----------------------------------------------------------
class SwEntwickler_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
#-------------------------------------------------------
def DELETE(self):
#-------------------------------------------------------
return json.dumps(retVal_o)
# EOF

52
Praktikum3/bt/app/templates.py Executable file
View File

@ -0,0 +1,52 @@
# coding: utf-8
import json
import os
import codecs
import cherrypy
# Method-Dispatching!
# Übersicht Anforderungen / Methoden
# (beachte: / relativ zu /template, siehe Konfiguration Server!)
"""
Anforderung GET PUT POST DELETE
----------------------------------------------------------------
/ Alle - - -
Templates
liefern
"""
#----------------------------------------------------------
class Templates_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
retVal_o = {
'templates': {}
}
files_a = os.listdir('templates')
for fileName_s in files_a:
file_o = codecs.open(os.path.join('templates', fileName_s), 'rU', 'utf-8')
content_s = file_o.read()
file_o.close()
retVal_o["templates"][fileName_s] = content_s
return json.dumps(retVal_o)
# EOF

BIN
Praktikum3/bt/data/.DS_Store vendored Normal file

Binary file not shown.

BIN
Praktikum3/bt/data/fehler/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
0

BIN
Praktikum3/bt/data/katfehler/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
0

BIN
Praktikum3/bt/data/katursache/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
0

BIN
Praktikum3/bt/data/komponente/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
0

BIN
Praktikum3/bt/data/projekt/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
0

Binary file not shown.

View File

@ -0,0 +1 @@
0

Binary file not shown.

View File

@ -0,0 +1 @@
0

76
Praktikum3/bt/server.py Executable file
View File

@ -0,0 +1,76 @@
#coding: utf-8
import os
import cherrypy
from app import application, templates, navigation, projekt, staff, error, eval
#--------------------------------------
def main():
#--------------------------------------
# Get current directory
try:
current_dir = os.path.dirname(os.path.abspath(__file__))
except:
current_dir = os.path.dirname(os.path.abspath(sys.executable))
# disable autoreload and timeout_monitor
cherrypy.engine.autoreload.unsubscribe()
cherrypy.engine.timeout_monitor.unsubscribe()
# Static content config
staticConfig_o = {
'/': {
'tools.staticdir.root': current_dir,
'tools.staticdir.on': True,
'tools.staticdir.dir': './static',
'tools.staticdir.index': './html/index.html',
'request.dispatch': cherrypy.dispatch.MethodDispatcher()
},
'/favicon.ico': {
'tools.staticfile.on': True,
'tools.staticfile.filename': current_dir+'/static/images/favicon.ico'
}
}
staticConfig2_o = {
'/': {
'request.dispatch': cherrypy.dispatch.MethodDispatcher()
}
}
cherrypy.config.update({
'tools.log_headers.on': True,
'tools.sessions.on': False,
'tools.encode.on': True,
'tools.encode.encoding': 'utf-8',
'server.socket_port': 8080,
'server.socket_timeout': 60,
'server.thread_pool': 10,
'server.environment': 'production',
'log.screen': True,
'request.show_tracebacks': False
})
# Request-Handler definieren
cherrypy.tree.mount(application.Application_cl(), '/', staticConfig_o)
cherrypy.tree.mount(templates.Templates_cl(), '/templates', staticConfig2_o)
cherrypy.tree.mount(navigation.Navigation_cl(), '/navigation', staticConfig2_o)
#cherrypy.tree.mount(projekt.Projekt_cl(), '/projekt', staticConfig2_o)
#cherrypy.tree.mount(projekt.ProjektKomponenten_cl(), '/projektkomponenten', staticConfig2_o)
#cherrypy.tree.mount(projekt.Komponente_cl(), '/komponente', staticConfig2_o)
#cherrypy.tree.mount(staff.QsMitarbeiter_cl(), '/qsmitarbeiter', staticConfig2_o)
#cherrypy.tree.mount(staff.SwEntwickler_cl(), '/swentwickler', staticConfig2_o)
#cherrypy.tree.mount(error.KatFehler_cl(), '/katfehler', staticConfig2_o)
#cherrypy.tree.mount(error.KatUrsache_cl(), '/katursache', staticConfig2_o)
#cherrypy.tree.mount(error.Fehler_cl(), '/fehler', staticConfig2_o)
#cherrypy.tree.mount(eval.ProList_cl(), '/prolist', staticConfig2_o)
#cherrypy.tree.mount(eval.KatList_cl(), '/katlist', staticConfig2_o)
# Start server
cherrypy.engine.start()
cherrypy.engine.block()
#--------------------------------------
if __name__ == '__main__':
#--------------------------------------
main()
# EOF

194
Praktikum3/bt/static/css/main.css Executable file
View File

@ -0,0 +1,194 @@
/* main.css */
/* allgemeine Vorgaben */
body {
font-family: "Open Sans", sans-serif;
font-size: 12pt;
padding: 0;
margin: 0;
}
/* Basislayout */
.clSiteHeader {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 50px;
line-height: 50px;
margin: 0;
padding: 5px;
font-size: 12pt;
color: white;
background-color: #0000AA;
}
.clNav {
position: absolute;
top: 60px; /* height, padding, border, margin von idSiteHeader beachten */
left: 0;
bottom: 0;
width: 140px;
border-right: 1px solid;
margin: 0;
padding: 5px;
}
.clNav a, a:hover, a:visited, a:active{
display: block;
text-decoration: none;
margin-bottom: 10px;
}
.clNav a:hover {
font-weight: bold;
}
.clContentOuter {
position: absolute;
top: 60px; /* height, padding, border, margin von idSiteHeader beachten */
left: 151px;
right: 0;
bottom: 0;
margin: 0;
padding: 0;
}
.clContent {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
padding: 5px;
}
/* Elemente im Content-Bereich */
.clContentHeader {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 30px;
line-height: 30px;
margin: 0;
padding: 5px;
font-size: 14pt;
text-align: center;
}
.clContentArea {
position: absolute;
top: 40px; /* height, padding, border, margin von idContentHeader beachten */
left: 0;
right: 0;
bottom: 40px; /* height, padding, border, margin von idButtonArea beachten */
margin: 0;
padding: 0px;
overflow-y: auto;
}
.clButtonArea {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 30px;
line-height: 30px;
margin: 0;
padding: 5px;
text-align: center;
background-color: #EEEEEE;
}
/* Links und Submit-Schalter im Buttonbereich gestalten */
.clButtonArea button, a, input[type="submit"] {
margin: 0 5px;
padding: 3px 6px;
font-size: 10pt;
text-decoration: none;
border: 1px solid;
color: black;
background-color: buttonface;
}
.clButtonArea button:disabled {
color: graytext;
}
/* unterschiedliche Kennzeichnungen je nach Bedienung vermeiden */
.clButtonArea a:hover, a:visited, a:active {
color: black;
}
/* Gestaltung von Tabellen */
#idList {
table-layout: fixed;
width: 80%;
border: 1px solid;
border-collapse: collapse;
margin:auto;
}
#idList th {
text-align: left;
padding-left: 6px;
}
#idList th, #idList td {
padding: 3px;
border: 1px solid;
}
/* damit wird jede ungerade Zeile in Tabellen mit einer anderen Hintergrundfarbe ausgegeben */
/* den Effekt nennt man auch "Zebra"-Tables */
tr:nth-of-type(odd) {
background-color:#ccc;
}
#idList tr.clSelected {
background-color: blue;
color: white;
}
/* Gestaltung von Formularen */
/* das Formular nochmals zusätzlich gestalten */
#idForm .clContentArea {
width: 500px;
margin: auto;
}
.clFormRow {
position: relative; /* damit das Element in jedem Fall "positioniert" ist und damit als Bezugspunkt geeignet ist */
height: 25px;
margin-bottom: 10px;
}
.clFormRow label {
position: absolute;
top: 0;
left: 0;
width: 150px;
text-align: right;
}
.clFormRow input {
position: absolute;
top: 0;
left: 160px;
width: 250px;
}
label span.clRequired {
color: red;
content: '*';
}
/* EOF */

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<title>
Bug-Tracker
</title>
<meta charset="UTF-8" />
<style type="text/css">
@import url("/css/main.css");
</style>
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/es.js"></script>
<script type="text/javascript" src="/js/te.js"></script>
<script type="text/javascript" src="/js/tm.js"></script>
<!-- hier zur Verdeutlichung der Strukturierung Aufteilung in mehrere js-Quellen -->
<!-- wird man im produktiven Einsatz zu einer js-Quelle zusammenfassen -->
<script type="text/javascript" src="/js/app.js"></script>
<script type="text/javascript" src="/js/detail.js"></script>
<script type="text/javascript" src="/js/list.js"></script>
<script type="text/javascript" src="/js/nav.js"></script>
</head>
<body>
<header>
<h1 id="idSiteHeader" class="clSiteHeader">
Bug-Tracker // Hoster, Felix // Wansart, Kai
</h1>
</header>
<section id="idContentOuter" class="clContentOuter">
</section>
<nav id="idNav" class="clNav">
</nav>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

105
Praktikum3/bt/static/js/app.js Executable file
View File

@ -0,0 +1,105 @@
// ----------------------------------------------
// Beispiel lit-x
// app.js
// ----------------------------------------------
// Verwendung von jquery, Single-Page / Ajax, Event-Service
// REST-Interface
// ----------------------------------------------
'use strict'
// ----------------------------------------------
// Namensraum einrichten
// ----------------------------------------------
let APP = {};
// ----------------------------------------------
APP.Application_cl = class {
// ----------------------------------------------
constructor () {
this.content_o = null; // das jeweils aktuelle Objekt im Contentbereich
this.nav_o = new APP.Nav_cl();
// this.listSources_o = new APP.ListView_cl('source', '/source/', 'sourceslist.tpl');
// this.detailSources_o = new APP.SourceDetailView_cl('source', '/source/', 'sourcedetail.tpl');
// this.listEvaluated_o = new APP.ListView_cl('evaluated', '/evaluated/', 'evaluatedlist.tpl');
// this.detailEvaluated_o = new APP.DetailView_cl('evaluated', '/evaluated/', 'evaluateddetail.tpl');
// Registrierungen
APP.es_o.subscribe_px(this, 'app');
}
notify_px (self_opl, message_spl, data_apl) {
switch (message_spl) {
case 'app':
switch (data_apl[0]) {
case 'init':
APP.tm_o = new TemplateManager_cl();
break;
case 'templates.loaded':
self_opl.nav_o.render_px();
// Liste Quellen im Content-Bereich anzeigen
// self_opl.setContent_p(self_opl.listSources_o, data_apl[1]);
break;
/* case 'source':
// Liste Quellen im Content-Bereich anzeigen
self_opl.setContent_p(self_opl.listSources_o, data_apl[1]);
break;
case 'source.add':
// (leeres) Detailformular im Content-Bereich anzeigen
self_opl.setContent_p(self_opl.detailSources_o, data_apl[1]);
break;
case 'source.edit':
// Detailformular im Content-Bereich anzeigen
self_opl.setContent_p(self_opl.detailSources_o, data_apl[1]);
break;
case 'evaluated':
// Liste Quellen im Content-Bereich anzeigen
self_opl.setContent_p(self_opl.listEvaluated_o, data_apl[1]);
break;
case 'evaluated.add':
// (leeres) Detailformular im Content-Bereich anzeigen
self_opl.setContent_p(self_opl.detailEvaluated_o, data_apl[1]);
break;
case 'evaluated.edit':
// Detailformular im Content-Bereich anzeigen
self_opl.setContent_p(self_opl.detailEvaluated_o, data_apl[1]);
break;*/
default:
console.warn('[Application_cl] unbekannte app-Notification: '+data_apl[0]);
break;
}
break;
default:
console.warn('[Application_cl] unbekannte Notification: '+message_spl);
break;
}
}
setContent_p (newContent_opl, data_opl) {
if (this.content_o != null) {
if (this.content_o === newContent_opl) { // Achtung: Vergleich auf Identität (===) und nicht nur auf Gleichheit (==)
// wird bereits angezeigt, keine Änderung
} else {
if (this.content_o.canClose_px()) {
this.content_o.close_px();
this.content_o = newContent_opl;
this.content_o.render_px(data_opl);
}
}
} else {
this.content_o = newContent_opl;
this.content_o.render_px(data_opl);
}
}
}
// ----------------------------------------------
$(document).ready(function(){
// ----------------------------------------------
// wird ausgeführt, wenn das Dokument vollständig geladen wurde
APP.es_o = new EventService_cl();
APP.app_o = new APP.Application_cl();
APP.es_o.publish_px('app', ['init', null]);
});
// EOF

142
Praktikum3/bt/static/js/detail.js Executable file
View File

@ -0,0 +1,142 @@
// ----------------------------------------------
// Beispiel lit-x
// detail.js
// ----------------------------------------------
// ----------------------------------------------
APP.DetailView_cl = class {
// ----------------------------------------------
constructor (name_spl, path_spl, template_spl) {
this.name_s = name_spl;
this.path_s = path_spl;
this.template_s = template_spl;
}
canClose_px () {
// Prüfen, ob Formularinhalt verändert wurde
let mod_b = this.isModified_p();
if (mod_b) {
if (confirm("Es gibt nicht gespeicherte Änderungen - verwerfen?")) {
mod_b = false;
}
}
return !mod_b;
}
close_px () {
this.exitHandler_p();
}
render_px (data_opl) {
let path_s;
if (data_opl != null) {
path_s = this.path_s + data_opl;
} else {
path_s = this.path_s + '0';
}
$.ajax({
dataType: "json",
url: path_s,
type: 'GET',
context: this
})
.done(function (data_opl) {
this.doRender_p(data_opl);
this.initHandler_p();
})
.fail(function(jqXHR_opl, textStatus_spl) {
alert( "[Detail] Fehler bei Anforderung: " + textStatus_spl );
});
}
doRender_p (data_opl) {
var markup_s = APP.tm_o.execute_px(this.template_s, data_opl);
$("#idContentOuter").html(markup_s);
this.storeFormContent_p();
}
initHandler_p () {
// Ereignisverarbeitung für das Formular einrichten
$("#idForm").on("click", "button", $.proxy(this.onClickButtons_p, this));
}
exitHandler_p () {
// Ereignisverarbeitung für das Formular aufheben
$("#idForm").off("click", "button", $.proxy(this.onClickButtons_p, this));
}
onClickButtons_p (event_opl) {
var do_b = false;
var path_s;
var action_s = $(event_opl.target).attr("data-action");
switch (action_s) {
case "back":
// Weiterleiten: Liste anfordern
APP.es_o.publish_px('app', [this.name_s, null]);
break;
case "save":
// Formularinhalt prüfen
if (this.isModified_p()) {
if (this.checkContent_p()) {
// kein klassisches submit, es wird auch keine neue Anzeige vorgenommen
var path_s = this.path_s;
var data_s = $("#idForm").serialize();
var type_s = 'PUT';
var id_s = $('#id_s').val();
if (id_s == '') {
type_s = 'POST';
}
$.ajax({
context: this,
dataType: "json",
data: data_s,
url: path_s,
type: type_s
})
.done(function (data_opl) {
// Umwandlung der JSON-Daten vom Server bereits erfolgt
$('#id_s').val(data_opl['id']);
// aktuellen Formularinhalt speichern
// (das Formular wird ja nicht mehr neu geladen!)
this.storeFormContent_p();
alert("Speichern ausgeführt!");
})
.fail(function(jqXHR_opl, textStatus_spl) {
alert( "Fehler bei Anforderung: " + textStatus_spl );
});
} else {
alert("Bitte prüfen Sie die Eingaben in den Formularfeldern!")
}
}
break;
}
// Weiterleitung und Standardbearbeitung unterbinden
event_opl.stopPropagation();
event_opl.preventDefault();
}
isModified_p () {
// Prüfen, ob Formularinhalt verändert wurde
var mod_b = this.FormContentOrg_s != $("#idForm").serialize();
return mod_b;
}
checkContent_p () {
return true;
}
storeFormContent_p () {
this.FormContentOrg_s = $("#idForm").serialize();
}
}
// ----------------------------------------------
APP.SourceDetailView_cl = class extends APP.DetailView_cl {
// ----------------------------------------------
//constructor (name_spl, path_spl, template_spl) {
// super.constructor(name_spl, path_spl, template_spl)
//}
checkContent_p () {
// hier nur zur Demonstration Prüfung des Typs gegen eine Werteliste
// (das realisiert man besser mit einer Liste)
var status_b = true;
var typ_s = $("#typ_s").val();
if ((typ_s != "Typ1") && (typ_s != "Typ2")) {
status_b = false;
}
return status_b;
}
}
// EOF

View File

@ -0,0 +1,104 @@
//------------------------------------------------------------------------------
// Event-Service: asynchroner Nachrichtenaustausch
//------------------------------------------------------------------------------
'use strict'
function each(object_opl, iterator_opl, context_opl) {
for (let key_s in object_opl) {
iterator_opl.call(context_opl, object_opl[key_s], key_s);
}
}
function findAll(object_opl, iterator_opl, context_opl) {
let results_a = [];
each(object_opl, function(value_opl, index_ipl) {
if (iterator_opl.call(context_opl, value_opl, index_ipl))
results_a.push(value_opl);
});
return results_a;
}
function compact(object_opl) {
return findAll(object_opl, function(value_opl) {
return value_opl != null;
});
}
//------------------------------------------------------------------------------
class EventService_cl {
//------------------------------------------------------------------------------
constructor () {
this.queue_o = [];
this.Subscriber_o = {};
window.onhashchange = this.send_p.bind(this);
}
send_p (event_opl) {
// der hash-Wert interessiert hier nicht
// gibt es Elemente in der queue?
if (this.queue_o.length > 0) {
let qentry_o = this.queue_o[0];
qentry_o[0].notify_px.apply(qentry_o[0], [qentry_o[0], qentry_o[1], qentry_o[2]]);
this.queue_o.shift();
}
if (this.queue_o.length > 0) {
let d_o = new Date();
window.location.hash = d_o.getTime();
}
event_opl.preventDefault();
return false;
}
subscribe_px (Subscriber_opl, Message_spl) {
if (Message_spl in this.Subscriber_o) {
// Message bekannt, Liste der Subscriber untersuchen
if (this.Subscriber_o[Message_spl].indexOf(Subscriber_opl) == -1) {
this.Subscriber_o[Message_spl].push(Subscriber_opl);
}
} else {
// Message noch nicht vorhanden, neu eintragen
this.Subscriber_o[Message_spl] = [Subscriber_opl];
}
}
unSubscribe_px (Subscriber_opl, Message_spl) {
if (Message_spl in this.Subscriber_o) {
// Message bekannt, Liste der Subscriber untersuchen
let Entry_a = this.Subscriber_o[Message_spl];
let index_i = Entry_a.indexOf(Subscriber_opl);
if (index_i >= 0) {
// Eintrag entfernen
Entry_a[index_i] = null;
Entry_a = compact(Entry_a); // compact liefert Kopie!
if (Entry_a.length == 0) {
// keine Subscriber mehr, kann entfernt werden
delete this.Subscriber_o[Message_spl];
}
}
} else {
// Message nicht vorhanden, falsche Anforderung
}
}
publish_px (Message_spl, Data_opl) {
let data_s = "<null>";
if ((Data_opl != undefined) && (Data_opl != null)) {
data_s = Data_opl.toString();
}
console.info('es - publish ' + Message_spl + ' ' + data_s);
let that = this;
each(this.Subscriber_o, function (value_apl, key_spl) {
// geliefert wird jeweils ein Wert, hier ein Array, und der Key
if (key_spl == Message_spl) {
// an alle Subscriber weitergeben
each(value_apl, function (entry_opl, index_ipl) {
// geliefert wird hier das Element und der Index
that.queue_o.push([entry_opl, Message_spl, Data_opl]);
let d_o = new Date();
window.location.hash = d_o.getTime();
}, this
);
}
}, this
)
}
}
// EOF

9210
Praktikum3/bt/static/js/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

143
Praktikum3/bt/static/js/list.js Executable file
View File

@ -0,0 +1,143 @@
// ----------------------------------------------
// Beispiel lit-x
// list.js
// ----------------------------------------------
// ----------------------------------------------
APP.ListView_cl = class {
// ----------------------------------------------
constructor (name_spl, path_spl, template_spl) {
this.name_s = name_spl;
this.path_s = path_spl;
this.template_s = template_spl;
}
canClose_px () {
return true;
}
close_px () {
this.exitHandler_p();
}
render_px (data_opl) {
// Parameter data_opl wird hier nicht benötigt
// Anforderung an den Server senden
$.ajax({
dataType: "json",
url: this.path_s,
type: 'GET',
context: this
})
.done(function (data_opl) {
this.doRender_p(data_opl);
this.initHandler_p();
this.initList_p();
})
.fail(function(jqXHR_opl, textStatus_spl) {
alert( "[Liste] Fehler bei Anforderung: " + textStatus_spl );
});
}
doRender_p (data_opl) {
// json-Daten bereits in js-Objekte umgesetzt
var markup_s = APP.tm_o.execute_px(this.template_s, data_opl);
$("#idContentOuter").html(markup_s);
}
initList_p () {
this.rowId_s = ""; // id der selektierten Zeile
// Buttons teilweise deaktivieren, bis eine Zeile ausgewählt wurde
this.disableButtons_p();
}
initHandler_p () {
// Ereignisverarbeitung einrichten
// Ereignisverarbeitung für die Tabelle einrichten
// man beachte: für jquery muss man CSS-Selektoren angeben, also #idList statt einfach nur idList !
$("#idList").on("click", "td", $.proxy(this.onClickList_p, this));
// Ereignisverarbeitung für die Schalter einrichten
$("#idListContent #idButtonArea").on("click", "button", $.proxy(this.onClickButtons_p, this));
}
exitHandler_p () {
// Ereignisverarbeitung aufheben
$("#idList").off("click", "td", $.proxy(this.onClickList_p, this));
$("#idListContent #idButtonArea").off("click", "button", $.proxy(this.onClickButtons_p, this));
}
onClickList_p (event_opl) {
// hier werden nur click-Events auf td-Elemente geliefert
if (this.rowId_s != "") {
$("#"+this.rowId_s).removeClass("clSelected"); // Achtung: jetzt ist nur die Bezeichnung der CSS-Klasse gemeint!
}
this.rowId_s = $(event_opl.target).parent().attr('id');
$("#"+this.rowId_s).addClass("clSelected");
this.enableButtons_p();
}
onClickButtons_p (event_opl) {
var action_s = $(event_opl.target).attr("data-action");
switch (action_s) {
case 'add':
// weiterleiten
APP.es_o.publish_px('app', [this.name_s+'.'+action_s, null]);
break;
case 'edit':
if (this.rowId_s != "") {
// Weiterleiten
APP.es_o.publish_px('app', [this.name_s+'.'+action_s, this.rowId_s]);
} else {
alert("Wählen Sie bitte einen Eintrag in der Tabelle aus!");
}
break;
case 'delete':
if (this.rowId_s != "") {
if (confirm("Soll der Datensatz gelöscht werden?")) {
// Id der selektierten Tabellenzeile anhängen
var path_s = this.path_s + this.rowId_s;
$.ajax({
context: this,
dataType: "json",
url: path_s,
type: 'DELETE'
})
.done(function (data_opl) {
// Auswertung der Rückmeldung
// der umständliche Weg:
// - Liste neu darstellen, hier vereinfacht durch neue Anforderung
//APP.es_o.publish_px('list', ['refresh', null]);
// einfacher mit direktem Entfernen der Zeile aus der Tabelle
// (id des gelöschten Eintrags wird in der Antwort geliefert)
$('#'+data_opl['id']).remove();
this.initList_p();
})
.fail(function(jqXHR_opl, textStatus_spl) {
alert( "[Liste] Fehler bei Anforderung: " + textStatus_spl );
});
}
} else {
alert("Wählen Sie bitte einen Eintrag in der Tabelle aus!");
}
break;
}
// Weiterleitung und Standardbearbeitung unterbinden
event_opl.stopPropagation();
event_opl.preventDefault();
}
// stärkere Einschränkung mit #idListContent notwendig, damit nicht die Buttons auf dem
// Formular ebenfalls geändert werden
enableButtons_p () {
$("#idListContent #idButtonArea button").each(function () {
if ($(this).attr("data-action") != "add") {
$(this).prop("disabled", false);
}
});
}
disableButtons_p () {
$("#idListContent #idButtonArea button").each(function () {
if ($(this).attr("data-action") != "add") {
$(this).prop("disabled", true);
}
});
}
}
// EOF

44
Praktikum3/bt/static/js/nav.js Executable file
View File

@ -0,0 +1,44 @@
// ----------------------------------------------
// Beispiel lit-x
// nav.js
// ----------------------------------------------
// ----------------------------------------------
APP.Nav_cl = class {
// ----------------------------------------------
constructor () {
}
render_px () {
// zur Vereinfachung hier direkt den Inhalt des
// Navigationsbereichs anzeigen und die Ereignisverarbeitung einrichten
$.ajax({
dataType: "json",
url: '/navigation',
type: 'GET',
context: this
})
.done(function (data_opl) {
this.doRender_p(data_opl);
this.initHandler_p();
})
.fail(function(jqXHR_opl, textStatus_spl) {
alert( "[Nav_cl] Fehler bei Anforderung: " + textStatus_spl );
});
}
doRender_p (data_opl) {
let markup_s = APP.tm_o.execute_px('nav.tpl', data_opl);
$('#idNav').html(markup_s);
}
initHandler_p () {
// Ereignisverarbeitung für die Schalter einrichten
$("#idNav").on("click", "a", function (event_opl) {
var action_s = $(event_opl.target).attr('data-action');
// Weiterleitung! Das Nav-Objekt ist nicht für die Bearbeitung direkt verantwortlich
APP.es_o.publish_px('app', [action_s, null]);
// Weiterleitung und Standardbearbeitung unterbinden
event_opl.stopPropagation();
event_opl.preventDefault();
});
}
}
// EOF

266
Praktikum3/bt/static/js/te.js Executable file
View File

@ -0,0 +1,266 @@
//------------------------------------------------------------------------------
// Template-Engine
//------------------------------------------------------------------------------
'use strict'
class Generator_cl {
constructor () {
this.reset_px();
}
reset_px () {
this.code_a = ['var result_a = [];\n'];
}
write_px (text_spl) {
// Escape-Zeichen bei Strings ergänzen
var text_s = text_spl.replace(/"/g, '\\"');
text_s = text_s.replace(/'/g, "\\'");
this.code_a.push('result_a.push("' + text_s + '");\n');
}
code_px (code_spl) {
if (code_spl.startsWith('if')) {
this.code_a.push('if (' + code_spl.substr(2) + ') {\n');
} else if (code_spl.startsWith('else')) {
this.code_a.push('} else {\n');
} else if (code_spl.startsWith('endif')) {
this.code_a.push('}\n');
} else if (code_spl.startsWith('for')) {
this.code_a.push('for (' + code_spl.substr(3) + ') {\n');
} else if (code_spl.startsWith('endfor')) {
this.code_a.push('}\n');
} else {
this.code_a.push(code_spl + '\n');
}
}
substitute_px (subst_spl) {
let value_s = subst_spl == null ? '' : String(subst_spl);
this.code_a.push('result_a.push(' + value_s + ');\n');
}
generate_px () {
var result_s = this.code_a.join('') + ' return result_a.join("");';
var f_o = new Function ('context', result_s);
return f_o;
}
}
class TemplateCompiler_cl {
constructor () {
this.gen_o = new Generator_cl();
this.reset_px();
}
reset_px () {
this.gen_o.reset_px();
this.preservePreWS_b = false;
this.preservePostWS_b = false;
}
setPreWS_px (on_bpl) {
if ((on_bpl == undefined) || (on_bpl == false)) {
this.preservePreWS_b = false;
} else {
this.preservePreWS_b = true;
}
}
setPostWS_px (on_bpl) {
if ((on_bpl == undefined) || (on_bpl == false)) {
this.preservePostWS_b = false;
} else {
this.preservePostWS_b = true;
}
}
compile_px (source_spl) {
var state_i = 0;
var pos_i = 0;
var len_i = source_spl.length;
var text_s = '';
var code_s = '';
var subst_s = '';
this.gen_o.reset_px();
var doubletest_f = function (char_spl) {
var status_b = false;
if ((pos_i + 1) < len_i) {
if ((source_spl[pos_i] == char_spl) && (source_spl[pos_i+1] == char_spl)) {
status_b = true;
}
}
return status_b;
}
while (pos_i < len_i) {
switch (state_i) {
case 0:
// outside
if (source_spl[pos_i] == '@') { // ECMA 5!
if (doubletest_f('@') == false) {
state_i = 2;
code_s = '';
} else {
// als normales Zeichen verarbeiten, ein Zeichen überlesen
state_i = 1;
text_s = '@';
pos_i++;
}
} else if (source_spl[pos_i] == '#') {
if (doubletest_f('#') == false) {
state_i = 3;
subst_s = '';
} else {
// als normales Zeichen verarbeiten, ein Zeichen überlesen
state_i = 1;
text_s = '#';
pos_i++;
}
} else if ((source_spl[pos_i] == ' ') || (source_spl[pos_i] == '\t')) {
state_i = 4;
text_s = '';
pos_i--; // Zeichen erneut verarbeiten
} else {
state_i = 1;
text_s = '';
pos_i--; // Zeichen erneut verarbeiten
}
break;
case 1:
// inText
if (source_spl[pos_i] == '@') {
if (doubletest_f('@') == false) {
// Textende, neuer Code
state_i = 0;
this.gen_o.write_px(text_s);
pos_i--; // Zeichen erneut verarbeiten
} else {
// als normales Zeichen verarbeiten, ein Zeichen überlesen
text_s += '@';
pos_i++;
}
} else if (source_spl[pos_i] == '#') {
if (doubletest_f('#') == false) {
// Textende, neue Substitution
state_i = 0;
this.gen_o.write_px(text_s);
pos_i--; // Zeichen erneut verarbeiten
// Textende, neuer Code
} else {
// als normales Zeichen verarbeiten, ein Zeichen überlesen
text_s += '#';
pos_i++;
}
} else if ((source_spl[pos_i] == ' ') || (source_spl[pos_i] == '\t')) {
// Textende
state_i = 0;
this.gen_o.write_px(text_s);
pos_i--; // Zeichen erneut verarbeiten
} else {
// sammeln
if ((source_spl[pos_i] != '\n') && (source_spl[pos_i] != '\r')) {
text_s += source_spl[pos_i];
} else if (source_spl[pos_i] == '\n') {
text_s += '\\n';
} else {
text_s += '\\r';
}
}
break;
case 2:
// inCode
if (source_spl[pos_i] == '@') {
if (doubletest_f('@') == false) {
// zu Ende, erzeugen
this.gen_o.code_px(code_s);
state_i = 5; //0
} else {
// als normales Zeichen verarbeiten, ein Zeichen überlesen
code_s += '@';
pos_i++;
}
} else {
// sammeln
code_s += source_spl[pos_i];
}
break;
case 3:
// inSubst
// Verdopplung # hier nicht zulässig!
if (source_spl[pos_i] == '#') {
// zu Ende, erzeugen
this.gen_o.substitute_px(subst_s);
state_i = 0;
} else {
// sammeln
subst_s += source_spl[pos_i];
}
break;
case 4:
// pre-code-whitespace
switch (source_spl[pos_i]) {
case ' ':
case '\t':
// sammeln
text_s += source_spl[pos_i];
break;
default:
state_i = 0;
if (source_spl[pos_i] != '@') {
this.gen_o.write_px(text_s);
} else {
if (doubletest_f('@') == false) {
// Whitespace vor Code-Beginn erkannt
if (this.preservePreWS_b == true) {
// trotzdem ausgeben
this.gen_o.write_px(text_s);
}
} // ansonsten wie normales Zeichen behandeln
}
pos_i--; // Zeichen erneut verarbeiten
}
break;
case 5:
// post-code-whitespace
switch (source_spl[pos_i]) {
case '\n':
text_s += '\\n';
state_i = 0;
break;
case '\r':
text_s += '\\r';
state_i = 0;
break;
case ' ':
case '\t':
// ggf. sammeln
text_s += source_spl[pos_i];
break;
default:
// Whitespace nach Code erkannt
if (this.preservePostWS_b == true) {
// trotzdem ausgeben
this.gen_o.write_px(text_s);
}
state_i = 0;
pos_i--; // Zeichen erneut verarbeiten
}
break;
}
pos_i++;
}
// welcher Zustand liegt abschließend vor?
if (state_i == 1) {
this.gen_o.write_px(text_s);
} else if (state_i == 2) {
this.gen_o.code_px(code_s);
} else if (state_i == 3) {
this.gen_o.substitute_px(subst_s);
} else if (state_i == 4) {
if (this.preservePreWS_b == true) {
this.gen_o.write_px(text_s);
}
} else if (state_i == 5) {
if (this.preservePostWS_b == true) {
this.gen_o.write_px(text_s);
}
}
return this.gen_o.generate_px();
}
}
// EOF

61
Praktikum3/bt/static/js/tm.js Executable file
View File

@ -0,0 +1,61 @@
//------------------------------------------------------------------------------
// Template-Manager
// - Laden und Bereitstellen von Template-Quellen
//------------------------------------------------------------------------------
// depends-on:
// jquery
// te
//------------------------------------------------------------------------------
'use strict'
class TemplateManager_cl {
constructor () {
this.templates_o = {};
this.compiled_o = {};
this.teCompiler_o = new TemplateCompiler_cl();
// Templates als Ressource anfordern und speichern
var path_s = "/templates/";
$.ajax({
dataType: "json",
url: path_s,
type: 'GET',
context: this
})
.done(function (data_opl) {
this.templates_o = data_opl['templates'];
// Benachrichtigung senden
APP.es_o.publish_px('app', ['templates.loaded', null]);
})
.fail(function(jqXHR_opl, textStatus_spl) {
alert( "[tm] Fehler bei Anforderung: " + textStatus_spl );
});
}
get_px (name_spl) {
if (name_spl in this.templates_o) {
return this.templates_o[name_spl];
} else {
return null;
}
}
execute_px (name_spl, data_opl) {
var compiled_o = null;
if (name_spl in this.compiled_o) {
compiled_o = this.compiled_o[name_spl];
} else {
// Übersetzen und ausführen
if (name_spl in this.templates_o) {
this.teCompiler_o.reset_px();
compiled_o = this.teCompiler_o.compile_px(this.templates_o[name_spl]);
this.compiled_o[name_spl] = compiled_o;
}
}
if (compiled_o != null) {
return compiled_o(data_opl);
} else {
return null;
}
}
}
// EOF

View File

@ -0,0 +1,28 @@
<!-- Template -->
<form id="idForm" class="clContent">
<h2 id="idContentHeader" class="clContentHeader">
Literaturauswertung / Formular
</h2>
<div id="idContentArea" class="clContentArea">
<input type="hidden" value="#context.data.id#" id="id_s" name="id_s" />
<div class="clFormRow">
<label for="title_s">Titel <span class="clRequired"></span></label>
<input type="text" value="#context.data.title#" id="title_s" name="title_s" autofocus required />
</div>
<div class="clFormRow">
<label for="author_s">Autor <span class="clRequired"></span></label>
<input type="text" value="#context.data.author#" id="author_s" name="author_s" required />
</div>
<div class="clFormRow">
<label for="evalyear_s">Jahr de Auswertung</label>
<input type="url" value="#context.data.evalyear#" id="evalyear_s" name="evalyear_s" />
</div>
</div>
<div id="idButtonArea" class="clButtonArea">
<button data-action="back" class="clButton">Zurück</button>
<button data-action="save" class="clButton">Speichern</button>
</div>
</form>
<!-- EOF -->

View File

@ -0,0 +1,26 @@
<!-- Template -->
<!-- evaluated -->
<div id="idListContent" class="clContent">
<h2 id="idContentHeader" class="clContentHeader">
Literaturauswertung
</h2>
<div id="idContentArea" class="clContentArea">
<table id="idList">
<tr class="listheader"><th>Titel</th><th>Autor</th><th>Auswertungsjahr</th></tr>
@var rows_o = context['data'];@
@for var key_s in rows_o@
<tr id='#key_s#'>
@var row_o = rows_o[key_s];@
<td>#row_o['title']#</td><td>#row_o['author']#</td><td>#row_o['evalyear']#</td>
</tr>
@endfor@
</table>
</div>
<div id="idButtonArea" class="clButtonArea">
<button data-action="add" class="clButton">Hinzufügen</button>
<button data-action="edit" class="clButton">Bearbeiten</button>
<button data-action="delete" class="clButton">Löschen</button>
</div>
</div>
<!-- EOF -->

View File

@ -0,0 +1,6 @@
<!-- Template -->
@let loop_i;@
@for loop_i=0; loop_i < context.length; loop_i++@
<a href="##" data-action="#context[loop_i].action#">#context[loop_i].text#</a>
@endfor@

View File

@ -0,0 +1,28 @@
<!-- Template -->
<form id="idForm" class="clContent">
<h2 id="idContentHeader" class="clContentHeader">
Literatur- / Quellenverzeichnis / Formular
</h2>
<div id="idContentArea" class="clContentArea">
<input type="hidden" value="#context.data.id#" id="id_s" name="id_s" />
<div class="clFormRow">
<label for="name_s">Name <span class="clRequired"></span></label>
<input type="text" value="#context.data.name#" id="name_s" name="name_s" autofocus required />
</div>
<div class="clFormRow">
<label for="typ_s">Typ <span class="clRequired"></span></label>
<input type="text" value="#context.data.typ#" id="typ_s" name="typ_s" required />
</div>
<div class="clFormRow">
<label for="referenz_s">Referenz</label>
<input type="url" value="#context.data.referenz#" id="referenz_s" name="referenz_s" />
</div>
</div>
<div id="idButtonArea" class="clButtonArea">
<button data-action="back" class="clButton">Zurück</button>
<button data-action="save" class="clButton">Speichern</button>
</div>
</form>
<!-- EOF -->

View File

@ -0,0 +1,26 @@
<!-- Template -->
<!-- sources -->
<div id="idListContent" class="clContent">
<h2 id="idContentHeader" class="clContentHeader">
Literatur- / Quellenverzeichnis
</h2>
<div id="idContentArea" class="clContentArea">
<table id="idList">
<tr class="listheader"><th>Name</th><th>Typ</th><th>Referenz</th></tr>
@var rows_o = context['data'];@
@for var key_s in rows_o@
<tr id='#key_s#'>
@var row_o = rows_o[key_s];@
<td>#row_o['name']#</td><td>#row_o['typ']#</td><td>#row_o['referenz']#</td>
</tr>
@endfor@
</table>
</div>
<div id="idButtonArea" class="clButtonArea">
<button data-action="add" class="clButton">Hinzufügen</button>
<button data-action="edit" class="clButton">Bearbeiten</button>
<button data-action="delete" class="clButton">Löschen</button>
</div>
</div>
<!-- EOF -->

BIN
Praktikum3/bt/test/.DS_Store vendored Normal file

Binary file not shown.

4
Praktikum3/bt/test/get.sh Executable file
View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080

View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080/fehler

View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080

View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080

View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080

View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080/projekt

View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080

View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080

View File

@ -0,0 +1,4 @@
curl \
--request GET \
-D- \
http://localhost:8080

BIN
Praktikum3/lit-x/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
# coding: utf-8
# hier können Paket-Initialisierungen eingetragen werden

View File

@ -0,0 +1,348 @@
# coding: utf-8
import json
import cherrypy
from .database import SourceDatabase_cl, EvaluatedDatabase_cl
# Method-Dispatching!
# Übersicht Anforderungen / Methoden
"""
Anforderung GET POST PUT DELETE
----------------------------------------------------------------
/ Liste - - -
Literatur
liefern
/source Liste - - -
Literatur
liefern
/evaluated Liste - - -
Auswertungen
liefern
/source/0 Dokument Dokument - -
mit id=0 anlegen
liefern
(Vorgabe-Werte)
/evaluated/0 Dokument Dokument - -
mit id=0 anlegen
liefern
(Vorgabe-Werte)
/source/{id} Dokument - Dokument Dokument
mit {id} ändern löschen
liefern
(Literatur)
/evaluated/{id} Dokument - Dokument Dokument
mit {id} ändern löschen
liefern
(Auswertungen)
id > 0 !
"""
#-------------------------------------------------------
def adjustId_p(id_spl, data_opl):
#-------------------------------------------------------
if id_spl == None:
data_opl['id'] = ''
elif id_spl == '':
data_opl['id'] = ''
elif id_spl == '0':
data_opl['id'] = ''
else:
data_opl['id'] = id_spl
return data_opl
#----------------------------------------------------------
class Source_cl(object):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
self.db_o = SourceDatabase_cl()
#-------------------------------------------------------
def GET(self, id):
#-------------------------------------------------------
retVal_o = {
'data': None
}
if id == None:
# Anforderung der Liste
retVal_o['data'] = self.db_o.read_px()
else:
# Anforderung eines Dokuments
data_o = self.db_o.read_px(id)
if data_o != None:
retVal_o['data'] = adjustId_p(id, data_o)
return retVal_o
#-------------------------------------------------------
def POST(self, data_opl):
#-------------------------------------------------------
retVal_o = {
'id': None
}
# data_opl: Dictionary mit den gelieferten key-value-Paaren
data_o = {
'name': data_opl["name_s"],
'typ': data_opl["typ_s"],
'referenz': data_opl["referenz_s"]
}
# Create-Operation
id_s = self.db_o.create_px(data_o)
retVal_o['id'] = id_s
return retVal_o
#-------------------------------------------------------
def PUT(self, data_opl):
#-------------------------------------------------------
# Sichern der Daten: jetzt wird keine vollständige Seite
# zurückgeliefert, sondern nur noch die Information, ob das
# Speichern erfolgreich war
retVal_o = {
'id': None
}
# data_opl: Dictionary mit den gelieferten key-value-Paaren
id_s = data_opl["id_s"]
data_o = {
'name': data_opl["name_s"],
'typ': data_opl["typ_s"],
'referenz': data_opl["referenz_s"]
}
# Update-Operation
retVal_o['id'] = id_s
if self.db_o.update_px(id_s, data_o):
pass
else:
retVal_o['id'] = None
return retVal_o
#-------------------------------------------------------
def DELETE(self, id):
#-------------------------------------------------------
# Eintrag löschen, nur noch Rückmeldung liefern
retVal_o = {
'id': id
}
if self.db_o.delete_px(id):
pass
else:
retVal_o['id'] = None
return retVal_o
#----------------------------------------------------------
class Evaluated_cl(object):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
self.db_o = EvaluatedDatabase_cl()
#-------------------------------------------------------
def GET(self, id):
#-------------------------------------------------------
retVal_o = {
'data': None
}
if id == None:
# Anforderung der Liste
retVal_o['data'] = self.db_o.read_px()
else:
# Anforderung eines Dokuments
data_o = self.db_o.read_px(id)
if data_o != None:
retVal_o['data'] = adjustId_p(id, data_o)
return retVal_o
#-------------------------------------------------------
def POST(self, data_opl):
#-------------------------------------------------------
retVal_o = {
'id': None
}
# data_opl: Dictionary mit den gelieferten key-value-Paaren
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
data_o = {
'title': data_opl["title_s"],
'author': data_opl["author_s"],
'evalyear': data_opl["evalyear_s"]
}
# Create-Operation
id_s = self.db_o.create_px(data_o)
retVal_o['id'] = id_s
return retVal_o
#-------------------------------------------------------
def PUT(self, data_opl):
#-------------------------------------------------------
# Sichern der Daten: jetzt wird keine vollständige Seite
# zurückgeliefert, sondern nur noch die Information, ob das
# Speichern erfolgreich war
retVal_o = {
'id': None
}
# data_opl: Dictionary mit den gelieferten key-value-Paaren
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
id_s = data_opl["id_s"]
data_o = {
'title': data_opl["title_s"],
'author': data_opl["author_s"],
'evalyear': data_opl["evalyear_s"]
}
# Update-Operation
retVal_o['id'] = id_s
if self.db_o.update_px(id_s, data_o):
pass
else:
retVal_o['id'] = None
return retVal_o
#-------------------------------------------------------
def DELETE(self, id):
#-------------------------------------------------------
# Eintrag löschen, nur noch Rückmeldung liefern
retVal_o = {
'id': id
}
if self.db_o.delete_px(id):
pass
else:
retVal_o['id'] = None
return retVal_o
#----------------------------------------------------------
class Application_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
self.handler_o = {
'source': Source_cl(),
'evaluated': Evaluated_cl()
}
# es wird keine index-Methode vorgesehen, weil stattdessen
# die Webseite index.html ausgeliefert wird (siehe Konfiguration)
#-------------------------------------------------------
def GET(self, path_spl = 'source', id=None):
#-------------------------------------------------------
retVal_o = {
'data': None
}
if path_spl in self.handler_o:
retVal_o = self.handler_o[path_spl].GET(id)
if retVal_o['data'] == None:
cherrypy.response.status = 404
return json.dumps(retVal_o)
#-------------------------------------------------------
def POST(self, path_spl = 'source', **data_opl):
#-------------------------------------------------------
retVal_o = {
'id': None
}
# data_opl: Dictionary mit den gelieferten key-value-Paaren
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
if path_spl in self.handler_o:
retVal_o = self.handler_o[path_spl].POST(data_opl)
if retVal_o['id'] == None:
cherrypy.response.status = 409
return json.dumps(retVal_o)
#-------------------------------------------------------
def PUT(self, path_spl = 'source', **data_opl):
#-------------------------------------------------------
# Sichern der Daten: jetzt wird keine vollständige Seite
# zurückgeliefert, sondern nur noch die Information, ob das
# Speichern erfolgreich war
retVal_o = {
'id': None
}
# data_opl: Dictionary mit den gelieferten key-value-Paaren
# hier müsste man prüfen, ob die Daten korrekt vorliegen!
if path_spl in self.handler_o:
retVal_o = self.handler_o[path_spl].PUT(data_opl)
if retVal_o['id'] == None:
cherrypy.response.status = 404
return json.dumps(retVal_o)
#-------------------------------------------------------
def DELETE(self, path_spl = 'source', id=None):
#-------------------------------------------------------
# Eintrag löschen, nur noch Rückmeldung liefern
retVal_o = {
'id': id
}
if path_spl in self.handler_o:
retVal_o = self.handler_o[path_spl].DELETE(id)
if retVal_o['id'] == None:
cherrypy.response.status = 404
return json.dumps(retVal_o)
#-------------------------------------------------------
def default(self, *arguments, **kwargs):
#-------------------------------------------------------
msg_s = "unbekannte Anforderung: " + \
str(arguments) + \
' ' + \
str(kwargs)
raise cherrypy.HTTPError(404, msg_s)
# EOF

162
Praktikum3/lit-x/app/database.py Executable file
View File

@ -0,0 +1,162 @@
# coding: utf-8
import os
import os.path
import codecs
import json
#----------------------------------------------------------
class Database_cl(object):
#----------------------------------------------------------
# Daten in dieser Variante dauerhaft (persistent) speichern
# dazu jedes Element in einer Datei, die entsprechend der id benannt ist, speichern
# alle Elemente werden zur Laufzeit des Servers zur Vereinfachung auch im
# Hauptspeicher abgelegt
# die nächste zu vergebende Id wird ebenfalls dauerhaft gespeichert
# zur Vereinfachung wird hier fest vorgegebenen, dass sich die Daten
# im Unterverzeichnis "data/<type>" befinden (siehe Konstruktor)
# es wird ferner angenommen, dass die Datei "data/<type>/maxid.dat" bereits existiert
# und als einzigen Eintrag den aktuellen Wert der maximalen Id enthält
#-------------------------------------------------------
def __init__(self, type_spl):
#-------------------------------------------------------
self.type_s = type_spl
self.path_s = os.path.join('data', type_spl)
self.data_o = {}
self.readData_p()
#-------------------------------------------------------
def create_px(self, data_opl):
#-------------------------------------------------------
# Überprüfung der Datenn müsste ergänzt werden!
id_s = self.nextId_p()
# Datei erzeugen
file_o = codecs.open(os.path.join(self.path_s , id_s+'.dat'), 'w', 'utf-8')
file_o.write(json.dumps(data_opl, indent=3, ensure_ascii=True))
file_o.close()
self.data_o[id_s] = data_opl
return id_s
#-------------------------------------------------------
def read_px(self, id_spl = None):
#-------------------------------------------------------
# hier zur Vereinfachung:
# Aufruf ohne id: alle Einträge liefern
data_o = None
if id_spl == None:
data_o = self.data_o
elif id_spl == '0':
data_o = self.getDefault_px()
else:
if id_spl in self.data_o:
data_o = self.data_o[id_spl]
return data_o
#-------------------------------------------------------
def update_px(self, id_spl, data_opl):
#-------------------------------------------------------
# Überprüfung der Daten müsste ergänzt werden!
status_b = False
if id_spl in self.data_o:
# Datei aktualisieren
file_o = codecs.open(os.path.join(self.path_s, id_spl+'.dat'), 'w', 'utf-8')
file_o.write(json.dumps(data_opl, indent=3, ensure_ascii=True))
file_o.close()
self.data_o[id_spl] = data_opl
status_b = True
return status_b
#-------------------------------------------------------
def delete_px(self, id_spl):
#-------------------------------------------------------
status_b = False
if id_spl in self.data_o:
# Datei entfernen
os.remove(os.path.join(self.path_s, id_spl+'.dat'))
del self.data_o[id_spl]
status_b = True
return status_b
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
# sollte überschrieben werden!
return {}
#-------------------------------------------------------
def readData_p(self):
#-------------------------------------------------------
files_a = os.listdir(self.path_s)
for fileName_s in files_a:
if fileName_s.endswith('.dat') and fileName_s != 'maxid.dat':
file_o = codecs.open(os.path.join(self.path_s, fileName_s), 'rU', 'utf-8')
content_s = file_o.read()
file_o.close()
id_s = fileName_s[:-4]
self.data_o[id_s] = json.loads(content_s)
#-------------------------------------------------------
def nextId_p(self):
#-------------------------------------------------------
file_o = open(os.path.join(self.path_s, 'maxid.dat'), 'r+')
maxId_s = file_o.read()
maxId_s = str(int(maxId_s)+1)
file_o.seek(0)
file_o.write(maxId_s)
file_o.close()
return maxId_s
#----------------------------------------------------------
class SourceDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('source')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'name': '',
'typ': 'Typ1',
'referenz': ''
}
#----------------------------------------------------------
class EvaluatedDatabase_cl(Database_cl):
#----------------------------------------------------------
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
super().__init__('evaluated')
#-------------------------------------------------------
def getDefault_px(self):
#-------------------------------------------------------
return {
'title': '',
'author': '',
'evalyear': ''
}
# EOF

View File

@ -0,0 +1,42 @@
# coding: utf-8
import json
import cherrypy
# Method-Dispatching!
# Übersicht Anforderungen / Methoden
# (beachte: / relativ zu /navigation, siehe Konfiguration Server!)
"""
Anforderung GET PUT POST DELETE
----------------------------------------------------------------
/ Nav-Entries - - -
"""
#----------------------------------------------------------
class Navigation_cl(object):
#----------------------------------------------------------
exposed = True # gilt für alle Methoden
#-------------------------------------------------------
def __init__(self):
#-------------------------------------------------------
pass
#-------------------------------------------------------
def GET(self):
#-------------------------------------------------------
# Hinweis: könnte man auch aus einer Datei einlesen
retVal_o = [
{'action': 'source' , 'text': 'Quellen'},
{'action': 'evaluated', 'text': 'Ausgewertet'}
]
return json.dumps(retVal_o)
# EOF

Some files were not shown because too many files have changed in this diff Show More