def connect_button_action(self, *args): if self.is_connected: self.c2.disconnect() else: if self.c2: self.c2.connect_to_server() else: self.action = ShowErrorAction( message= 'The Command and Control system was not properly initialized.\n' 'Please restart Scribe3 and try again.') self.action.display()
class C2Widget(BoxLayout): connection_status = ConnectionStatus.unknown is_enabled = BooleanProperty(False) is_connected = BooleanProperty(False) log = StringProperty() log_entries = deque([], maxlen=20) state = StringProperty('home') c2 = ObjectProperty() def __init__(self, *args, **kwargs): super(C2Widget, self).__init__(**kwargs) self.config = Scribe3Configuration() self.config.subscribe(self.on_config_update) self.on_config_update() def attach(self, c2): self.c2 = c2 self.c2.subscribe(self.on_c2_update) self.on_c2_update('Initialized') def on_c2_update(self, message, *args): self.is_connected = self.c2.connection != None \ and self.c2.connection.transport.connector.state == 'connected' # cannot find docs on this self.log_entries.append(message) self._on_log_entries() def _on_log_entries(self): self.log = '\n'.join([x for x in self.log_entries]) def on_config_update(self, *args, **kwargs): self.is_enabled = self.config.is_true('enable_c2') if not self.is_enabled and self.is_connected: self.c2.disconnect() def on_state(self, *args, **kwargs): pass def disable_button_action(self, *args): self.config.set('enable_c2', not self.is_enabled) def connect_button_action(self, *args): if self.is_connected: self.c2.disconnect() else: if self.c2: self.c2.connect_to_server() else: self.action = ShowErrorAction( message= 'The Command and Control system was not properly initialized.\n' 'Please restart Scribe3 and try again.') self.action.display()
class MetadataCollectionSection(BaseSection, MetadataCollectionsScreen): def __init__(self, **kwargs): super(MetadataCollectionSection, self).__init__(**kwargs) def on_enter(self): super(MetadataCollectionSection, self).on_enter() def restart_app(self, *args, **kwargs): restart_app() def before_next(self): self.message = self.bt_server_register() if len(self.message) > 0: self.action = ShowErrorAction(message=self.message, on_popup_dismiss=self.restart_app) self.action.display() @staticmethod def bt_server_register(): message = '' #config = Scribe3Configuration() Logger.info('bt_server_register: Registering scribe') try: dd = dict( (k, v) for k, v in get_metadata(scribe_globals.CONFIG_DIR).items() if v) dd['books'] = '[]' tts = TTSServices(dd) success, tts_id = tts.register_tts(tts_id=dd['scanner'], metadata=dd) if success: #config.set('identifier', str(tts_id)) push_event('tts-register', dd, 'tts', tts_id) Logger.info( 'bt_server_register: Registered scribe: {}'.format(tts_id)) else: message = 'bt_server_register: Could not register this '\ 'scribe with Archive.org or scribe already '\ 'registered' Logger.info(message) except Exception: message = 'bt_server_register: Failed to register' Logger.exception(message) return message
def load_qr_data(self, qrcode_content): try: qr_bytes = qrcode_content.encode('utf-8') base64_decoded = base64.b64decode(qr_bytes) decompressed = zlib.decompress(base64_decoded) metadata = pickle.loads(decompressed) if not self.is_boxid_valid(): self.action = ShowErrorAction( message='You must insert a valid boxid') self.action.display() else: self._process_book(metadata) except Exception as e: self.action = ShowErrorAction( message='The following error occured:\n\n[b]{}[/b]'.format( str(e))) self.action.display()
def start_print_slip(self, identifier): self.action = ColoredYesNoActionPopupMixin( action_function=self.actually_reprint_slip, title='Reprint slip?', message='Are you sure you want to PRINT AGAIN this slip?', extra=identifier, ) self.action.display()
def collect_collection(self): collection_set_name = self.ids.collections_spinner.text #will be rcs collection_set = self.collection_sets_mapping.get(collection_set_name) if collection_set: return [ {'key': 'collection_set', 'value': collection_set.get('name')}, {'key': 'sponsor', 'value': collection_set.get('sponsor')}, {'key': 'contributor', 'value': collection_set.get('contributor')}, {'key': 'partner', 'value': collection_set.get('partner')}, {'key': 'rcs_key', 'value': u'{}'.format(collection_set.get('rcs_key'))}, {'key': 'collection', 'value': self.backend.create_collections(collection_set.get('name'))} ] else: self.action = ShowErrorAction( message='No collection set defined! Saving without collection string information.') self.action.display() return []
def show_slip(self, *args): if not self.backend.book_obj.has_slip(): return slip_image = Image(source=self.backend.book_obj.get_slip(full_path=True), size_hint=(None, None), allow_stretch=True, ) slip_image.size = slip_image.texture_size slip_name = self.backend.book_obj.get_slip_type() self.action = ShowGenericInfoAction( additional_content=slip_image, title='Slip type #{}'.format(slip_name) ) self.action.display()
def open(self, book): if self.screen_manager.current == 'capture_screen': self.action = ShowErrorAction( message='Another book is currently open for scanning.\n' 'Please close the current book before opening a new one.', on_popup_dismiss=self._action_no_op_callback) self.action.display() return capture_screen = self.scribe_widget.ids._capture_screen capture_screen.book_dir = book['path'] target_screen = 'capture_screen' self.screen_manager.transition.direction = 'left' self.screen_manager.current = target_screen self.book_menu_popup.dismiss()
def post_login(self, result, error): if error: self.action = ShowErrorAction( title='Login error', message=error, ) self.action.display() else: # here it calls update_config, and if we write successfully if self.update_config(result) is True: self.success = True success_message = "You are now logged in as: \n\n" + str( urllib.parse.unquote( result.get("cookies")["logged-in-user"])) + "." self.action = ShowInfoActionPopupMixin( message=success_message, on_popup_dismiss=self.post_login_confirmation) self.action.display()
def upload_done_book_anew(self, book): target_status, target_name = get_upload_target(book) if not target_status: self.action = ShowErrorAction(message='Book error'\ 'Could not tell if book is a\nfoldouts or '\ 'corrections item.\nPlease contact an admin.', on_popup_dismiss=self._action_no_op_callback) self.action.display() return book_object = self.get_book_object(book) self.action = UploadAnewBookActionMixin(book=book_object, task_scheduler=self.task_scheduler, done_task_callback=self.book_reset_callback, target_name=target_name, target_status=target_status, ) self.action.display()
def do_action(self, popup, *args, **kwargs): target_scanner = None for button in popup.content.ids._content.children: if button.active: target_scanner = button.text if not target_scanner: self.action = ShowErrorAction( message='You need to select a station') self.action.display() return self.book.set_foldout_target(target_scanner) self.action = ShowInfoActionPopupMixin( message='Okay, upon [u]upload[/u] [b]{}[/b] ' 'will be sent to [b]{}[/b] for foldouts.'.format( self.book.name_human_readable(), target_scanner)) self.action.display() self.popup.dismiss()
class BoxingAppScreen(Screen): identifier = StringProperty(None) task_scheduler = ObjectProperty() library = ObjectProperty() sc_metadata = DictProperty() current_boxid = StringProperty() BOXID_VALIDATION_REGEX = config.get('boxid_validation_regex', '^IA\d{6,7}$') print_slip = BooleanProperty(False) banner_message = StringProperty() def __init__(self, **kwargs): self.task_scheduler = kwargs.get('task_scheduler') self.library = kwargs.get('library') super(BoxingAppScreen, self).__init__(**kwargs) def load_qr_data(self, qrcode_content): try: qr_bytes = qrcode_content.encode('utf-8') base64_decoded = base64.b64decode(qr_bytes) decompressed = zlib.decompress(base64_decoded) metadata = pickle.loads(decompressed) if not self.is_boxid_valid(): self.action = ShowErrorAction( message='You must insert a valid boxid') self.action.display() else: self._process_book(metadata) except Exception as e: self.action = ShowErrorAction( message='The following error occured:\n\n[b]{}[/b]'.format( str(e))) self.action.display() def _process_book(self, metadata): generated_uuid = str(uuid4()) sc_metadata = get_sc_metadata() user = sc_metadata.get('operator') scanningcenter = sc_metadata.get('scanningcenter') scanner = sc_metadata.get('scanner') boxid = self.current_boxid Logger.info('Creating dummy book {}'.format(generated_uuid)) book = self.library.new_book(generated_uuid, operator=user, scanner=scanner, scanningcenter=scanningcenter, boxid=boxid) book.initialze_metaxml() slip_metadata = metadata slip_metadata['boxid'] = boxid slip_metadata['datetime'] = datetime.now() slip_metadata['reason'] = 'Duplicate' slip_metadata['comment'] = 'BOXED' # This is necessary to tell rejection tracker to put this event in a separate itemset slip_metadata['boxed'] = True slip_metadata['operator'] = book.operator book.set_slip_metadata(REJECTED_DO_NOT_WANT_SLIP, slip_metadata.copy()) # This is mostly a placeholder to demonstrate we can tell the user what to do on screen. self.banner_message = 'Put this book in box {}'.format( metadata.get('keep_dupe_status_code')) task_handler = self._reject_and_print_slip(book, slip_metadata) \ if self.print_slip \ else self._reject_without_printing_slip(book) task_handler.task.fbind('on_end', self._on_task_end) self.task_scheduler.schedule(task_handler.task) def _reject_and_print_slip(self, book, slip_metadata): task = GenericUIHandler( MakeAndPrintSlipTask, book=book, type=REJECTED_DO_NOT_WANT_SLIP, slip_metadata=slip_metadata, transition='do_reject', ) return task def _reject_without_printing_slip(self, book): task = GenericUIHandler( BookTask, book=book, command='do_reject', ) return task def _on_task_end(self, task): book_obj = task.book if hasattr(task, 'book') else task._book self.banner_message = 'Done with {}'.format(book_obj) self.ids.identifier_input.text = '' self.ids.identifier_input.focus = True Clock.schedule_once(self._empty_banner_message, 3) def _empty_banner_message(self, *args, **kwargs): self.banner_message = '' def is_boxid_valid(self): pattern = self.BOXID_VALIDATION_REGEX res = re.match(pattern, self.current_boxid) if res: if len(self.current_boxid) != res.span()[1]: res = False else: res = True return res
class BookMetadataScreen(TooltipScreen, TooltipBehavior, Screen): books_db = ObjectProperty(allownone=True) task_scheduler = ObjectProperty(allownone=True) camera_system = ObjectProperty(allownone=True) input_disabled = BooleanProperty(False) target_extra = ObjectProperty(allownone=True) catalogs = ListProperty(['none',]) collection_sets_mapping = DictProperty() formatted_collection_sets = ListProperty() is_current_rcs_default = BooleanProperty() collection_string = StringProperty() current_catalog = StringProperty('none') can_reprint_slip = BooleanProperty(False) _marc_popup = ObjectProperty(None, allownone=True) object_type = StringProperty('item') OLD_PALLET_VALIDATION_REGEX = StringProperty() BOXID_VALIDATION_REGEX = StringProperty() __events__ = ('on_done', 'on_cancel') def __init__(self, **kwargs): self._search_option = 'identifier' self._new_book = False self._input_trigger = Clock.create_trigger(self._on_input_disabled, -1) self.fbind('disabled', self._input_trigger) self.fbind('input_disabled', self._input_trigger) self.OLD_PALLET_VALIDATION_REGEX = config.get('old_pallet_validation_regex', '(IA-..-\d{7})|(IA|CH)[\dxX]{4,5}') self.BOXID_VALIDATION_REGEX = config.get('boxid_validation_regex', '^IA\d{6,7}$') super(BookMetadataScreen, self).__init__(**kwargs) self._new_metadata_field_popup = NewMetadataFieldPopup() self._progress_popup = ProgressPopup() self.backend = BookMetadataScreenBackend( task_scheduler=self.task_scheduler ) self._bind_backend_events() Clock.schedule_once(self._postponed_init, -1) def _postponed_init(self, *args): self._setup_new_metadata_field_popup() self._wonderfetch_popup = WonderfetchDialog() self.catalogs = self._wonderfetch_popup.catalogs self.current_catalog = self._wonderfetch_popup.default_catalog self._bind_wonderfetch_popup_events() def _bind_backend_events(self): md_loaded_trigger = Clock.create_trigger(self._on_metadata_loaded, -1) bk = self.backend bk.fbind(bk.EVENT_INIT, self._on_backend_init) bk.fbind(bk.EVENT_INIT, self._input_trigger) bk.fbind(bk.EVENT_BOOK_STATE, self._on_book_state) bk.fbind(bk.EVENT_ERROR, self._on_error) bk.fbind(bk.EVENT_METADATA_ERROR, self._on_metadata_error) bk.fbind(bk.EVENT_METADATA_DEFERRED, self._on_metadata_deferred) bk.fbind(bk.EVENT_IDENTIFIER_LOADED, self._on_identifier) bk.fbind(bk.EVENT_OFFLINE_ITEM_CREATED, self._on_offline_item_created) bk.fbind(bk.EVENT_METADATA_LOADED, md_loaded_trigger) bk.fbind(bk.EVENT_SELECT_IDENTIFIER, self._on_select_identifier) bk.fbind(bk.EVENT_START_MARC, self._on_start_marc) bk.fbind(bk.EVENT_TASK_START, self._progress_popup.open) bk.fbind(bk.EVENT_TASK_END, self._progress_popup.dismiss) bk.fbind(bk.EVENT_TASK_PROGRESS, self._on_task_progress) bk.fbind(bk.EVENT_BOOK_REJECTED, self._on_book_rejected) bk.fbind(bk.EVENT_START_WONDERFETCH, self._on_start_wonderfetch) bk.fbind(bk.EVENT_END_WONDERFETCH_SUCCESS, self._on_wonderfetch_success) bk.fbind(bk.EVENT_SLIP_PRINTED, self._on_slip_printed) bk.fbind(bk.EVENT_RCS_UPDATED, self._on_rcs_updated) def _setup_new_metadata_field_popup(self): popup = self._new_metadata_field_popup popup.target_widget = self.ids.metadata_form popup.fbind('on_submit', self._on_new_metadata_field_popup_submit) def _bind_wonderfetch_popup_events(self): popup = self._wonderfetch_popup popup.fbind(popup.EVENT_CANNOT_SCAN_BOOK, self._on_wonderfetch_cannot_scan_book) popup.fbind(popup.EVENT_SCAN_BOOK, self._on_wonderfetch_scan_book) popup.fbind(popup.EVENT_REJECT_BOOK, self._on_wonderfetch_reject_book) popup.fbind(popup.EVENT_SCAN_EXISTING_BOOK, self._on_wonderfetch_scan_book) popup.fbind(popup.EVENT_RETRIEVAL_ERROR, self._on_wonderfetch_retrieval_error) def _bind_marc_popup_events(self, popup): popup.fbind(popup.EVENT_RECORD_SELECTED, self.on_marc_selected_record) def _ensure_book_path_and_init(self, *args): if not self.backend.book_path: self.backend.create_new_book() self.backend.init() def start_load_metadata(self, identifier, volume): option = self._search_option if option == 'identifier': self.backend.load_metadata_via_identifier(identifier) elif option in ['isbn', 'openlibrary']: catalog = self.current_catalog if self.is_loading_allowed(): self.backend.wonderfetch_search(option, identifier, volume, catalog) def generate_identifier(self): self._save_metadata_if_valid(callback=self.do_generate_identifier) def do_generate_identifier(self): self.backend.make_identifier() def start_print_slip(self, identifier): self.action = ColoredYesNoActionPopupMixin( action_function=self.actually_reprint_slip, title='Reprint slip?', message='Are you sure you want to PRINT AGAIN this slip?', extra=identifier, ) self.action.display() def actually_reprint_slip(self, action, *args, **kwargs): identifier = action.extra_args self.save_metadata() self.backend.generate_and_print_slip(identifier) def start_print_slip_and_upload(self, identifier, next_action=None): self.save_metadata() self.backend.generate_reserve_print_slip(identifier, next_action) def start_marc_search(self, identifier): self.backend.marc_search(identifier) def reject_button_action(self): self._save_metadata_if_valid(callback=self.show_book_reject_popup, force=True, # this suppresses the "insufficient metadata" window ignore_fields=['old_pallet']) def show_book_reject_popup(self): popup = RejectBookPopup(title="Reject book", message="Please indicate the rejection reason") popup.fbind('on_submit', self._on_reject_book_popup_submit) popup.open() def _on_reject_book_popup_submit(self, popup, data): popup.dismiss() self.backend.reject_book(data) def show_slip(self, *args): if not self.backend.book_obj.has_slip(): return slip_image = Image(source=self.backend.book_obj.get_slip(full_path=True), size_hint=(None, None), allow_stretch=True, ) slip_image.size = slip_image.texture_size slip_name = self.backend.book_obj.get_slip_type() self.action = ShowGenericInfoAction( additional_content=slip_image, title='Slip type #{}'.format(slip_name) ) self.action.display() def save_metadata(self): Logger.info('BMDS: User pressed Save button') self._save_metadata_if_valid() def save_metadata_and_done(self): Logger.info('BMDS: User pressed Save&Done button') self._save_metadata_if_valid(callback=self.done) def is_loading_allowed(self): if self.backend.is_this_a_supercenter() and not self._ensure_boxid_and_old_pallet(): self.show_error('You must supply a compliant boxid\n' 'value in order to use this feature.') return False success, md = self.is_metadata_valid() # test boxid is not empty here return success def is_metadata_valid(self, ignore_fields=[]): metadata = self.collect_metadata() self.ids.metadata_form.validate() modern_books_section_ok, payload = self._are_modern_books_items_valid(ignore_fields=ignore_fields) if not modern_books_section_ok and self.backend.is_this_a_supercenter(): self.show_error('Your {} seems to be invalid.'.format(payload['key'])) return False, None identifier_list = list(filter(lambda entry: entry['key'] == 'user_identifier', metadata)) if len(identifier_list) > 0: identifier = identifier_list[0]['value'] if identifier: if not self.is_identifier_valid(identifier): self.show_error('Identifier{} is invalid.'.format(identifier)) return False, None if self._are_metadata_items_valid(metadata): return True, metadata else: return False, None def _save_metadata_if_valid(self, callback=None, force=False, ignore_fields=[]): success, metadata = self.is_metadata_valid(ignore_fields=ignore_fields) if success: self.backend.set_metadata_from_form(metadata) self.backend.save_metadata() if not self.backend._has_minimum_acceptable_metadata() and not force: msg = "Your metadata was saved. However, it appears you are attempting to create an " \ "item without some key fields." \ "\nAt least [b]title and creator[/b], or [b]isbn[/b] should be present.\n" \ "\n[b]Would you like to continue with insufficient metadata?[/b]\n" \ "\nClick NO to go back and review the currently available metadata." self.show_choice('Insufficient metadata', msg, callback) return False if callback: callback() return True else: self.show_error('Ensure that all fields are non-empty and valid.') return False def collect_metadata(self): md = self.ids.metadata_form.collect_data() md.extend(self.collect_global_book_settings()) if not self.backend.book_obj.is_preloaded(): md.extend(self.collect_collection()) md.extend(self.collect_identifier()) camera = self.backend.get_metadata_item('camera') if not camera and self.camera_system: camera = self.camera_system.get_name() if camera: md.append({'key': 'camera', 'value': camera}) return md def _are_metadata_items_valid(self, metadata): new_book = self._new_book for_removal = [] for index, item in enumerate(metadata): if item.get('deleted', False): continue value = item['value'] if not item.get('valid', True): return False for index, md_index in enumerate(for_removal): metadata.pop(md_index - index) return True def _are_modern_books_items_valid(self, ignore_fields): for index, item in enumerate(self.collect_global_book_settings()): #if item.get('deleted', False): # continue value = item['value'] if not item.get('valid', True): if item['key'] in ignore_fields: continue return False, item return True, None def open_new_metadata_field_popup(self): skip_keys = MD_SKIP_KEYS | MD_READONLY_KEYS all_data_keys = self.ids.metadata_form.all_data_keys for key in all_data_keys: if key in MD_KEYS_WITH_SINGLE_VALUE \ and all_data_keys[key] == 1: skip_keys.add(key) self._new_metadata_field_popup.skip_keys = skip_keys self._new_metadata_field_popup.open() def collect_collection(self): collection_set_name = self.ids.collections_spinner.text #will be rcs collection_set = self.collection_sets_mapping.get(collection_set_name) if collection_set: return [ {'key': 'collection_set', 'value': collection_set.get('name')}, {'key': 'sponsor', 'value': collection_set.get('sponsor')}, {'key': 'contributor', 'value': collection_set.get('contributor')}, {'key': 'partner', 'value': collection_set.get('partner')}, {'key': 'rcs_key', 'value': u'{}'.format(collection_set.get('rcs_key'))}, {'key': 'collection', 'value': self.backend.create_collections(collection_set.get('name'))} ] else: self.action = ShowErrorAction( message='No collection set defined! Saving without collection string information.') self.action.display() return [] def add_collection_set(self): #Only temporary, use app.get_popup instead from ia_scribe.uix.components.poppers.popups import WidgetPopup from ia_scribe.uix.widgets.rcs.rcs_widget import RCSSelectionWidget self.widget = WidgetPopup(content_class=RCSSelectionWidget, title='Add new RCS', size_hint=(None, None), size=('800dp', '500dp') ) self.widget.bind_events({ 'EVENT_CLOSED': self.widget.dismiss, 'EVENT_RCS_SELECTED': self.backend.add_collection_set, }) self.widget.content.set_center(get_scanner_property('scanningcenter')) self.widget.content.fbind(self.widget.content.EVENT_RCS_SELECTED, self._add_collection_set_callback) self.widget.open() def _add_collection_set_callback(self, *args, **kwargs): self.widget.dismiss() def is_selection_the_default_collection_set(self, *args, **kwargs): spinner_name = self.ids.collections_spinner.text selected_rcs = self.collection_sets_mapping.get(spinner_name) return selected_rcs == self.backend.rcs_manager.get_default(wrap=False) def set_default_collection_set(self, *args, **kwargs): spinner_name = self.ids.collections_spinner.text selected_rcs = self.collection_sets_mapping[spinner_name] if selected_rcs != self.backend.rcs_manager.get_default(wrap=False): self.backend.rcs_manager.set_default(selected_rcs) self.refresh_collection_star() def is_boxid_valid(self, input, old_pallet=False): if config.is_true('disable_mandatory_fields_in_dwwi'): return True res = None if old_pallet: pattern = self.OLD_PALLET_VALIDATION_REGEX else: pattern = self.BOXID_VALIDATION_REGEX res = re.match(pattern, input) if res: if len(input) != res.span()[1]: res = False else: res = True return res def is_identifier_valid(self, identifier): pattern = '^[a-zA-Z0-9][a-zA-Z0-9\.\-_]{4,99}$' match_result = re.match(pattern, identifier) if not match_result: return False return match_result.string == identifier def collect_global_book_settings(self): ids = self.ids return [ {'key': 'ppi', 'value': ids.ppi_input.value}, {'key': 'boxid', 'value': ids.box_id_input.text, 'deleted': not ids.box_id_input.text, 'valid': self.is_boxid_valid(ids.box_id_input.text),}, {'key': 'old_pallet', 'value': ids.box_id2_input.text, 'deleted': not ids.box_id2_input.text, 'valid': self.is_boxid_valid(ids.box_id2_input.text, old_pallet=True),}, {'key': 'volume', 'value': ids.volume_input.text, 'deleted': not ids.volume_input.text}, ] def collect_identifier(self): if self.ids.identifier_input.text: return [{'key': 'user_identifier', 'value': self.ids.identifier_input.text,}] return [] def reload(self): Logger.info('BMDS: User pressed Reload button') self.backend.reinit() def done(self): Logger.info('BMDS: User pressed Done button') self.dispatch('on_done') def cance_from_user(self): Logger.info('BMDS: User pressed Cancel button') self.cancel() def cancel(self): self.dispatch('on_cancel') def open_book_path(self): book_path = self.backend.book_path if book_path and exists(book_path): subprocess.check_call(['xdg-open', book_path.encode('utf-8')]) def show_info(self, message): popup = InfoPopup(title='Book metadata information', message=str(message)) popup.open() def show_error(self, message): popup = InfoPopup(title='Book metadata error', message=str(message)) popup.open() def show_choice(self, title, message, ok_callback, payload=None): popup = QuestionPopup(title=title, message=message, extra={'callback': ok_callback, 'payload': payload}, size=(400, 300)) popup.bind(on_submit=self.ok_callback) popup.open() def ok_callback(self, popup, option): if option == popup.OPTION_YES: if 'callback' in popup.extra and popup.extra['callback'] is not None: popup.extra['callback']() def _on_backend_init(self, backend): self._new_metadata_field_popup.dismiss() self._progress_popup.dismiss() self._on_book_state(backend, backend.get_book_state()) self._disable_by_state_if_necessary(backend) self._on_metadata_loaded(backend) self.object_type = self.backend.book_obj.get_type().lower() def _on_slip_printed(self, *args): ids = self.ids ids.slip_present_label.text = 'Yes' if self.backend.book_obj.has_slip() else 'No' ids.display_slip_button.opacity = 1 if self.backend.book_obj.has_slip() else 0 def _on_book_state(self, backend, state): self._on_slip_printed() ids = self.ids ids.marc_xml_label.text = 'Yes' if state & ST_HAS_MARC_XML else 'No' ids.marc_bin_label.text = 'Yes' if state & ST_HAS_MARC_BIN else 'No' ids.metasource_label.text = \ 'Yes' if state & ST_HAS_METASOURCE else 'No' ids.dwwi_and_marc_panel.disabled = bool(state & ST_PRELOADED) if state != 0: self.input_disabled = (bool(state & ST_DOWNLOADED) or not bool(state & ST_MARC_DOWNLOAD_FAILED)) else: self.input_disabled = False if state & ST_QUEUED_FOR_DELETE: Logger.info('BMDS: Cancelling screen because book is flagged for ' 'deletion') self.cancel() def _disable_by_state_if_necessary(self, backend): if backend.book_obj.status in ['loading_deferred']: self.input_disabled = True def _on_metadata_loaded(self, *args): backend = self.backend if not backend.is_initialized(): return self._new_book = not exists(backend.book_path) md = backend.create_form_metadata(MD_SKIP_KEYS) self._insert_separators_to_metadata(md) ids = self.ids ids.metadata_form.set_data(md) ids.ppi_input.value = backend.book_obj.scandata.get_bookdata('ppi') ids.box_id_input.text = backend.get_metadata_item('boxid') or u'' ids.box_id2_input.text = backend.get_metadata_item('old_pallet') or u'' ids.volume_input.text = backend.get_metadata_item('volume') or u'' ids.path_label.text = backend.book_path or '' self._populate_collection_sets() self.can_reprint_slip = self.backend.can_reprint_slip() def _populate_collection_sets(self): ret = {} default_collection_set = None for entry in self.backend.rcs_manager.as_list(): name_human_readable = '{} ({})'.format(entry.get('name'), entry.get('partner')) ret[name_human_readable] = entry if entry.get('default') is True: default_collection_set = name_human_readable self.collection_sets_mapping = ret self.formatted_collection_sets = ret.keys() # select correct entry book_metadata = self.backend.get_metadata() if 'rcs_key' in book_metadata: actual_collection = [human_name for human_name, entry in self.collection_sets_mapping.items() if str(entry.get('rcs_key')) == str(book_metadata.get('rcs_key'))] if len(actual_collection) > 0: self.ids.collections_spinner.text = actual_collection[0] elif 'collection_set' in book_metadata: # If a 'collection set' entry is present, try and match actual_collection = [human_name for human_name, entry in self.collection_sets_mapping.items() if entry.get('name') == book_metadata.get('collection_set')] if len(actual_collection) > 0: self.ids.collections_spinner.text = actual_collection[0] elif default_collection_set: self.ids.collections_spinner.text = default_collection_set self.refresh_collection_star() def refresh_collection_star(self): self.is_current_rcs_default = self.is_selection_the_default_collection_set() self.refresh_collection_string() def refresh_collection_string(self): spinner_name = self.ids.collections_spinner.text selected_rcs = self.collection_sets_mapping.get(spinner_name, {}) self.collection_string = selected_rcs.get('collections', '') def _insert_separators_to_metadata(self, metadata): separator = {'view_class': 'SeparatorLabelItem', 'size': (None, dp(30))} last_required_item_index = -1 for index, item in enumerate(metadata): if 'required' in item: last_required_item_index = index if 0 < last_required_item_index < len(metadata) - 1: metadata.insert(last_required_item_index + 1, separator) def _on_identifier(self, backend, identifier, *args, **kwargs): self.ids.identifier_input.text = identifier or u'' #self.input_disabled = bool(identifier) def _on_new_metadata_field_popup_submit(self, popup, data): self.ids.metadata_form.add_item(data) def _ensure_boxid_and_old_pallet(self): gbs = self.collect_global_book_settings() MANDATORY_FIELDS = ['boxid',] for item in gbs: if item['key'] in MANDATORY_FIELDS: if 'valid' in item and not item['valid']: return False return True def _on_start_marc(self, backend, identifier): self._ensure_book_path_and_init() app = App.get_running_app() marc_popup = app.get_popup(MARCPopup, size=(1200, 700), size_hint=(None, None)) self._bind_marc_popup_events(marc_popup) marc_popup.open() def _on_start_wonderfetch(self, backend, method, identifier, volume=None, catalog=None): self._ensure_book_path_and_init() self._wonderfetch_popup.book_dir = backend.book_path old_pallet = self.ids.box_id2_input.text if identifier: self._wonderfetch_popup.open_search(method, identifier, volume, catalog, old_pallet) else: self._wonderfetch_popup.open() def _on_task_progress(self, backend, report): self._progress_popup.message = report.get('message', None) or '' self._progress_popup.progress = report.get('progress', 0) def _on_error(self, backend, error_message): self.show_error(error_message) def _on_metadata_error(self, backend, identifier): message = ( 'show_create_confirm: Cannot verify item with archive.org\n' 'Would you like to create the item\n[b]{id}[/b] locally?' .format(id=identifier) ) popup = QuestionPopup(title='Offline mode', message=message, extra={'identifier': identifier}) popup.bind(on_submit=self._on_create_offline_item_popup_submit) popup.open() def _on_metadata_deferred(self, *args, **kwargs): self.done() def _on_create_offline_item_popup_submit(self, popup, option): if option == popup.OPTION_YES: self.backend.create_offline_item(popup.extra['identifier']) def _on_offline_item_created(self, backend): popup = InfoPopup( title='Offline mode', message=('Ok, created {} successfully!' .format(backend.get_identifier())), ) popup.open() def _on_select_identifier(self, backend, identifiers): popup = UniversalIDPopup(identifiers=identifiers) popup.fbind('on_submit', self._on_universal_id_popup_submit) popup.open() def _on_universal_id_popup_submit(self, popup, identifier): self.backend.load_metadata_via_identifier(identifier) def _on_wonderfetch_scan_book(self, dwwi_popup, payload, search_id, volume, *args): if payload: extra = self.collect_global_book_settings() self.backend.load_metadata_via_openlibrary(payload, extra, search_id, volume) def _on_wonderfetch_cannot_scan_book(self, dwwi_widget, catalog, search_key, response): self._save_metadata_if_valid(force=True) if search_key: self.backend.cannot_scan_book(catalog, search_key, response) def _on_wonderfetch_reject_book(self, dwwi_popup, isbn, volume, *args): self._save_metadata_if_valid(force=True) def _on_wonderfetch_success(self, *args, **kwargs): self.save_metadata() def _on_wonderfetch_retrieval_error(self, popup, error, wid, method, catalog): popup.dismiss() msg = '[b]We are currently unable to retrieve\nthe metadata for this book.[/b]\n\n' \ 'This could be due to a local or archive.org network issue. ' \ 'You can defer the retrieval to begin shooting the ' \ 'book right now and retry fetching the metadata later.' \ '\n\n[b]Do you want to defer retrieving ' \ 'metadata and continue to scanning[/b].' # prolly wanna use a local method to dismiss, alert and stuff ok_callback = partial(self.backend.on_end_wonderfetch_failure, error, wid, method, catalog) self.show_choice(title='Defer metadata retrieval?', message=msg, ok_callback=ok_callback) def on_marc_selected_record(self, widget, query, data): formatted_value = lambda v: v.encode('utf-8').decode('utf-8').encode('ascii', 'ignore') \ if v is not None else 'unknown' title = formatted_value(data['dc_meta']['metadata'].get('title', 'title unknown')) author = formatted_value(data['dc_meta']['metadata'].get('creator', 'creator unknown')) date = formatted_value(data['dc_meta']['metadata'].get('year', 'year unknown')) msg = 'Would you like to load metadata for ' \ '[b]{title}[/b] by [b]{author}[b] ({date})?'.format( title=title, author=author, date=date, ) ok_callback = partial(self._on_marc_record_confirmation, marc_widget=widget, query=query, data=data) self.show_choice('Load this MARC?', msg, ok_callback=ok_callback) def _on_marc_record_confirmation(self, marc_widget, query, data): marc_widget.close() self.backend.extract_metadata_from_marc_search(query, data) def _on_marc_downloaded_metadata(self, marc_popup, metadata, *args): # TODO: Validate downloaded metadata self.backend.set_metadata(metadata) self.backend.save_metadata() self.backend.reinit() def _on_input_disabled(self, *args): ids = self.ids if self.disabled or not self.backend.is_initialized(): return disabled = self.input_disabled ids.preloaded_panel.disabled = disabled ids.dwwi_and_marc_panel.disabled = disabled ids.metadata_form.layout_manager.disabled = disabled ids.add_new_field_button.disabled = disabled if not disabled: # It's possible that all views did not set disabled to False, # and therefore we have to refresh the form when disabled is False ids.metadata_form.refresh_from_layout() def _on_book_rejected(self, *args, **kwargs): self.target_extra = None if self._progress_popup: self._progress_popup.dismiss() self.cancel() def on_pre_enter(self, *args): self.ids.preloaded_id_input.text = u'' self.ids.identifier_input.text = u'' extra = self.target_extra if extra and extra.get('should_create_new_book', False): self.backend.create_new_book() self.backend.init() def on_leave(self, *args): if self._progress_popup: self._progress_popup.dismiss() self.target_extra = None self.backend.reset() self.backend.book_path = None def on_books_db(self, screen, books_db): self.backend.books_db = books_db def on_task_scheduler(self, screen, task_scheduler): self.backend.task_scheduler = task_scheduler def on_done(self): pass def on_cancel(self): pass def on_catalogs(self, *args, **kwargs): self.ids.catalog_spinner.values[:] = self.catalogs if self.current_catalog == 'none': self.ids.catalog_spinner.text = self._wonderfetch_popup.default_catalog def _on_rcs_updated(self, *args, **kwargs): self._populate_collection_sets()
def before_next(self): self.message = self.bt_server_register() if len(self.message) > 0: self.action = ShowErrorAction(message=self.message, on_popup_dismiss=self.restart_app) self.action.display()