66from tkinter import filedialog
77from tkinter import font
88import platform
9+ from queue import Queue
910
1011from . import views as v
1112from . import models as m
@@ -65,7 +66,7 @@ def __init__(self, *args, **kwargs):
6566 '<<NewRecord>>' : self ._new_record ,
6667 '<<UpdateWeatherData>>' : self ._update_weather_data ,
6768 '<<UploadToCorporateREST>>' : self ._upload_to_corporate_rest ,
68- '<<UploadToCorporateFTP >>' : self ._upload_to_corporate_ftp ,
69+ '<<UploadToCorporateSFTP >>' : self ._upload_to_corporate_sftp ,
6970 '<<ShowGrowthChart>>' : self .show_growth_chart ,
7071 '<<ShowYieldChart>>' : self .show_yield_chart
7172 }
@@ -99,9 +100,8 @@ def __init__(self, *args, **kwargs):
99100
100101 # The data record list
101102 self .recordlist_icon = tk .PhotoImage (file = images .LIST_ICON )
102- self .recordlist = v .RecordList (
103- self , self .inserted_rows , self .updated_rows
104- )
103+ self .recordlist = v .RecordList (self )
104+
105105 self .notebook .insert (
106106 0 , self .recordlist , text = 'Records' ,
107107 image = self .recordlist_icon , compound = tk .LEFT
@@ -288,12 +288,13 @@ def _set_font(self, *_):
288288 tk_font .config (size = font_size , family = font_family )
289289
290290 # new chapter 13
291- def _update_weather_data (self ):
291+ def _update_weather_data (self , * _ ):
292292 """Initiate retrieval and storage of weather data"""
293+ weather_data_model = m .WeatherDataModel (
294+ self .settings ['weather_station' ].get ()
295+ )
293296 try :
294- weather_data = n .get_local_weather (
295- self .settings ['weather_station' ].get ()
296- )
297+ weather_data = weather_data_model .get_weather_data ()
297298 except Exception as e :
298299 messagebox .showerror (
299300 title = 'Error' ,
@@ -306,58 +307,186 @@ def _update_weather_data(self):
306307 time = weather_data ['observation_time_rfc822' ]
307308 self .status .set (f"Weather data recorded for { time } " )
308309
309- def _upload_to_corporate_ftp (self , * _ ):
310+ def _create_csv_extract (self ):
311+ csvmodel = m .CSVModel ()
312+ records = self .model .get_all_records ()
313+ if not records :
314+ raise Exception ('No records were found to build a CSV file.' )
315+ for record in records :
316+ csvmodel .save_record (record )
317+ return csvmodel .file
310318
311- csvfile = self ._create_csv_extract ()
312- d = v .LoginDialog (self , 'Login to ABQ Corporate FTP' )
313- if d .result is not None :
314- username , password = d .result
315- try :
316- n .upload_to_corporate_ftp (
317- csvfile ,
318- self .settings ['abq_ftp_host' ].get (),
319- self .settings ['abq_ftp_port' ].get (),
320- username , password
321- )
322- except n .ftp .all_errors as e :
323- messagebox .showerror ('Error connecting to ftp' , str (e ))
324- else :
325- messagebox .showinfo (
326- 'Success' , f'{ csvfile } successfully uploaded to FTP'
319+
320+ def _upload_to_corporate_sftp (self , * _ ):
321+
322+ # create csv file
323+ try :
324+ csvfile = self ._create_csv_extract ()
325+ except Exception as e :
326+ messagebox .showwarning (
327+ title = 'Error' , message = str (e )
328+ )
329+ return
330+
331+ # authenticate
332+ d = v .LoginDialog (self , 'Login to ABQ Corporate SFTP' )
333+ if d .result is None :
334+ return
335+ username , password = d .result
336+
337+ # create model
338+ host = self .settings ['abq_sftp_host' ].get ()
339+ port = self .settings ['abq_sftp_port' ].get ()
340+ sftp_model = m .SFTPModel (host , port )
341+ try :
342+ sftp_model .authenticate (username , password )
343+ except Exception as e :
344+ messagebox .showerror ('Error Authenticating' , str (e ))
345+ return
346+
347+ # check destination file
348+ destination_dir = self .settings ['abq_sftp_path' ].get ()
349+ destination_path = f'{ destination_dir } /{ csvfile .name } '
350+
351+ try :
352+ exists = sftp_model .check_file (destination_path )
353+ except Exception as e :
354+ messagebox .showerror (
355+ f'Error checking file { destination_path } ' ,
356+ str (e )
357+ )
358+ return
359+ if exists :
360+ # ask if we should overwrite
361+ overwrite = messagebox .askyesno (
362+ 'File exists' ,
363+ f'The file { destination_path } already exists on the server, '
364+ 'do you want to overwrite it?'
365+ )
366+ if not overwrite :
367+ # ask if we should download it
368+ download = messagebox .askyesno (
369+ 'Download file' ,
370+ 'Do you want to download the file to inspect it?'
327371 )
372+ if download :
373+ # get a destination filename and save
374+ filename = filedialog .asksaveasfilename ()
375+ if not filename :
376+ return
377+ try :
378+ sftp_model .get_file (destination_path , filename )
379+ except Exception as e :
380+ messagebox .showerror ('Error downloading' , str (e ))
381+ return
382+ messagebox .showinfo (
383+ 'Download Complete' , 'Download Complete.'
384+ )
385+ return
386+ # if we haven't returned, the user wants to upload
387+ try :
388+ sftp_model .upload_file (csvfile , destination_path )
389+ except Exception as e :
390+ messagebox .showerror ('Error uploading' , str (e ))
391+ else :
392+ messagebox .showinfo (
393+ 'Success' ,
394+ f'{ csvfile } successfully uploaded to SFTP server.'
395+ )
328396
329- def _upload_to_corporate_rest (self ):
330- csvfile = self ._create_csv_extract ()
331- if csvfile is None :
397+ def _upload_to_corporate_rest (self , * _ ):
398+
399+ # create csv file
400+ try :
401+ csvfile = self ._create_csv_extract ()
402+ except Exception as e :
332403 messagebox .showwarning (
333- title = 'No records' ,
334- message = 'There are no records to upload'
404+ title = 'Error' , message = str (e )
335405 )
336406 return
407+
408+ # Authenticate to the rest server
337409 d = v .LoginDialog (
338410 self , 'Login to ABQ Corporate REST API'
339411 )
340412 if d .result is not None :
341413 username , password = d .result
342414 else :
343415 return
416+
417+ # create REST model
418+ rest_model = m .CorporateRestModel (
419+ self .settings ['abq_rest_url' ].get ()
420+ )
344421 try :
345- n .upload_to_corporate_rest (
346- csvfile ,
347- self .settings ['abq_upload_url' ].get (),
348- self .settings ['abq_auth_url' ].get (),
349- username ,
350- password
351- )
352- except n .requests .ConnectionError as e :
353- messagebox .showerror ('Error connecting' , str (e ))
422+ rest_model .authenticate (username , password )
354423 except Exception as e :
355- messagebox .showerror ('General Exception' , str (e ))
356- else :
357- messagebox .showinfo (
358- 'Success' ,
359- f'{ csvfile } successfully uploaded to REST API.'
424+ messagebox .showerror ('Error authenticating' , str (e ))
425+ return
426+
427+ # Check if the file exists
428+ try :
429+ exists = rest_model .check_file (csvfile .name )
430+ except Exception as e :
431+ messagebox .showerror ('Error checking for file' , str (e ))
432+ return
433+
434+ if exists :
435+ # ask if we should overwrite
436+ overwrite = messagebox .askyesno (
437+ 'File exists' ,
438+ f'The file { csvfile .name } already exists on the server, '
439+ 'do you want to overwrite it?'
360440 )
441+ if not overwrite :
442+ # ask if we should download it
443+ download = messagebox .askyesno (
444+ 'Download file' ,
445+ 'Do you want to download the file to inspect it?'
446+ )
447+ if download :
448+ # get a destination filename and save
449+ filename = filedialog .asksaveasfilename ()
450+ if not filename :
451+ return
452+ try :
453+ data = rest_model .get_file (csvfile .name )
454+ except Exception as e :
455+ messagebox .showerror ('Error downloading' , str (e ))
456+ return
457+ with open (filename , 'w' , encoding = 'utf-8' ) as fh :
458+ fh .write (data )
459+ messagebox .showinfo (
460+ 'Download Complete' , 'Download Complete.'
461+ )
462+ return
463+ # if we haven't returned, the user wants to upload
464+ rest_model .upload_file (csvfile )
465+ self ._check_queue (rest_model .queue )
466+
467+
468+ def _check_queue (self , queue ):
469+ while not queue .empty ():
470+ item = queue .get ()
471+ if item .status == 'done' :
472+ messagebox .showinfo (
473+ item .status ,
474+ message = item .subject ,
475+ detail = item .body
476+ )
477+ self .status .set (item .subject )
478+ return
479+ elif item .status == 'error' :
480+ messagebox .showerror (
481+ item .status ,
482+ message = item .subject ,
483+ detail = item .body
484+ )
485+ self .status .set (item .subject )
486+ return
487+ else :
488+ self .status .set (f'{ item .subject } : { item .body } ' )
489+ self .after (100 , self ._check_queue , queue )
361490
362491 #New for ch15
363492 def show_growth_chart (self , * _ ):
0 commit comments