complete rewrite of lodur form handling
This commit is contained in:
parent
e7c8ba7e9f
commit
6b93ae3dfa
|
@ -41,6 +41,7 @@ Einsätze!
|
|||
* Documentation
|
||||
* IMAP idle
|
||||
* Display PDF on Dashboard
|
||||
* Send statistics to InfluxDB
|
||||
* Webapp to see what's going on
|
||||
* Get as many data out of the PDFs as possible
|
||||
* Simple webform to fill-in missing data (skipping Lodur completely)
|
||||
|
|
226
lodur.py
226
lodur.py
|
@ -6,6 +6,7 @@ import re
|
|||
import logging
|
||||
from datetime import datetime
|
||||
import mechanicalsoup
|
||||
from webdav import WebDav
|
||||
|
||||
class Lodur:
|
||||
""" Lodur """
|
||||
|
@ -35,7 +36,7 @@ class Lodur:
|
|||
self.logger.fatal('Login to Lodur failed - exiting')
|
||||
raise SystemExit(1)
|
||||
|
||||
def einsatzprotokoll(self, lodur_id, pdf_data):
|
||||
def einsatzprotokoll(self, f_id, pdf_data, webdav_client):
|
||||
""" Prepare Einsatzprotokoll to be sent to Lodur
|
||||
TODO This doesn't work as Lodur doesn't add the values directly in to HTML but
|
||||
uses JavaScript to dynamically populate the form data.
|
||||
|
@ -45,51 +46,52 @@ class Lodur:
|
|||
to update the form in Lodur
|
||||
"""
|
||||
|
||||
# when PDF parsing fails, pdf_data is false. fill with tbd when this happens
|
||||
if pdf_data:
|
||||
zh_alarmierung = datetime.strptime(
|
||||
pdf_data['disposition'],
|
||||
'%H:%M',
|
||||
)
|
||||
zh_fw_ausg = datetime.strptime(
|
||||
pdf_data['ausgerueckt'],
|
||||
'%H:%M',
|
||||
)
|
||||
zh_am_schad = datetime.strptime(
|
||||
pdf_data['anort'],
|
||||
'%H:%M',
|
||||
)
|
||||
# check if data is already sent to lodur - data contains lodur_id
|
||||
lodur_data = webdav_client.get_lodur_data(f_id)
|
||||
|
||||
if lodur_data:
|
||||
# einsatz available in Lodur - updating existing entry
|
||||
self.logger.info('[%s] Lodur data found - updating entry', f_id)
|
||||
|
||||
# when PDF parsing fails, pdf_data is false. fill with tbd when this happens
|
||||
if pdf_data:
|
||||
zh_fw_ausg = datetime.strptime(
|
||||
pdf_data['ausgerueckt'],
|
||||
'%H:%M',
|
||||
)
|
||||
zh_am_schad = datetime.strptime(
|
||||
pdf_data['anort'],
|
||||
'%H:%M',
|
||||
)
|
||||
else:
|
||||
# Do nothing when no PDF data - we don't have anything to do then
|
||||
self.logger.error('[%s] No PDF data found - filling in dummy data', f_id)
|
||||
zh_fw_ausg = datetime.now()
|
||||
zh_am_schad = datetime.now()
|
||||
|
||||
# Complement existing form data
|
||||
self.logger.info('[%s] Preparing form data for Einsatzprotokoll', f_id)
|
||||
lodur_data['zh_fw_ausg_h'] = zh_fw_ausg.hour # 13. FW ausgerückt
|
||||
lodur_data['zh_fw_ausg_m'] = zh_fw_ausg.minute # 13. FW ausgerückt
|
||||
lodur_data['zh_am_schad_h'] = zh_am_schad.hour # 14. Am Schadenplatz
|
||||
lodur_data['zh_am_schad_m'] = zh_am_schad.minute # 14. Am Schadenplatz
|
||||
# The following fields are currently unknown as PDF parsing is hard for these
|
||||
#lodur_data['zh_fw_einge_h'] = UNKNOWN, # 15. FW eingerückt
|
||||
#lodur_data['zh_fw_einge_m'] = 'UNKNOWN' # 15. FW eingerückt
|
||||
#lodur_data['eins_erst_h'] = 'UNKNOWN' # 16. Einsatzbereitschaft erstellt
|
||||
#lodur_data['eins_erst_m'] = 'UNKNOWN' # 16. Einsatzbereitschaft erstellt
|
||||
|
||||
# Submit the form
|
||||
self.submit_form_einsatzrapport(lodur_data)
|
||||
else:
|
||||
# Do nothing when no PDF data - we don't have anything to do then
|
||||
# einsatz not available in Lodur
|
||||
self.logger.error('[%s] No lodur_id found')
|
||||
return False
|
||||
|
||||
# Prepare the form
|
||||
self.browser.open(self.url + '?modul=36&what=144&edit=1&event=' + lodur_id)
|
||||
self.browser.select_form('#einsatzrapport_main_form')
|
||||
print(self.browser.get_current_form().print_summary())
|
||||
def einsatzrapport(self, f_id, pdf_data, webdav_client):
|
||||
""" Prepare form in module 36 - Einsatzrapport """
|
||||
|
||||
# Fill in form data
|
||||
self.browser['zh_alarmierung_h'] = zh_alarmierung.hour # 12. Alarmierung
|
||||
self.browser['zh_alarmierung_m'] = zh_alarmierung.minute # 12. Alarmierung
|
||||
self.browser['zh_fw_ausg_h'] = zh_fw_ausg.hour # 13. FW ausgerückt
|
||||
self.browser['zh_fw_ausg_m'] = zh_fw_ausg.minute # 13. FW ausgerückt
|
||||
self.browser['zh_am_schad_h'] = zh_am_schad.hour # 14. Am Schadenplatz
|
||||
self.browser['zh_am_schad_m'] = zh_am_schad.minute # 14. Am Schadenplatz
|
||||
# The following fields are currently unknown as PDF parsing is hard for these
|
||||
#self.browser['zh_fw_einge_h'] = 'UNKNOWN' # 15. FW eingerückt
|
||||
#self.browser['zh_fw_einge_m'] = 'UNKNOWN' # 15. FW eingerückt
|
||||
#self.browser['eins_erst_h'] = 'UNKNOWN' # 16. Einsatzbereitschaft erstellt
|
||||
#self.browser['eins_erst_m'] = 'UNKNOWN' # 16. Einsatzbereitschaft erstellt
|
||||
|
||||
# Submit the form
|
||||
#print(self.browser.get_current_form().print_summary())
|
||||
self.logger.info('Submitting form Einsatzrapport')
|
||||
self.browser.submit_selected()
|
||||
|
||||
def einsatzrapport(self, f_id, pdf_data):
|
||||
""" Form in module 36 - Einsatzrapport """
|
||||
|
||||
# when PDF parsing fails, pdf_data is false. fill with tbd when this happens
|
||||
# when PDF parsing fails, pdf_data is false. fill with placeholder when this happens
|
||||
if pdf_data:
|
||||
date = datetime.strptime(
|
||||
pdf_data['datum'],
|
||||
|
@ -107,58 +109,122 @@ class Lodur:
|
|||
eins_ereig = 'UNKNOWN'
|
||||
adr = 'UNKNOWN'
|
||||
|
||||
# Prepare the form
|
||||
self.browser.open(self.url + '?modul=36')
|
||||
self.browser.select_form('#einsatzrapport_main_form')
|
||||
|
||||
# Fill in form data
|
||||
self.browser['e_r_num'] = f_id # 01. Einsatzrapportnummer
|
||||
self.browser['eins_stat_kantone'] = '1' # 02. Einsatzart FKS
|
||||
self.browser['emergency_concept_id'] = '2' # 03. Verrechnungsart
|
||||
self.browser['ver_sart'] = 'ab' # 03. Verrechnungsart internal: ab, th, uh, ak, tt
|
||||
self.browser['dtv_d'] = str(date.day) # 04. Datum von
|
||||
self.browser['dtv_m'] = str(date.month) # 04. Datum von
|
||||
self.browser['dtv_y'] = str(date.year) # 04. Datum von
|
||||
self.browser['dtb_d'] = str(date.day) # 04. Datum bis - we dont know yet the end date
|
||||
self.browser['dtb_m'] = str(date.month) # 04. Datum bis - assume the same day
|
||||
self.browser['dtb_y'] = str(date.year) # 04. Datum bis
|
||||
self.browser['ztv_h'] = str(time.hour) # 05. Zeit von
|
||||
self.browser['ztv_m'] = str(time.minute) # 05. Zeit von
|
||||
self.browser['ztb_h'] = str(time.hour + 1) # 05. Zeit bis - we dont know yet the end time
|
||||
self.browser['ztb_m'] = str(time.minute) # 05. Zeit bis - just add 1 hour and correct later
|
||||
self.browser['e_ort_1'] = '306' # 06. Einsatzort: Urdorf 306, Birmensdorf 298
|
||||
self.browser['eins_ereig'] = eins_ereig.encode('iso-8859-1') # 07. Ereignis
|
||||
self.browser['adr'] = adr.encode('iso-8859-1') # 08. Adresse
|
||||
self.browser['ang_sit'] = 'TBD1' # 17. Angetroffene Situation
|
||||
self.browser['mn'] = 'TBD2' # 19. Massnahmen
|
||||
self.browser['bk'] = 'TBD3' # 20. Bemerkungen
|
||||
self.browser['en_kr_feuwehr'] = '1' # 21. Einsatzkräfte
|
||||
self.browser['ali_io'] = '1' # 24. Alarmierung
|
||||
self.browser['kopie_gvz'] = '1' # 31. Kopie innert 10 Tagen an GVZ
|
||||
self.browser['mannschaftd_einsa'] = '70' # 32. Einsatzleiter|in
|
||||
self.logger.info('[%s] Preparing form data for Einsatzrapport', f_id)
|
||||
lodur_data = {
|
||||
'e_r_num': f_id, # 01. Einsatzrapportnummer
|
||||
'eins_stat_kantone': '1', # 02. Einsatzart FKS
|
||||
'emergency_concept_id': '2', # 03. Verrechnungsart
|
||||
'ver_sart': 'ab', # 03. Verrechnungsart internal: ab, th, uh, ak, tt
|
||||
'dtv_d': str(date.day), # 04. Datum von
|
||||
'dtv_m': str(date.month), # 04. Datum von
|
||||
'dtv_y': str(date.year), # 04. Datum von
|
||||
'dtb_d': str(date.day), # 04. Datum bis - we dont know yet the end date
|
||||
'dtb_m': str(date.month), # 04. Datum bis - assume the same day
|
||||
'dtb_y': str(date.year), # 04. Datum bis
|
||||
'ztv_h': str(time.hour), # 05. Zeit von
|
||||
'ztv_m': str(time.minute), # 05. Zeit von
|
||||
'ztb_h': str(time.hour + 1), # 05. Zeit bis - we dont know yet the end time
|
||||
'ztb_m': str(time.minute), # 05. Zeit bis - just add 1 hour and correct later
|
||||
'e_ort_1': '306', # 06. Einsatzort: Urdorf 306, Birmensdorf 298
|
||||
'eins_ereig': eins_ereig, # 07. Ereignis
|
||||
'adr': adr, # 08. Adresse
|
||||
'zh_alarmierung_h': str(time.hour), # 12. Alarmierung
|
||||
'zh_alarmierung_m': str(time.minute), # 12. Alarmierung
|
||||
'ang_sit': 'TBD1', # 17. Angetroffene Situation
|
||||
'mn': 'TBD2', # 19. Massnahmen
|
||||
'bk': 'TBD3', # 20. Bemerkungen
|
||||
'en_kr_feuwehr': '1', # 21. Einsatzkräfte
|
||||
'ali_io': '1', # 24. Alarmierung
|
||||
'kopie_gvz': '1', # 31. Kopie innert 10 Tagen an GVZ
|
||||
'mannschaftd_einsa': '70', # 32. Einsatzleiter|in
|
||||
}
|
||||
|
||||
# Submit the form
|
||||
self.logger.info('Submitting form Einsatzrapport')
|
||||
response = self.browser.submit_selected()
|
||||
lodur_id, auto_num = self.submit_form_einsatzrapport(lodur_data)
|
||||
|
||||
# save lodur id and data to webdav
|
||||
lodur_data['event_id'] = lodur_id
|
||||
lodur_data['auto_num'] = auto_num
|
||||
webdav_client.store_lodur_data(f_id, lodur_data)
|
||||
|
||||
# very ugly way to find the assigned event id by lodur
|
||||
# lodur adds a script element at the bottom of the returned html
|
||||
# with the location to reload the page - containing the assigned event id
|
||||
lodur_id = re.search('modul=36&event=([0-9].*)&edit=1&what=144', response.text).group(1)
|
||||
self.logger.info('Lodur assigned the id ' + lodur_id + ' to ' + f_id)
|
||||
return lodur_id
|
||||
|
||||
def einsatzrapport_alarmdepesche(self, lodur_id, file_path):
|
||||
def einsatzrapport_alarmdepesche(self, f_id, file_path, webdav_client):
|
||||
""" Upload a file to Alarmdepesche """
|
||||
|
||||
# check if data is already sent to lodur - data contains lodur_id
|
||||
lodur_id = webdav_client.get_lodur_data(f_id)['event_id']
|
||||
|
||||
# Prepare the form
|
||||
self.browser.open(self.url + '?modul=36&what=828&event=' + lodur_id)
|
||||
self.browser.select_form('#frm_alarmdepesche')
|
||||
|
||||
# Fill in form data
|
||||
self.logger.info('Submitting Alarmdepesche to Lodur id ' + lodur_id)
|
||||
self.logger.info('[%s] Submitting Alarmdepesche to Lodur', f_id)
|
||||
self.browser['alarmdepesche'] = open(file_path, 'rb')
|
||||
|
||||
# Submit the form
|
||||
self.browser.submit_selected()
|
||||
self.logger.info('Alarmdepesche submitted')
|
||||
self.logger.info('[%s] Alarmdepesche submitted', f_id)
|
||||
|
||||
def submit_form_einsatzrapport(self, lodur_data):
|
||||
""" Form in module 36 - Einsatzrapport """
|
||||
|
||||
# Prepare the form
|
||||
if 'event_id' in lodur_data:
|
||||
# existing entry to update
|
||||
self.logger.info(
|
||||
'[%s] Updating existing entry with ID %s',
|
||||
lodur_data['e_r_num'],
|
||||
lodur_data['event_id'],
|
||||
)
|
||||
self.browser.open(
|
||||
self.url +
|
||||
'?modul=36&what=144&edit=1&event=' +
|
||||
lodur_data['event_id']
|
||||
)
|
||||
else:
|
||||
self.logger.info('[%s] Creating new entry in Lodur', lodur_data['e_r_num'])
|
||||
self.browser.open(
|
||||
self.url +
|
||||
'?modul=36'
|
||||
)
|
||||
|
||||
self.browser.select_form('#einsatzrapport_main_form')
|
||||
|
||||
# Prepare the form data to be submitted
|
||||
for key, value in lodur_data.items():
|
||||
# Encode fields so they are sent in correct format
|
||||
self.logger.debug('Form data: %s = %s', key, value)
|
||||
if key in ('eins_ereig', 'adr'):
|
||||
self.browser[key] = value.encode('iso-8859-1')
|
||||
else:
|
||||
self.browser[key] = value
|
||||
|
||||
# Submit the form
|
||||
self.logger.info('[%s] Submitting form Einsatzrapport', lodur_data['e_r_num'])
|
||||
response = self.browser.submit_selected()
|
||||
self.logger.info('[%s] Form Einsatzrapport submitted', lodur_data['e_r_num'])
|
||||
|
||||
if 'event_id' in lodur_data:
|
||||
return True
|
||||
else:
|
||||
# very ugly way to find the assigned event id by lodur
|
||||
# lodur adds a script element at the bottom of the returned html
|
||||
# with the location to reload the page - containing the assigned event id
|
||||
lodur_id = re.search('modul=36&event=([0-9].*)&edit=1&what=144', response.text).group(1)
|
||||
self.logger.info('[%s] Lodur assigned the event_id %s', lodur_data['e_r_num'], lodur_id)
|
||||
|
||||
# The hidden field auto_num is also needed for updating the form
|
||||
# and it's written somewhere in javascript code - but not on the page
|
||||
# delivered after the submission which contains the redirect URL
|
||||
# It's only delivered in the next page. So we browse to this page now
|
||||
content = self.browser.open(
|
||||
self.url +
|
||||
'?modul=36&edit=1&what=144&event=' + lodur_id
|
||||
).text
|
||||
auto_num = re.search("fdata\['auto_num'\]\[2\]='(.*)';", content).group(1)
|
||||
self.logger.info('[%s] Lodur assigned the auto_num %s', lodur_data['e_r_num'], auto_num)
|
||||
|
||||
return lodur_id, auto_num
|
||||
|
|
64
main.py
64
main.py
|
@ -97,65 +97,77 @@ def main():
|
|||
|
||||
# Take actions - depending on the type
|
||||
if f_type == 'Einsatzausdruck_FW':
|
||||
lodur_id = webdav_client.get_lodur_id(f_id)
|
||||
if lodur_id:
|
||||
lodur_data = webdav_client.get_lodur_data(f_id)
|
||||
if lodur_data:
|
||||
logger.info(
|
||||
'Einsatzrapport ' + f_id + ' already created in Lodur: ' + lodur_id
|
||||
'[%s] Einsatzrapport already created in Lodur', f_id
|
||||
)
|
||||
# Upload Alarmdepesche as it could contain more information than the first one
|
||||
# Upload Alarmdepesche as it could contain more information
|
||||
# than the first one
|
||||
lodur_client.einsatzrapport_alarmdepesche(
|
||||
lodur_id,
|
||||
f_id,
|
||||
os.path.join(TMP_DIR, file_name),
|
||||
webdav_client,
|
||||
)
|
||||
else:
|
||||
# this is real - publish Einsatz on MQTT
|
||||
# TODO publish more information about the einsatz - coming from the PDF
|
||||
mqtt_client.send_message(f_type, f_id)
|
||||
|
||||
else:
|
||||
# get as many information from PDF as possible
|
||||
pdf_data = pdf.extract_einsatzausdruck(
|
||||
os.path.join(TMP_DIR, file_name),
|
||||
f_id,
|
||||
)
|
||||
|
||||
# publish Einsatz on MQTT
|
||||
# TODO publish more information about the einsatz - coming from the PDF
|
||||
mqtt_client.send_message(f_type, f_id)
|
||||
|
||||
# create new Einsatzrapport in Lodur
|
||||
logger.info('Creating Einsatzrapport in Lodur for ' + f_id)
|
||||
lodur_id = lodur_client.einsatzrapport(
|
||||
lodur_client.einsatzrapport(
|
||||
f_id,
|
||||
pdf_data,
|
||||
webdav_client,
|
||||
)
|
||||
# store lodur id in webdav
|
||||
webdav_client.store_lodur_id(lodur_id, f_id)
|
||||
|
||||
# upload Alarmdepesche to Lodur
|
||||
# upload Alarmdepesche PDF to Lodur
|
||||
lodur_client.einsatzrapport_alarmdepesche(
|
||||
lodur_id,
|
||||
f_id,
|
||||
os.path.join(TMP_DIR, file_name),
|
||||
webdav_client,
|
||||
)
|
||||
|
||||
elif f_type == 'Einsatzprotokoll':
|
||||
# Einsatz finished - publish on MQTT
|
||||
mqtt_client.send_message(f_type, f_id)
|
||||
|
||||
lodur_id = webdav_client.get_lodur_id(f_id)
|
||||
if lodur_id:
|
||||
logger.info('Uploading Einsatzprotokoll to Lodur')
|
||||
lodur_data = webdav_client.get_lodur_data(f_id)
|
||||
if lodur_data:
|
||||
logger.info('[%s] Uploading Einsatzprotokoll to Lodur', f_id)
|
||||
|
||||
# Upload Einsatzprotokoll to Lodur
|
||||
lodur_client.einsatzrapport_alarmdepesche(
|
||||
lodur_id,
|
||||
f_id,
|
||||
os.path.join(TMP_DIR, file_name),
|
||||
webdav_client,
|
||||
)
|
||||
|
||||
# Parse the Einsatzprotokoll PDF
|
||||
pdf_data = pdf.extract_einsatzprotokoll(
|
||||
os.path.join(TMP_DIR, file_name),
|
||||
f_id,
|
||||
)
|
||||
# only update when parsing was successfull
|
||||
if pdf_data:
|
||||
logger.info('Updating Einsatzrapport with data from PDF - not yet implemented')
|
||||
else:
|
||||
logger.info('Updating Einsatzrapport not possible - PDF parsing failed')
|
||||
|
||||
# Update entry in Lodur with parse PDF data
|
||||
logger.info('[%s] Updating Einsatzrapport with data from PDF', f_id)
|
||||
lodur_client.einsatzprotokoll(f_id, pdf_data, webdav_client)
|
||||
|
||||
else:
|
||||
logger.error('Cannot process Einsatzprotokoll as there is no Lodur ID')
|
||||
logger.error(
|
||||
'[%s] Cannot process Einsatzprotokoll as there is no Lodur ID',
|
||||
f_id
|
||||
)
|
||||
|
||||
else:
|
||||
logger.error('Unknown type: ' + f_type)
|
||||
logger.error('[%s] Unknown type: %s', f_id, f_type)
|
||||
|
||||
# send heartbeat
|
||||
requests.get(HEARTBEAT_URL)
|
||||
|
|
42
webdav.py
42
webdav.py
|
@ -3,6 +3,7 @@
|
|||
""" WebDav Functions """
|
||||
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import asyncio
|
||||
|
@ -63,41 +64,40 @@ class WebDav:
|
|||
else:
|
||||
return False
|
||||
|
||||
def store_lodur_id(self, lodur_id, f_id):
|
||||
""" stores assigned lodur_id on webdav """
|
||||
def store_lodur_data(self, f_id, lodur_data):
|
||||
""" stores lodur data on webdav """
|
||||
|
||||
file_name = f_id + '_lodurid.txt'
|
||||
file_name = f_id + '_lodur.json'
|
||||
file_path = os.path.join(self.tmp_dir, file_name)
|
||||
if not os.path.isfile(file_path):
|
||||
file = open(file_path, 'w')
|
||||
file.write(str(lodur_id))
|
||||
file.close()
|
||||
self.logger.info('Stored Lodur ID locally in: ' + file_path)
|
||||
self.upload(file_name, f_id)
|
||||
else:
|
||||
self.logger.info('Lodur ID already available locally in: ' + file_path)
|
||||
|
||||
def get_lodur_id(self, f_id):
|
||||
""" gets lodur_id if it exists """
|
||||
file = open(file_path, 'w')
|
||||
file.write(json.dumps(lodur_data))
|
||||
file.close()
|
||||
|
||||
file_name = f_id + '_lodurid.txt'
|
||||
self.logger.info('Stored Lodur data locally in: ' + file_path)
|
||||
self.upload(file_name, f_id)
|
||||
|
||||
def get_lodur_data(self, f_id):
|
||||
""" gets lodur data if it exists """
|
||||
|
||||
file_name = f_id + '_lodur.json'
|
||||
file_path = os.path.join(self.tmp_dir, file_name)
|
||||
|
||||
# first check if we already have it locally - then check on webdav
|
||||
if os.path.isfile(file_path):
|
||||
with open(file_path, 'r') as content:
|
||||
lodur_id = content.read()
|
||||
self.logger.info('Found Lodur ID for ' + f_id + ' locally: ' + lodur_id)
|
||||
return lodur_id
|
||||
lodur_data = json.loads(content.read())
|
||||
self.logger.info('[%s] Found Lodur data locally', f_id)
|
||||
return lodur_data
|
||||
else:
|
||||
remote_upload_dir = self.webdav_basedir + "/" + str(datetime.now().year) + "/" + f_id
|
||||
remote_file_path = remote_upload_dir + '/' + file_name
|
||||
if self.loop.run_until_complete(self.webdav.exists(remote_file_path)):
|
||||
self.loop.run_until_complete(self.webdav.download(remote_file_path, file_path))
|
||||
with open(file_path, 'r') as content:
|
||||
lodur_id = content.read()
|
||||
self.logger.info('Found Lodur ID for ' + f_id + ' on WebDAV: ' + lodur_id)
|
||||
return lodur_id
|
||||
lodur_data = json.loads(content.read())
|
||||
self.logger.info('[%s] Found Lodur data on WebDAV', f_id)
|
||||
return lodur_data
|
||||
else:
|
||||
self.logger.info('No Lodur ID found for ' + f_id)
|
||||
self.logger.info('[%s] No existing Lodur data found', f_id)
|
||||
return False
|
||||
|
|
Loading…
Reference in New Issue