def set_errors(form, builder, fields): log.error("Form is not valid") log.debug(form.errors.as_json()) for item in form.errors: if "_id" in item: item = item.split("_id")[0] # Get the widget if ("entry" in fields and item in fields["entry"]) or \ ("spinbutton" in fields and item in fields["spinbutton"]): entry = builder.get_object(item) entry.get_style_context().add_class("error") entry.set_icon_from_icon_name(1, "error") item_errors = "\n".join(form.errors[item]) entry.set_icon_tooltip_markup(1, item_errors) entry.connect("changed", error_field_changed) if "combobox" in fields and item in fields["combobox"]: combobox = builder.get_object(item) combobox.get_style_context().add_class("error-combobox") combobox.connect("changed", error_field_changed) if "textview" in fields and item in fields["textview"]: textview = builder.get_object(item + "_buffer") textview.get_style_context().add_class("error-textview") textview.connect("changed", error_field_changed) return
def refresh_single_grid(self, visible_child_name): try: visible_bag_id = int(visible_child_name.split("-")[-1]) except ValueError as error: log.error("Wrong child name (not integer found). %s", error) return child_builder = self.children[visible_bag_id] grid = child_builder.get_object("grid") for child in grid.get_children(): child.destroy() data = parser(self.params) # Toggle item toggle_row_num = None if self.toggled[visible_bag_id]: toggle_row_num = self.toggled[visible_bag_id][0] - 1 # Reset toggled value self.toggled[visible_bag_id] = False self.build_grid(child_builder, data, visible_bag_id, toggle_row_num) return
def delete_key(self, fingerprint): """Delete key from the keyring. :param str fingerprint: The fingerprint of the key to delete. :return: True if the key is successfully deleted. :rtype: bool :Example: >>> km = KeyManager() >>> km.delete_key("0123456789ABCDEF0123456789ABCDEF01234567") True """ try: r = self.gpg.delete_keys(fingerprint) if r.status != 'ok': raise ValueError(r.status) except ValueError as e: log.error("Key not found: %s", e) self.status = _('Key not found!') return False self.status = _('Key removed') return True
def import_allowance(self): """Import an Allowance from a YAML file. Update the :class:`pharmaship.inventory.models.Allowance` info or create it from scratch. :return: Allowance instance or ``False`` in case of import error. :rtype: models.Allowance or bool """ content = get_file("inventory/allowance.yaml", self.tar) if not content: return False try: deserialized_allowance = serializers.deserialize("yaml", content) deserialized_allowance = list(deserialized_allowance) except serializers.base.DeserializationError as error: log.error("Cannot deserialize allowance: %s", error) return False for allowance in deserialized_allowance: obj = update_allowance(allowance.object, self.key['keyid'][-8:]) break # FUTURE: Only one allowance per file? return obj
def test_create_molecules(self): required = rescue_bag.get_required(self.params) output = rescue_bag.create_molecules(required["molecules"].keys(), required["molecules"]) image_field = TypeDefinition(name='image_field', included_types=(ImageFieldFile, ), excluded_types=()) Validator.types_mapping['image_field'] = image_field schema_path = settings.VALIDATOR_PATH.joinpath("parsers", "rescue_bag", "single_item.json") schema = json.loads(schema_path.read_text()) validator = Validator(schema) for item in output: result = validator.validate(output[item]) if not result: log.error(validator.errors) log.debug(output[item]) self.assertTrue(result) schema = {"data": {"type": "dict", "keysrules": {"type": "integer"}}} validator = Validator(schema) self.assertTrue(validator.validate({"data": output}))
def export_pdf(html_string, filename): """Export the equipment inventory in PDF.""" css_path = os.path.join(settings.PHARMASHIP_REPORTS, filename) try: with open(css_path, "r") as fdesc: css_string = fdesc.read() except IOError as error: log.error("CSS file not readable: %s", error) return None # Create a temporary file tmp_file = tempfile.NamedTemporaryFile(prefix="pharmaship_", suffix=".pdf", delete=False) font_config = FontConfiguration() html = HTML(string=html_string) css = CSS(string=css_string, font_config=font_config) html.write_pdf(target=tmp_file.name, stylesheets=[css], font_config=font_config) query_count_all() return tmp_file.name
def get_base(type, content, model=None): """Return a model instance according to the type and model if provided. If the `model` is not provided, it is retrieved from the `type` structure. On some `model` (ie: :class:`pharmaship.inventory.models.RescueBagReqQty`), the type can be either :class:`pharmaship.inventory.models.Equipment` or :class:`pharmaship.inventory.models.Molecule`. :param type: Model class of base field (Django internal). :type type: models.Equipment or models.Molecule :param dict content: Dictionnary with all natural key fields for the\ related base. :param model: Model class of base item to serialize. :type model: models.Equipment or models.Molecule :return: A model instance or ``None`` if not found. :rtype: models.Equipment or models.Molecule or None """ if not model: try: model = type.field.related_model except AttributeError as error: log.error("Model class not found: %s", error) return None try: instance = model.objects.get_by_natural_key(**content) except model.DoesNotExist: log.error("%s instance does not exist.", model) log.debug(content) return None return instance
def refresh_single_grid(self, visible_child_name): try: visible_kit_id = int(visible_child_name.split("-")[-1]) except ValueError as error: log.error("Wrong child name (not integer found). %s", error) return child_builder = self.children[visible_kit_id] grid = child_builder.get_object("grid") for child in grid.get_children(): child.destroy() kits = models.FirstAidKit.objects.filter(id=visible_kit_id).order_by("id").prefetch_related("items")[:self.params.setting.first_aid_kit] data = parser(self.params, kits) # Toggle item toggle_row_num = None if self.toggled[visible_kit_id]: toggle_row_num = self.toggled[visible_kit_id][0] - 1 # Reset toggled value self.toggled[visible_kit_id] = False self.build_grid(child_builder, data[0], toggle_row_num) return
def test_get_transactions(self): schema_path = settings.VALIDATOR_PATH.joinpath( "parsers", "rescue_bag", "get_transactions.json") schema = json.loads(schema_path.read_text()) validator = Validator(schema) # Test for medicines content_type = self.params.content_types["medicine"] items = models.Medicine.objects.filter(used=False).values_list( "id", flat=True) output = rescue_bag.get_transactions(content_type, items) result = validator.validate({"data": output}) if not result: log.error(validator.errors) log.debug(output) self.assertTrue(result) # Test for articles content_type = self.params.content_types["article"] items = models.Article.objects.filter(used=False).values_list( "id", flat=True) output = rescue_bag.get_transactions(content_type, items) result = validator.validate({"data": output}) if not result: log.error(validator.errors) log.debug(output) self.assertTrue(result)
def test_merge_bags(self): required = rescue_bag.get_required(self.params) equipments = rescue_bag.get_articles(self.params, required["equipments"], [110, 111]) molecules = rescue_bag.get_medicines(self.params, required["molecules"], [110, 111]) bags = models.RescueBag.objects.all() output = rescue_bag.merge_bags(bags, molecules, equipments) image_field = TypeDefinition(name='image_field', included_types=(ImageFieldFile, ), excluded_types=()) Validator.types_mapping['image_field'] = image_field schema_path = settings.VALIDATOR_PATH.joinpath("parsers", "rescue_bag", "merged_bags.json") schema = json.loads(schema_path.read_text()) validator = Validator(schema) result = validator.validate({"data": output}) if not result: log.error(validator.errors) log.debug(output) self.assertTrue(result)
def save_kit(self, source, builder, kit): fields = { "entry": [ "name" ], "combobox": [ "location" ] } cleaned_data = utils.get_form_data(forms.FirstAidKitForm, builder, fields) if cleaned_data is None: return try: kit_obj = models.FirstAidKit.objects.get(id=kit["id"]) except models.FirstAidKit.DoesNotExist as error: log.error("First aid kit (ID %s) not found.", error) return False kit_obj.name = cleaned_data["name"] kit_obj.location_id = cleaned_data["location_id"] kit_obj.save() child = self.stack.get_child_by_name("first-aid-kit-{0}".format(kit_obj.id)) self.stack.child_set_property(child, "title", cleaned_data["name"]) self.cancel(source, builder)
def add_key(self, import_file): """Add a key to the keyring. :param file-object import_file: File object containing the key data. :return: True if the key is successfully added. :rtype: bool :Example: >>> from pathlib import Path >>> my_key_file = Path("pharmaship.pub").open() >>> km = KeyManager() >>> km.add_key(my_key_file) True """ key_data = import_file.read() r = self.gpg.import_keys(key_data) for item in r.results: if 'ok' not in item.keys(): log.error("Signature error: %s", item["text"]) self.status = _('Something went wrong! See detailed logs.') return False if r.imported == 0: log.info("Key already added.") self.status = _('Key already added') else: key = self.get_key(r.fingerprints[0]) item = {"name": key['uids'][0], "fingerprint": key['fingerprint']} log.debug(item) self.status = _('Key successfully added') return True
def test_telemedical_parser(self): """Check conformity of parser's output. Proceed in two steps: 1. Check the conformity of output items 2. Check the conformity of output keys Use Cerberus for checking conformity. """ output = parsers.laboratory.parser(self.params) schema_path = settings.VALIDATOR_PATH / "parsers" / "telemedical.json" schema = json.loads(schema_path.read_text()) group_type = TypeDefinition( name='equipment_group', included_types=(models.EquipmentGroup,), excluded_types=() ) image_field = TypeDefinition( name='image_field', included_types=(ImageFieldFile,), excluded_types=() ) Validator.types_mapping['equipment_group'] = group_type Validator.types_mapping['image_field'] = image_field validator = Validator(schema) dict_result = {"data": output} result = validator.validate(dict_result) if not result: log.error(validator.errors) log.debug(output) self.assertTrue(result)
def handle(self, *args, **options): if "fingerprint" in options: regex = re.search(r"^[0-9a-fA-F]{40}$", options["fingerprint"]) if not regex: log.error("Fingerprint not correct.") return False if "func" in options: options['func'](options)
def allowance(self, args): """Export selected `Allowance` instance in a tar file.""" log.debug("Allowance export") try: allowance = models.Allowance.objects.get(id=args["id"]) except models.Allowance.DoesNotExist: log.error("Allowance does not exists.") exit() create_archive(allowance, args["filename"])
def deserialize_json_file(data, tar, allowance): """Deserialize a JSON file contained in the tar file. :param dict data: Dictionnary with filename and model related. The \ following keys must be present: * ``filename``: the name of the JSON file to extract from the tar \ archive; * ``model``: the class of model to deserialize \ (ie: :class:`pharmaship.inventory.models.MoleculeReqQty`). :param tarfile.TarFile tar: tar file archive containing the file to extract :param allowance: allowance instance to rattach :type allowance: models.Allowance :return: List of `model` instances. :rtype: list """ content = get_file(data["filename"], tar) if not content: return False try: item_data = json.loads(content) except json.decoder.JSONDecodeError as error: log.error("Corrupted JSON file: %s", error) return False objects = [] for item in item_data: if "content_type" not in item: base = get_base(type=data["model"].base, content=item["base"]) else: ct = get_model(item["content_type"]) if ct is None: return False base = get_base(type=data["model"].base, content=item["base"], model=ct.model_class()) if not base: log.error("Base for item not found.") log.debug(item) return False instance = data["model"](allowance=allowance, base=base, required_quantity=item["required_quantity"]) objects.append(instance) return objects
def test_get_required(self): output = rescue_bag.get_required(self.params) schema_path = settings.VALIDATOR_PATH.joinpath("parsers", "rescue_bag", "get_required.json") schema = json.loads(schema_path.read_text()) validator = Validator(schema) result = validator.validate(output) if not result: log.error(validator.errors) log.debug(output) self.assertTrue(result)
def test_search(self): call_command("loaddata", self.assets / "test.dump.yaml") text = "Doli" params = GlobalParameters() output = search.search(text, params) schema_path = settings.VALIDATOR_PATH.joinpath("search.json") schema = json.loads(schema_path.read_text()) validator = Validator(schema) result = validator.validate({"data": output}) if not result: log.error(validator.errors) log.debug(output) self.assertTrue(result)
def check_tarfile(data): """Check that the data input is a valid Tar file. :param bytes data: binary string issued from GPG armor decoding containing\ a tar file. :return: A Tarfile object. :rtype: tarfile.TarFile """ try: tar = tarfile.open(fileobj=io.BytesIO(data), mode="r") return tar except (tarfile.ReadError, tarfile.CompressionError) as error: log.error("File is not a valid Tar file. %s", error) return False
def import_molecule(self): """Import Molecule objects from a YAML file. Use Django's update_or_create method for :class:`pharmaship.inventory.models.Molecule`. :return: ``True`` if successful import, ``False`` otherwise. :rtype: bool """ content = get_file("inventory/molecule_obj.yaml", self.tar) if not content: return False try: deserialized_list = serializers.deserialize("yaml", content) deserialized_list = list(deserialized_list) except serializers.base.DeserializationError as error: log.error("Cannot deserialize molecule objects: %s", error) return False for molecule in deserialized_list: # Unique: (name, roa, dosage_form, composition) unique_values = { 'name': molecule.object.name, 'roa': molecule.object.roa, 'dosage_form': molecule.object.dosage_form, 'composition': molecule.object.composition, } molecule_dict = dict(unique_values) # Hard copy molecule_dict['medicine_list'] = molecule.object.medicine_list molecule_dict['group'] = molecule.object.group molecule_dict['remark'] = molecule.object.remark # TODO: DB calls optimization obj, created = models.Molecule.objects.update_or_create( defaults=molecule_dict, **unique_values) # Add M2M relations try: if molecule.m2m_data['tag']: obj.tag = molecule.m2m_data['tag'] obj.save() except KeyError: pass if created: log.debug("Created molecule: %s", obj) return True
def get_file(filename, tar): """Extract a file from a tar archive. :param str filename: Filename to extract from tar file. :param tarfile.TarFile tar: tar file instance. :return: Content of the file or ``False`` if the file cannot be accessed. :rtype: bytes or bool """ try: fdesc = tar.extractfile(filename) except KeyError: log.error("File `%s` not found.", filename) return False return fdesc.read()
def check_signature(self): """Check the signature of the package. Decoded data is stored in ``self.data`` property. :return: ``True`` if the signature is correct, ``False`` otherwise. :rtype: bool """ res = self.km.check_signature(self.content) if not res: log.error("Error during signature check: %s", self.km.status) self.status = _("Signature not validated. See detailled log.") return False # Save the result in the instance self.data = res return True
def create_archive(allowance, file_obj): """Create an archive from the given `Allowance` instance. The response is a tar.gz file containing YAML files generated by the function `serialize_allowance`. """ # Creating a tar.gz archive hashes = [] serialized_data, equipment_list = serialize_allowance( allowance=allowance, content_types=get_content_types() ) with tarfile.open(fileobj=file_obj, mode='w') as tar: # Processing the database for item in serialized_data: info, f = create_tarinfo(item[0], item[1]) tar.addfile(info, f) hashes.append(get_hash(info.name, content=item[1])) # Adding the pictures of Equipment for item in get_pictures(equipment_list): picture_filename = settings.PICTURES_FOLDER / item log.debug(picture_filename) try: tar.add(picture_filename, arcname=PurePath("pictures", item)) # TODO: Detail Exception except Exception as error: log.error("Error: %s", error) hashes.append(get_hash(PurePath("pictures", item), filename=picture_filename)) # Add the MANIFEST package_content = create_package_yaml(allowance) info, f = create_tarinfo("package.yaml", package_content) tar.addfile(info, f) hashes.append(get_hash("package.yaml", content=package_content)) # Add the MANIFEST manifest_content = create_manifest(hashes) info, f = create_tarinfo("MANIFEST", manifest_content) tar.addfile(info, f) return True
def test_parser(self): output = rescue_bag.parser(self.params) image_field = TypeDefinition(name='image_field', included_types=(ImageFieldFile, ), excluded_types=()) Validator.types_mapping['image_field'] = image_field schema_path = settings.VALIDATOR_PATH.joinpath("parsers", "rescue_bag", "rescue_bag.json") schema = json.loads(schema_path.read_text()) validator = Validator(schema) result = validator.validate({"data": output}) if not result: log.error(validator.errors) log.debug(output) self.assertTrue(result)
def get_template(filename, lang): """Return a Django template.""" template_path = os.path.join(settings.PHARMASHIP_REPORTS, filename) try: with open(template_path, "r") as fdesc: template_string = fdesc.read() except IOError as error: log.error("File not readable. %s", error) return False # Force language. If not, LANGUAGE_CODE in django settings is used. translation.activate(lang) # Create Django template template = Template(template_string) return template
def get_model(data): """Return the related ContentType from `data`. :param dict data: Dictionnary containing at least following keys: * ``app_label``: the application name, * ``name``: the name of the model :return: The Django ContentType instance or ``None`` if it does not exist. :rtype: django.contrib.contenttypes.models.ContentType or None """ try: ct = ContentType.objects.get_by_natural_key( app_label=data["app_label"], model=data["name"]) except ContentType.DoesNotExist: log.error("ContentType not found.") log.debug(data) return None return ct
def get_hash(name, content=None, filename=None): """Return sha256 hash and filename for MANIFEST file.""" if content is None and filename is None: return None m = hashlib.sha256() if content: if isinstance(content, bytes): m.update(content) else: m.update(bytes(content, "utf-8")) elif filename: try: with open(filename, 'rb') as fdesc: m.update(fdesc.read()) except IOError as error: log.error("File %s not readable. %s", filename, error) return None return (name, m.hexdigest())
def import_equipment(self): """Import Equipment objects from a YAML file. Use Django's update_or_create method for :class:`pharmaship.inventory.models.Equipment`. :return: ``True`` if successful import, ``False`` otherwise. :rtype: bool """ content = get_file("inventory/equipment_obj.yaml", self.tar) if not content: return False try: deserialized_list = serializers.deserialize("yaml", content) deserialized_list = list(deserialized_list) except serializers.base.DeserializationError as error: log.error("Cannot deserialize equipment objects: %s", error) return False for equipment in deserialized_list: # Unique: (name, packaging, perishable, consumable) unique_values = { 'name': equipment.object.name, 'packaging': equipment.object.packaging, 'perishable': equipment.object.perishable, 'consumable': equipment.object.consumable } equipment_dict = dict(unique_values) # Hard copy equipment_dict["group"] = equipment.object.group equipment_dict['picture'] = equipment.object.picture equipment_dict['remark'] = equipment.object.remark # TODO: DB calls optimization obj, created = models.Equipment.objects.update_or_create( defaults=equipment_dict, **unique_values) if created: log.debug("Created equipment: %s", obj) return True
def deploy(self): """Propagate the import to concerned modules. For each module listed in the configuration, the import class ``update()`` method is called. :return: ``True`` if all updates are applied correctly, ``False``\ otherwise :rtype: bool """ for module in self.modules: import_class = load_module(module) if not import_class: self.status = _("Module import error. See detailed log.") return False data_import = import_class(tar=self.archive, conf=self.conf, key=self.km.key) if not (hasattr(data_import, "update") and callable(data_import.update)): log.error("Module %s has no DataImport.update method.", module) self.status = _( "Target module has no update method. See detailed log.") return False step_result = data_import.update() if not step_result: msg = _("Import of module {0} failed. See detailed logs." ).format(module) log.error(msg) else: msg = _("Import of module {0} succeeded.").format(module) log.info(msg) self.import_log.append({'name': module, 'value': msg}) self.status = _("Import success.") return True
def test_parser(self): kits = models.FirstAidKit.objects.all() output = first_aid.parser(self.params, kits) self.assertIsInstance(output, list) image_field = TypeDefinition(name='image_field', included_types=(ImageFieldFile, ), excluded_types=()) Validator.types_mapping['image_field'] = image_field schema_path = settings.VALIDATOR_PATH.joinpath("parsers", "first_aid", "first_aid_kit.json") schema = json.loads(schema_path.read_text()) validator = Validator(schema) for item in output: result = validator.validate(item) if not result: log.error(validator.errors) log.debug(item) self.assertTrue(result)