| 1 |  |  | # -*- coding: utf-8 -*- | 
            
                                                        
            
                                    
            
            
                | 2 |  |  | # | 
            
                                                        
            
                                    
            
            
                | 3 |  |  | # This file is part of SENAITE.CORE | 
            
                                                        
            
                                    
            
            
                | 4 |  |  | # | 
            
                                                        
            
                                    
            
            
                | 5 |  |  | # Copyright 2018 by it's authors. | 
            
                                                        
            
                                    
            
            
                | 6 |  |  | # Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst. | 
            
                                                        
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 8 |  |  | import csv | 
            
                                                        
            
                                    
            
            
                | 9 |  |  | from DateTime.DateTime import DateTime | 
            
                                                        
            
                                    
            
            
                | 10 |  |  | from bika.lims.browser import BrowserView | 
            
                                                        
            
                                    
            
            
                | 11 |  |  | from bika.lims.exportimport.instruments import get_automatic_parser | 
            
                                                        
            
                                    
            
            
                | 12 |  |  | from bika.lims.utils import tmpID | 
            
                                                        
            
                                    
            
            
                | 13 |  |  | from Products.CMFCore.utils import getToolByName | 
            
                                                        
            
                                    
            
            
                | 14 |  |  | from bika.lims.exportimport.instruments.resultsimport import \ | 
            
                                                        
            
                                    
            
            
                | 15 |  |  |     AnalysisResultsImporter | 
            
                                                        
            
                                    
            
            
                | 16 |  |  | import traceback | 
            
                                                        
            
                                    
            
            
                | 17 |  |  | from os import listdir | 
            
                                                        
            
                                    
            
            
                | 18 |  |  | from os.path import isfile, join | 
            
                                                        
            
                                    
            
            
                | 19 |  |  | from bika.lims.idserver import renameAfterCreation | 
            
                                                        
            
                                    
            
            
                | 20 |  |  | from bika.lims import logger | 
            
                                                        
            
                                    
            
            
                | 21 |  |  | from datetime import datetime | 
            
                                                        
            
                                    
            
            
                | 22 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 24 |  |  | class ResultsImportView(BrowserView): | 
            
                                                        
            
                                    
            
            
                | 25 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 26 |  |  |     """ | 
            
                                                        
            
                                    
            
            
                | 27 |  |  |     This view will be called from any periodically running script to run | 
            
                                                        
            
                                    
            
            
                | 28 |  |  |     auto-import process. Instruments which has interfaces, and also interfaces | 
            
                                                        
            
                                    
            
            
                | 29 |  |  |     which auto-import folders assigned, will participate in this process. | 
            
                                                        
            
                                    
            
            
                | 30 |  |  |     To import for specified Instrument or/and Interface, these parameters can | 
            
                                                        
            
                                    
            
            
                | 31 |  |  |     be set in URL as well. | 
            
                                                        
            
                                    
            
            
                | 32 |  |  |     """ | 
            
                                                        
            
                                    
            
            
                | 33 |  |  |     def __init__(self, context, request): | 
            
                                                        
            
                                    
            
            
                | 34 |  |  |         super(ResultsImportView, self).__init__(context, request) | 
            
                                                        
            
                                    
            
            
                | 35 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 36 |  |  |     def __call__(self): | 
            
                                                        
            
                                    
            
            
                | 37 |  |  |         request = self.request | 
            
                                                        
            
                                    
            
            
                | 38 |  |  |         bsc = getToolByName(self, 'bika_setup_catalog') | 
            
                                                        
            
                                    
            
            
                | 39 |  |  |         # Getting instrumnets to run auto-import | 
            
                                                        
            
                                    
            
            
                | 40 |  |  |         query = {'portal_type': 'Instrument', | 
            
                                                        
            
                                    
            
            
                | 41 |  |  |                  'inactive_state': 'active'} | 
            
                                                        
            
                                    
            
            
                | 42 |  |  |         if request.get('i_uid', ''): | 
            
                                                        
            
                                    
            
            
                | 43 |  |  |             query['UID'] = request.get('i_uid') | 
            
                                                        
            
                                    
            
            
                | 44 |  |  |         brains = bsc(query) | 
            
                                                        
            
                                    
            
            
                | 45 |  |  |         interfaces = [] | 
            
                                                        
            
                                    
            
            
                | 46 |  |  |         for brain in brains: | 
            
                                                        
            
                                    
            
            
                | 47 |  |  |             i = brain.getObject() | 
            
                                                        
            
                                    
            
            
                | 48 |  |  |             logger.info('Auto import for ' + i.Title()) | 
            
                                                        
            
                                    
            
            
                | 49 |  |  |             # If Import Interface ID is specified in request, then auto-import | 
            
                                                        
            
                                    
            
            
                | 50 |  |  |             # will run only that interface. Otherwise all available interfaces | 
            
                                                        
            
                                    
            
            
                | 51 |  |  |             # of this instruments | 
            
                                                        
            
                                    
            
            
                | 52 |  |  |             if request.get('interface', ''): | 
            
                                                        
            
                                    
            
            
                | 53 |  |  |                 interfaces.append(request.get('interface')) | 
            
                                                        
            
                                    
            
            
                | 54 |  |  |             else: | 
            
                                                        
            
                                    
            
            
                | 55 |  |  |                 interfaces = [pairs.get('InterfaceName', '') for pairs | 
            
                                                        
            
                                    
            
            
                | 56 |  |  |                               in i.getResultFilesFolder()] | 
            
                                                        
            
                                    
            
            
                | 57 |  |  |             folder = '' | 
            
                                                        
            
                                    
            
            
                | 58 |  |  |             for interface in interfaces: | 
            
                                                        
            
                                    
            
            
                | 59 |  |  |                 # Each interface must have its folder where result files are | 
            
                                                        
            
                                    
            
            
                | 60 |  |  |                 # saved. If not, then we will skip | 
            
                                                        
            
                                    
            
            
                | 61 |  |  |                 for pairs in i.getResultFilesFolder(): | 
            
                                                        
            
                                    
            
            
                | 62 |  |  |                     if pairs['InterfaceName'] == interface: | 
            
                                                        
            
                                    
            
            
                | 63 |  |  |                         folder = pairs.get('Folder', '') | 
            
                                                        
            
                                    
            
            
                | 64 |  |  |                 if not folder: | 
            
                                                        
            
                                    
            
            
                | 65 |  |  |                     continue | 
            
                                                        
            
                                    
            
            
                | 66 |  |  |                 logger.info('Auto import for ' + interface) | 
            
                                                        
            
                                    
            
            
                | 67 |  |  |                 all_files = [f for f in listdir(folder) | 
            
                                                        
            
                                    
            
            
                | 68 |  |  |                              if isfile(join(folder, f))] | 
            
                                                        
            
                                    
            
            
                | 69 |  |  |                 imported_list = self.getAlreadyImportedFiles(folder) | 
            
                                                        
            
                                    
            
            
                | 70 |  |  |                 if not imported_list: | 
            
                                                        
            
                                    
            
            
                | 71 |  |  |                     logger.warn('imported.csv file not found ' + interface) | 
            
                                                        
            
                                    
            
            
                | 72 |  |  |                     self.add_to_logs(i, interface, | 
            
                                                        
            
                                    
            
            
                | 73 |  |  |                                      'imported.csv File not found...', '') | 
            
                                                        
            
                                    
            
            
                | 74 |  |  |                     continue | 
            
                                                        
            
                                    
            
            
                | 75 |  |  |                 for file_name in all_files: | 
            
                                                        
            
                                    
            
            
                | 76 |  |  |                     if file_name in imported_list: | 
            
                                                        
            
                                    
            
            
                | 77 |  |  |                         continue | 
            
                                                        
            
                                    
            
            
                | 78 |  |  |                     temp_file = open(folder+'/'+file_name) | 
            
                                                        
            
                                    
            
            
                | 79 |  |  |                     # Parsers work with UploadFile object from | 
            
                                                        
            
                                    
            
            
                | 80 |  |  |                     # zope.HTTPRequest which has filename attribute. | 
            
                                                        
            
                                    
            
            
                | 81 |  |  |                     # To add this attribute we convert the file. | 
            
                                                        
            
                                    
            
            
                | 82 |  |  |                     # CHECK should we add headers too? | 
            
                                                        
            
                                    
            
            
                | 83 |  |  |                     result_file = ConvertToUploadFile(temp_file) | 
            
                                                        
            
                                    
            
            
                | 84 |  |  |                     parser = get_automatic_parser(interface, result_file) | 
            
                                                        
            
                                    
            
            
                | 85 |  |  |                     if not parser: | 
            
                                                        
            
                                    
            
            
                | 86 |  |  |                         self.add_to_logs(i, interface, | 
            
                                                        
            
                                    
            
            
                | 87 |  |  |                                          'Parser not found...', file_name) | 
            
                                                        
            
                                    
            
            
                | 88 |  |  |                         continue | 
            
                                                        
            
                                    
            
            
                | 89 |  |  |                     # We will run import with some default parameters | 
            
                                                        
            
                                    
            
            
                | 90 |  |  |                     # Expected to be modified in the future. | 
            
                                                        
            
                                    
            
            
                | 91 |  |  |                     logger.info('Parsing ' + file_name) | 
            
                                                        
            
                                    
            
            
                | 92 |  |  |                     importer = AnalysisResultsImporter( | 
            
                                                        
            
                                    
            
            
                | 93 |  |  |                                 parser=parser, | 
            
                                                        
            
                                    
            
            
                | 94 |  |  |                                 context=self.portal, | 
            
                                                        
            
                                    
            
            
                | 95 |  |  |                                 override=[False, False], | 
            
                                                        
            
                                    
            
            
                | 96 |  |  |                                 instrument_uid=i.UID()) | 
            
                                                        
            
                                    
            
            
                | 97 |  |  |                     tbex = '' | 
            
                                                        
            
                                    
            
            
                | 98 |  |  |                     try: | 
            
                                                        
            
                                    
            
            
                | 99 |  |  |                         importer.process() | 
            
                                                        
            
                                    
            
            
                | 100 |  |  |                     except: | 
            
                                                        
            
                                    
            
            
                | 101 |  |  |                         tbex = traceback.format_exc() | 
            
                                                        
            
                                    
            
            
                | 102 |  |  |                     errors = importer.errors | 
            
                                                        
            
                                    
            
            
                | 103 |  |  |                     logs = importer.logs | 
            
                                                        
            
                                    
            
            
                | 104 |  |  |                     if tbex: | 
            
                                                        
            
                                    
            
            
                | 105 |  |  |                         errors.append(tbex) | 
            
                                                        
            
                                    
            
            
                | 106 |  |  |                     final_log = '' | 
            
                                                        
            
                                    
            
            
                | 107 |  |  |                     success_log = self.getInfoFromLog(logs, 'Import finished') | 
            
                                                        
            
                                    
            
            
                | 108 |  |  |                     if success_log: | 
            
                                                        
            
                                    
            
            
                | 109 |  |  |                         final_log = success_log | 
            
                                                        
            
                                    
            
            
                | 110 |  |  |                     else: | 
            
                                                        
            
                                    
            
            
                | 111 |  |  |                         final_log = errors | 
            
                                                        
            
                                    
            
            
                | 112 |  |  |                     self.insert_file_name(folder, file_name) | 
            
                                                        
            
                                    
            
            
                | 113 |  |  |                     self.add_to_logs(i, interface, final_log, file_name) | 
            
                                                        
            
                                    
            
            
                | 114 |  |  |                     self.add_to_log_file(i.Title(), interface, final_log, | 
            
                                                        
            
                                    
            
            
                | 115 |  |  |                                          file_name, folder) | 
            
                                                        
            
                                    
            
            
                | 116 |  |  |         logger.info('End of auto import...') | 
            
                                                        
            
                                    
            
            
                | 117 |  |  |         return 'Auto-Import finished...' | 
            
                                                        
            
                                    
            
            
                | 118 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 119 |  |  |     def getAlreadyImportedFiles(self, folder): | 
            
                                                        
            
                                    
            
            
                | 120 |  |  |         try: | 
            
                                                        
            
                                    
            
            
                | 121 |  |  |             with open(folder+'/imported.csv', 'r') as f: | 
            
                                                        
            
                                    
            
            
                | 122 |  |  |                 imported = f.readlines() | 
            
                                                        
            
                                    
            
            
                | 123 |  |  |                 imported = [i.strip() for i in imported] | 
            
                                                        
            
                                    
            
            
                | 124 |  |  |                 return imported | 
            
                                                        
            
                                    
            
            
                | 125 |  |  |         except: | 
            
                                                        
            
                                    
            
            
                | 126 |  |  |             with open(folder+'/imported.csv', 'w') as f: | 
            
                                                        
            
                                    
            
            
                | 127 |  |  |                 f.write('imported.csv\n') | 
            
                                                        
            
                                    
            
            
                | 128 |  |  |                 f.write('logs.log\n') | 
            
                                                        
            
                                    
            
            
                | 129 |  |  |                 f.close() | 
            
                                                        
            
                                    
            
            
                | 130 |  |  |             return [''] | 
            
                                                        
            
                                    
            
            
                | 131 |  |  |         return None | 
            
                                                        
            
                                    
            
            
                | 132 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 133 |  |  |     def insert_file_name(self, folder, name): | 
            
                                                        
            
                                    
            
            
                | 134 |  |  |         try: | 
            
                                                        
            
                                    
            
            
                | 135 |  |  |             with open(folder+'/imported.csv', 'a') as fd: | 
            
                                                        
            
                                    
            
            
                | 136 |  |  |                 fd.write(name+'\n') | 
            
                                                        
            
                                    
            
            
                | 137 |  |  |                 fd.close() | 
            
                                                        
            
                                    
            
            
                | 138 |  |  |         except: | 
            
                                                        
            
                                    
            
            
                | 139 |  |  |             pass | 
            
                                                        
            
                                    
            
            
                | 140 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 141 |  |  |     def getInfoFromLog(self, logs, keyword): | 
            
                                                        
            
                                    
            
            
                | 142 |  |  |         try: | 
            
                                                        
            
                                    
            
            
                | 143 |  |  |             for log in logs: | 
            
                                                        
            
                                    
            
            
                | 144 |  |  |                 if keyword in log: | 
            
                                                        
            
                                    
            
            
                | 145 |  |  |                     return log | 
            
                                                        
            
                                    
            
            
                | 146 |  |  |             return None | 
            
                                                        
            
                                    
            
            
                | 147 |  |  |         except: | 
            
                                                        
            
                                    
            
            
                | 148 |  |  |             return None | 
            
                                                        
            
                                    
            
            
                | 149 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 150 |  |  |     def add_to_logs(self, instrument, interface, log, filename): | 
            
                                                        
            
                                    
            
            
                | 151 |  |  |         if not log: | 
            
                                                        
            
                                    
            
            
                | 152 |  |  |             return | 
            
                                                        
            
                                    
            
            
                | 153 |  |  |         log = ''.join(log) | 
            
                                                        
            
                                    
            
            
                | 154 |  |  |         log = log[:80]+'...' if len(log) > 80 else log | 
            
                                                        
            
                                    
            
            
                | 155 |  |  |         _id = instrument.invokeFactory("AutoImportLog", id=tmpID(), | 
            
                                                        
            
                                    
            
            
                | 156 |  |  |                                        Instrument=instrument, | 
            
                                                        
            
                                    
            
            
                | 157 |  |  |                                        Interface=interface, | 
            
                                                        
            
                                    
            
            
                | 158 |  |  |                                        Results=log, | 
            
                                                        
            
                                    
            
            
                | 159 |  |  |                                        ImportedFile=filename) | 
            
                                                        
            
                                    
            
            
                | 160 |  |  |         item = instrument[_id] | 
            
                                                        
            
                                    
            
            
                | 161 |  |  |         item.unmarkCreationFlag() | 
            
                                                        
            
                                    
            
            
                | 162 |  |  |         renameAfterCreation(item) | 
            
                                                        
            
                                    
            
            
                | 163 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 164 |  |  |     def add_to_log_file(self, instrument, interface, log, filename, folder): | 
            
                                                        
            
                                    
            
            
                | 165 |  |  |         log = self.format_log_data(instrument, interface, log, filename) | 
            
                                                        
            
                                    
            
            
                | 166 |  |  |         try: | 
            
                                                        
            
                                    
            
            
                | 167 |  |  |             with open(folder+'/logs.log', 'a') as fd: | 
            
                                                        
            
                                    
            
            
                | 168 |  |  |                 fd.write(log+'\n') | 
            
                                                        
            
                                    
            
            
                | 169 |  |  |                 fd.close() | 
            
                                                        
            
                                    
            
            
                | 170 |  |  |         except: | 
            
                                                        
            
                                    
            
            
                | 171 |  |  |             with open(folder+'/logs.log', 'w') as f: | 
            
                                                        
            
                                    
            
            
                | 172 |  |  |                 f.write(log+'\n') | 
            
                                                        
            
                                    
            
            
                | 173 |  |  |                 f.close() | 
            
                                                        
            
                                    
            
            
                | 174 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 175 |  |  |     def format_log_data(self, instrument, interface, result, filename): | 
            
                                                        
            
                                    
            
            
                | 176 |  |  |         log = DateTime.strftime(DateTime(), '%Y-%m-%d %H:%M:%S') | 
            
                                                        
            
                                    
            
            
                | 177 |  |  |         log += ' - ' + instrument | 
            
                                                        
            
                                    
            
            
                | 178 |  |  |         log += ' - ' + interface | 
            
                                                        
            
                                    
            
            
                | 179 |  |  |         log += ' - ' + filename | 
            
                                                        
            
                                    
            
            
                | 180 |  |  |         r = ''.join(result) | 
            
                                                        
            
                                    
            
            
                | 181 |  |  |         log += ' - ' + r | 
            
                                                        
            
                                    
            
            
                | 182 |  |  |         return log | 
            
                                                        
            
                                    
            
            
                | 183 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 184 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 185 |  |  | class ConvertToUploadFile: | 
            
                                                        
            
                                    
            
            
                | 186 |  |  |     """ | 
            
                                                        
            
                                    
            
            
                | 187 |  |  |     File objects don't have 'filename' and 'headers' attributes. | 
            
                                                        
            
                                    
            
            
                | 188 |  |  |     Since Import step of different Interfaces checks if 'filename' is set | 
            
                                                        
            
                                    
            
            
                | 189 |  |  |     to be sure that submitted form contains uploaded file, we also have to add | 
            
                                                        
            
                                    
            
            
                | 190 |  |  |     this attribute to our File object. | 
            
                                                        
            
                                    
            
            
                | 191 |  |  |     """ | 
            
                                                        
            
                                    
            
            
                | 192 |  |  |     def __init__(self, orig_file): | 
            
                                                        
            
                                    
            
            
                | 193 |  |  |         if hasattr(orig_file, '__methods__'): | 
            
                                                        
            
                                    
            
            
                | 194 |  |  |             methods = orig_file.__methods__ | 
            
                                                        
            
                                    
            
            
                | 195 |  |  |         else: | 
            
                                                        
            
                                    
            
            
                | 196 |  |  |             methods = ['close', 'fileno', 'flush', 'isatty', | 
            
                                                        
            
                                    
            
            
                | 197 |  |  |                        'read', 'readline', 'readlines', 'seek', | 
            
                                                        
            
                                    
            
            
                | 198 |  |  |                        'tell', 'truncate', 'write', 'writelines', | 
            
                                                        
            
                                    
            
            
                | 199 |  |  |                        '__iter__', 'next', 'name'] | 
            
                                                        
            
                                    
            
            
                | 200 |  |  |         d = self.__dict__ | 
            
                                                        
            
                                    
            
            
                | 201 |  |  |         for m in methods: | 
            
                                                        
            
                                    
            
            
                | 202 |  |  |             if hasattr(orig_file, m): | 
            
                                                        
            
                                    
            
            
                | 203 |  |  |                 d[m] = getattr(orig_file, m) | 
            
                                                        
            
                                    
            
            
                | 204 |  |  |         self.filename = orig_file.name | 
            
                                                        
            
                                    
            
            
                | 205 |  |  |  |