pylokid/library/lodur.py

294 lines
12 KiB
Python

#!/usr/bin/env python3
""" Small Lodur Library for the Module 36 - Einsatzrapport """
import re
import logging
from datetime import datetime
import mechanicalsoup
class Lodur:
""" Lodur """
def __init__(self, url, username, password):
self.logger = logging.getLogger(__name__)
self.logger.info('Connecting to Lodur')
self.url = url
self.username = username
self.password = password
# MechanicalSoup initialization and login to Lodur
self.browser = mechanicalsoup.StatefulBrowser()
self.login()
if self.logged_in():
self.logger.info('Login to Lodur succeeded')
else:
self.logger.fatal('Login to Lodur failed - exiting')
raise SystemExit(1)
def login(self):
""" Login to lodur """
# The login form is located in module number 9
self.browser.open(self.url + '?modul=9')
# only log in when not yed logged in
if not self.logged_in():
# open login page again as the logged_in function has navigated to another page
self.browser.open(self.url + '?modul=9')
self.browser.select_form()
self.browser['login_member_name'] = self.username
self.browser['login_member_pwd'] = self.password
self.browser.submit_selected()
def logged_in(self):
""" check if logged in to lodur - session is valid """
# Check if login succeeded by finding the img with
# alt text LOGOUT on dashboard
self.browser.open(self.url + '?modul=16')
page = self.browser.get_current_page()
if page.find(alt='LOGOUT'):
self.logger.debug('Logged in')
return True
else:
self.logger.debug('Not logged in')
return False
def einsatzprotokoll(self, f_id, pdf_data, webdav_client):
""" Prepare Einsatzprotokoll to be sent to Lodur """
# 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:
try:
zh_fw_ausg = datetime.strptime(
pdf_data['ausgerueckt'],
'%H:%M:%S',
)
zh_am_schad = datetime.strptime(
pdf_data['vorort'],
'%H:%M:%S',
)
except ValueError as err:
self.logger.error('[%s] Date parsing failed: %s', f_id, err)
zh_fw_ausg = datetime.now()
zh_am_schad = datetime.now()
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:
# einsatz not available in Lodur
self.logger.error('[%s] No lodur_id found')
return False
def einsatzrapport(self, f_id, pdf_data, webdav_client):
""" Prepare form in module 36 - Einsatzrapport """
# when PDF parsing fails, pdf_data is false. fill with placeholder when this happens
if pdf_data:
date = datetime.strptime(
pdf_data['datum'],
'%d.%m.%Y',
)
time = datetime.strptime(
pdf_data['zeit'],
'%H:%M',
)
eins_ereig = pdf_data['einsatz']
bemerkungen = pdf_data['bemerkungen'] + '\n' + pdf_data['disponierteeinheiten']
wer_ala = pdf_data['melder']
adr = pdf_data['ort']
else:
date = datetime.now()
time = datetime.now()
eins_ereig = 'UNKNOWN'
bemerkungen = 'UNKNOWN'
wer_ala = 'UNKNOWN'
adr = 'UNKNOWN'
# Fill in form data
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
'wer_ala': wer_ala, # 10. Wer hat alarmiert
'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': bemerkungen, # 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
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)
return lodur_id
def einsatzrapport_alarmdepesche(self, f_id, file_path, webdav_client):
""" Upload a file to Alarmdepesche """
self.logger.info('[%s] Submitting File to Lodur "Alarmdepesche"', f_id)
# Login to lodur
self.login()
# 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.browser['alarmdepesche'] = open(file_path, 'rb')
# Submit the form
self.browser.submit_selected()
self.logger.info('[%s] File uploaded', f_id)
def einsatzrapport_scan(self, f_id, file_path, webdav_client):
""" Prepare Einsatzrapport Scan to be sent to Lodur """
# 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)
# Complement existing form data
self.logger.info('[%s] Preparing form data for Einsatzprotokoll', f_id)
lodur_data['ang_sit'] = 'Siehe Alarmdepesche - Einsatzrapport' # 17. Angetroffene Situation
lodur_data['mn'] = 'Siehe Alarmdepesche - Einsatzrapport' # 19. Massnahmen
# Submit the form
self.submit_form_einsatzrapport(lodur_data)
# Upload scan to Alarmdepesche
self.einsatzrapport_alarmdepesche(
f_id,
file_path,
webdav_client,
)
else:
# einsatz not available in Lodur
self.logger.error('[%s] No lodur_id found')
return False
def submit_form_einsatzrapport(self, lodur_data):
""" Form in module 36 - Einsatzrapport """
# Login to lodur
self.login()
# 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 some of the fields so they are sent in correct format
# Encoding bk causes some troubles - therefore we skip that - but it
# would be good if it would be encoded as it can / will contain f.e.abs
# Umlauts
# AttributeError: 'bytes' object has no attribute 'parent'
self.logger.info('Form data: %s = %s', key, value)
if key in ('eins_ereig', 'adr', 'wer_ala'):
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(r"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