예제 #1
0
def build_move_form(node: Node) -> FlaskForm:
    class Form(FlaskForm):  # type: ignore
        is_node_form = HiddenField()
        checkbox_values = HiddenField()
        selection = SelectMultipleField(
            '', [InputRequired()],
            coerce=int,
            option_widget=widgets.CheckboxInput(),
            widget=widgets.ListWidget(prefix_label=False))
        save = SubmitField(uc_first(_('move entities')))

    root = g.nodes[node.root[-1]]
    setattr(Form, str(root.id), TreeField(str(root.id)))
    form = Form(obj=node)
    choices = []
    if root.class_.name == 'administrative_unit':
        for entity in node.get_linked_entities('P89', True):
            place = entity.get_linked_entity('P53', True)
            if place:
                choices.append((entity.id, place.name))
    elif root.name in app.config['PROPERTY_TYPES']:
        for row in Link.get_entities_by_node(node):
            domain = Entity.get_by_id(row['domain_id'])
            range_ = Entity.get_by_id(row['range_id'])
            choices.append((row['id'], domain.name + ' - ' + range_.name))
    else:
        for entity in node.get_linked_entities('P2', True):
            choices.append((entity.id, entity.name))
    form.selection.choices = choices
    return form
예제 #2
0
def hierarchy_update(id_: int) -> Union[str, Response]:
    hierarchy = g.nodes[id_]
    if hierarchy.standard:
        abort(403)
    form = build_form('hierarchy', hierarchy)
    form.forms.choices = Node.get_form_choices(hierarchy)
    if hasattr(form, 'multiple') and form.multiple.data:
        form.multiple.render_kw = {'disabled': 'disabled'}
    if form.validate_on_submit():
        if form.name.data != hierarchy.name and Node.get_nodes(form.name.data):
            flash(_('error name exists'), 'error')
        else:
            save(form, hierarchy)
            flash(_('info update'), 'info')
        tab = 'value' if g.nodes[id_].value_type else 'custom'
        return redirect(
            f"{url_for('node_index')}#menu-tab-{tab}_collapse-{hierarchy.id}")
    form.multiple = hierarchy.multiple
    table = Table(paging=False)
    for form_id, form_ in hierarchy.forms.items():
        count = Node.get_form_count(hierarchy, form_id)
        table.rows.append([
            g.classes[form_['name']].label,
            format_number(count) if count else link(
                _('remove'),
                url_for('remove_form', id_=hierarchy.id, form_id=form_id))
        ])
    return render_template('display_form.html',
                           form=form,
                           table=table,
                           manual_page='entity/type',
                           title=_('types'),
                           crumbs=[[_('types'),
                                    url_for('node_index')], hierarchy,
                                   _('edit')])
예제 #3
0
def build_move_form(form: Any, node: Node) -> FlaskForm:
    root = g.nodes[node.root[-1]]
    setattr(form, str(root.id), TreeField(str(root.id)))
    form_instance = form(obj=node)

    # Delete custom fields except the ones specified for the form
    delete_list = [
    ]  # Can't delete fields in the loop so creating a list for later deletion
    for field in form_instance:
        if type(field) is TreeField and int(field.id) != root.id:
            delete_list.append(field.id)
    for item in delete_list:
        delattr(form_instance, item)

    choices = []
    if root.class_.code == 'E53':
        for entity in node.get_linked_entities('P89', True):
            place = entity.get_linked_entity('P53', True)
            if place:
                choices.append((entity.id, place.name))
    elif root.name in app.config['PROPERTY_TYPES']:
        for row in LinkMapper.get_entities_by_node(node):
            domain = EntityMapper.get_by_id(row.domain_id)
            range_ = EntityMapper.get_by_id(row.range_id)
            choices.append((row.id, domain.name + ' - ' + range_.name))
    else:
        for entity in node.get_linked_entities('P2', True):
            choices.append((entity.id, entity.name))

    form_instance.selection.choices = choices
    return form_instance
예제 #4
0
def node_move_entities(id_: int) -> Union[str, Response]:
    node = g.nodes[id_]
    root = g.nodes[node.root[-1]]
    if root.value_type:  # pragma: no cover
        abort(403)
    form = build_move_form(node)
    if form.validate_on_submit():
        Transaction.begin()
        Node.move_entities(node,
                           getattr(form, str(root.id)).data,
                           form.checkbox_values.data)
        Transaction.commit()
        flash(_('Entities were updated'), 'success')
        if node.class_.name == 'administrative_unit':
            tab = 'places'
        elif root.standard:
            tab = 'standard'
        elif node.value_type:  # pragma: no cover
            tab = 'value'
        else:
            tab = 'custom'
        return redirect(
            f"{url_for('node_index')}#menu-tab-{tab}_collapse-{root.id}")
    getattr(form, str(root.id)).data = node.id
    return render_template('types/move.html',
                           table=Table(header=['#', _('selection')],
                                       rows=[[item, item.label.text]
                                             for item in form.selection]),
                           root=root,
                           form=form,
                           entity=node,
                           crumbs=[[_('types'),
                                    url_for('node_index')], root, node,
                                   _('move entities')])
예제 #5
0
def node_move_entities(id_: int) -> Union[str, Response]:
    node = g.nodes[id_]
    root = g.nodes[node.root[-1]]
    if node.class_.name == 'administrative_unit':
        tab_hash = '#menu-tab-places_collapse-'
    elif root.standard:
        tab_hash = '#menu-tab-standard_collapse-'
    elif node.value_type:  # pragma: no cover
        tab_hash = '#menu-tab-value_collapse-'
    else:
        tab_hash = '#menu-tab-custom_collapse-'
    if root.value_type:  # pragma: no cover
        abort(403)
    form = build_move_form(node)
    if form.validate_on_submit():
        Transaction.begin()
        Node.move_entities(node, getattr(form, str(root.id)).data, form.checkbox_values.data)
        Transaction.commit()
        flash(_('Entities were updated'), 'success')
        return redirect(url_for('node_index') + tab_hash + str(root.id))
    getattr(form, str(root.id)).data = node.id
    return render_template(
        'types/move.html',
        node=node,
        root=root,
        form=form,
        title=_('types'),
        crumbs=[[_('types'), url_for('node_index')], root, node, _('move entities')])
예제 #6
0
def remove_form(id_: int, form_id: int) -> Response:
    root = g.nodes[id_]
    if Node.get_form_count(root, form_id):
        abort(403)  # pragma: no cover
    try:
        Node.remove_form_from_hierarchy(form_id, root.id)
        flash(_('info update'), 'info')
    except Exception as e:  # pragma: no cover
        logger.log('error', 'database', 'remove form from hierarchy failed', e)
        flash(_('error database'), 'error')
    return redirect(url_for('hierarchy_update', id_=id_))
예제 #7
0
 def check_single_type_duplicates() -> List[List[str]]:
     from openatlas.models.node import Node
     from openatlas.models.entity import Entity
     data = []
     for node in g.nodes.values():
         if node.root or node.multiple or node.value_type:
             continue  # pragma: no cover
         node_ids = Node.get_all_sub_ids(node)
         if not node_ids:
             continue  # pragma: no cover
         for id_ in Db.check_single_type_duplicates(node_ids):
             offending_nodes = []
             entity = Entity.get_by_id(id_, nodes=True)
             for entity_node in entity.nodes:
                 if g.nodes[entity_node.root[-1]].id != node.id:
                     continue  # pragma: no cover
                 offending_nodes.append(
                     '<a href="{url}">{label}</a> {name}'.format(
                         label=uc_first(_('remove')),
                         name=entity_node.name,
                         url=url_for('admin_delete_single_type_duplicate',
                                     entity_id=entity.id,
                                     node_id=entity_node.id)))
             data.append([
                 link(entity), entity.class_.name,
                 link(g.nodes[node.id]),
                 '<br><br><br><br><br>'.join(offending_nodes)
             ])
     return data
예제 #8
0
def before_request() -> None:
    from openatlas.models.model import CidocClass, CidocProperty
    from openatlas.models.node import Node
    from openatlas.models.settings import Settings
    from openatlas.models.reference_system import ReferenceSystem
    if request.path.startswith('/static'):  # pragma: no cover
        return  # Avoid overhead for files if not using Apache with static alias
    open_connection(app.config)
    session['settings'] = Settings.get_settings()
    session['language'] = get_locale()
    g.cidoc_classes = CidocClass.get_all()
    g.properties = CidocProperty.get_all()

    from openatlas.models import system
    g.table_headers = system.get_table_headers()
    g.classes = system.get_system_classes()
    g.view_class_mapping = system.view_class_mapping
    g.class_view_mapping = system.get_class_view_mapping()
    g.nodes = Node.get_all_nodes()
    g.reference_systems = ReferenceSystem.get_all()
    g.file_stats = None

    # Set max file upload in MB
    app.config['MAX_CONTENT_LENGTH'] = \
        session['settings']['file_upload_max_size'] * 1024 * 1024

    if request.path.startswith('/api/'):
        ip = request.environ.get('HTTP_X_REAL_IP', request.remote_addr)
        if not current_user.is_authenticated \
                and not session['settings']['api_public'] \
                and ip not in app.config['ALLOWED_IPS']:
            raise AccessDeniedError  # pragma: no cover
예제 #9
0
def hierarchy_insert(param: str) -> Union[str, Response]:
    form = build_form('hierarchy', code=param)
    form.forms.choices = Node.get_form_choices()
    if form.validate_on_submit():
        if Node.check_hierarchy_exists(form.name.data):
            flash(_('error name exists'), 'error')
            return render_template('display_form.html', form=form)
        save(form, param=param)
        flash(_('entity created'), 'info')
        return redirect(url_for('node_index') + '#menu-tab-' + param)
    return render_template(
        'display_form.html',
        form=form,
        manual_page='entity/type',
        title=_('types'),
        crumbs=[[_('types'), url_for('node_index')], '+ ' + uc_first(_(param))])
예제 #10
0
def save(form: FlaskForm,
         node: Optional[Node] = None,
         param: Optional[str] = None) -> Optional[Node]:
    Transaction.begin()
    try:
        if node:
            Node.update_hierarchy(node, form)
        else:
            node = Entity.insert('type', sanitize(form.name.data))
            Node.insert_hierarchy(node, form, value_type=(param == 'value'))
        node.update(form)
        Transaction.commit()
    except Exception as e:  # pragma: no cover
        Transaction.rollback()
        logger.log('error', 'database', 'transaction failed', e)
        flash(_('error transaction'), 'error')
        abort(418)
    return node
예제 #11
0
 def print_standard_type(self) -> str:
     from openatlas.models.node import Node
     if not self.class_.standard_type:
         return ''
     root_id = Node.get_hierarchy(self.class_.standard_type).id
     for node in self.nodes:
         if node.root and node.root[-1] == root_id:
             return link(node)
     return ''
예제 #12
0
 def __call__(self, field: TreeField, **kwargs: Any) -> TreeMultiSelect:
     data: List[int] = []
     if field.data:
         data = ast.literal_eval(field.data) \
             if isinstance(field.data, str) else field.data
     html = render_template('forms/tree_multi_select.html',
                            field=field,
                            root=g.nodes[int(field.id)],
                            selection=sorted(
                                [g.nodes[id_].name for id_ in data]),
                            data=Node.get_tree_data(int(field.id), data))
     return super(TreeMultiSelect, self).__call__(field, **kwargs) + html
예제 #13
0
def add_types(form: Any, class_: str) -> None:
    types = OrderedDict(Node.get_nodes_for_form(class_))
    for node in types.values():  # Move standard type to top
        if node.standard and node.class_.name == 'type':
            types.move_to_end(node.id, last=False)
            break

    for node in types.values():
        if node.multiple:
            setattr(form, str(node.id), TreeMultiField(str(node.id)))
        else:
            setattr(form, str(node.id), TreeField(str(node.id)))
        if node.value_type:
            add_value_type_fields(form, node.subs)
예제 #14
0
def display_file_api(filename: str) -> Any:  # pragma: no cover
    parser = image_parser.parse_args()
    from pathlib import Path as Pathlib_path
    entity = Entity.get_by_id(int(Pathlib_path(filename).stem), nodes=True)
    license_ = None
    for node in entity.nodes:
        if node.root and node.root[-1] == Node.get_hierarchy('License').id:
            license_ = node.name
    if not license_:
        raise AccessDeniedError
    if parser['download']:
        return send_file(str(app.config['UPLOAD_DIR']) + '/' + filename,
                         as_attachment=True)
    return send_from_directory(app.config['UPLOAD_DIR'], filename)
예제 #15
0
 def __call__(self, field: TreeField, **kwargs: Any) -> TreeSelect:
     selection = ''
     selected_ids = []
     if field.data:
         field.data = field.data[0] \
             if isinstance(field.data, list) else field.data
         selection = g.nodes[int(field.data)].name
         selected_ids.append(g.nodes[int(field.data)].id)
     html = render_template('forms/tree_select.html',
                            field=field,
                            selection=selection,
                            data=Node.get_tree_data(int(field.id),
                                                    selected_ids))
     return super(TreeSelect, self).__call__(field, **kwargs) + html
예제 #16
0
def show_untyped_entities(id_: int) -> str:
    hierarchy = g.nodes[id_]
    table = Table(['name', 'class', 'first', 'last', 'description'])
    for entity in Node.get_untyped(hierarchy.id):
        table.rows.append([
            link(entity), entity.class_.label, entity.first, entity.last,
            entity.description
        ])
    return render_template('table.html',
                           entity=hierarchy,
                           table=table,
                           crumbs=[[_('types'),
                                    url_for('node_index')],
                                   link(hierarchy),
                                   _('untyped entities')])
예제 #17
0
 def get(filename: str) -> Response:
     from pathlib import Path as Pathlib_path
     entity = Entity.get_by_id(int(Pathlib_path(filename).stem), nodes=True)
     license_ = None
     for node in entity.nodes:
         if node.root and node.root[-1] == Node.get_hierarchy('License').id:
             license_ = node.name
     if not license_:
         raise AccessDeniedError
     parser = image.parse_args()
     if parser['download']:
         return send_file(f"{app.config['UPLOAD_DIR']}/{filename}",
                          as_attachment=True)
     if parser['image_size']:
         size = app.config['IMAGE_SIZE'][parser['image_size']]
         return send_from_directory(
             f"{app.config['RESIZED_IMAGES']}/{size}", filename)
     return send_from_directory(app.config['UPLOAD_DIR'], filename)
예제 #18
0
 def get_node_overview() -> Dict[str, Dict[Entity, str]]:
     nodes: Dict[str, Any] = {
         'standard': {},
         'custom': {},
         'places': {},
         'value': {}}
     for node in g.nodes.values():
         if node.root:
             continue
         type_ = 'custom'
         if node.class_.name == 'administrative_unit':
             type_ = 'places'
         elif node.standard:
             type_ = 'standard'
         elif node.value_type:
             type_ = 'value'
         nodes[type_][node.name] = GetNodeOverview.walk_tree(
             Node.get_nodes(node.name))
     return nodes
예제 #19
0
def node_index() -> str:
    nodes: Dict[str, Dict[Entity, str]] = \
        {'standard': {}, 'custom': {}, 'places': {}, 'value': {}}
    for node in g.nodes.values():
        if node.root:
            continue
        type_ = 'custom'
        if node.class_.name == 'administrative_unit':
            type_ = 'places'
        elif node.standard:
            type_ = 'standard'
        elif node.value_type:
            type_ = 'value'
        nodes[type_][node] = render_template('forms/tree_select_item.html',
                                             name=sanitize(node.name),
                                             data=walk_tree(
                                                 Node.get_nodes(node.name)))
    return render_template('types/index.html',
                           nodes=nodes,
                           title=_('types'),
                           crumbs=[_('types')])
예제 #20
0
 def test_duplicates(self) -> None:
     with app.app_context():  # type: ignore
         with app.test_request_context():
             app.preprocess_request()  # type: ignore
             event = Entity.insert('acquisition', 'Event Horizon')
             source = Entity.insert('source', 'Tha source')
             source.link('P67', event)
             source.link('P67', event)
             source_node = Node.get_hierarchy('Source')
             source.link('P2', g.nodes[source_node.subs[0]])
             source.link('P2', g.nodes[source_node.subs[1]])
         rv = self.app.get(url_for('admin_check_link_duplicates'))
         assert b'Event Horizon' in rv.data
         rv = self.app.get(url_for('admin_check_link_duplicates',
                                   delete='delete'),
                           follow_redirects=True)
         assert b'Remove' in rv.data
         rv = self.app.get(url_for('admin_delete_single_type_duplicate',
                                   entity_id=source.id,
                                   node_id=source_node.subs[0]),
                           follow_redirects=True)
         assert b'Congratulations, everything looks fine!' in rv.data
예제 #21
0
def add_reference_systems(form: Any, form_name: str) -> None:
    precisions = [('', '')]
    for id_ in Node.get_hierarchy('External reference match').subs:
        precisions.append((str(g.nodes[id_].id), g.nodes[id_].name))
    for system in g.reference_systems.values():
        if form_name not in [
                form_['name'] for form_ in system.get_forms().values()
        ]:
            continue
        setattr(
            form, 'reference_system_id_{id}'.format(id=system.id),
            StringField(system.name,
                        validators=[OptionalValidator()],
                        description=system.description,
                        render_kw={
                            'autocomplete': 'off',
                            'placeholder': system.placeholder
                        }))
        setattr(
            form, 'reference_system_precision_{id}'.format(id=system.id),
            SelectField(_('precision'),
                        choices=precisions,
                        default=system.precision_default_id))
예제 #22
0
def add_reference_systems(form: Any, form_name: str) -> None:
    precision_nodes = Node.get_hierarchy('External reference match').subs
    precisions = [('', '')] + [(str(g.nodes[id_].id), g.nodes[id_].name)
                               for id_ in precision_nodes]
    systems = list(g.reference_systems.values())
    systems.sort(key=lambda x: x.name.casefold())
    for system in systems:
        if form_name \
                not in [form_['name'] for form_ in system.get_forms().values()]:
            continue
        setattr(
            form, f'reference_system_id_{system.id}',
            StringField(uc_first(system.name), [OptionalValidator()],
                        description=system.description,
                        render_kw={
                            'autocomplete': 'off',
                            'placeholder': system.placeholder
                        }))
        setattr(
            form, f'reference_system_precision_{system.id}',
            SelectField(_('precision'),
                        choices=precisions,
                        default=system.precision_default_id))
예제 #23
0
def tree_select(name: str) -> str:
    from openatlas.models.node import Node
    return """
        <div id="{name}-tree"></div>
        <script>
            $(document).ready(function () {{
                $("#{name}-tree").jstree({{
                    "search": {{ "case_insensitive": true, "show_only_matches": true }},
                    "plugins" : ["core", "html_data", "search"],
                    "core": {{ "data": {tree_data} }}
                }});
                $("#{name}-tree").on("select_node.jstree", function (e, data) {{
                    document.location.href = data.node.original.href;
                }});
                $("#{name}-tree-search").keyup(function() {{
                    if (this.value.length >= {min_chars}) {{
                        $("#{name}-tree").jstree("search", $(this).val());
                    }}
                }});
            }});
        </script>""".format(
        min_chars=session['settings']['minimum_jstree_search'],
        name=sanitize(name),
        tree_data=walk_tree(Node.get_nodes(name)))
예제 #24
0
def before_request() -> None:
    from openatlas.models.model import CidocClass, CidocProperty
    from openatlas.models.node import Node
    from openatlas.models.settings import Settings
    from openatlas.models.reference_system import ReferenceSystem
    if request.path.startswith('/static'):  # pragma: no cover
        return  # Only needed if not running with Apache and static alias
    open_connection(app.config)
    session['settings'] = Settings.get_settings()
    session['language'] = get_locale()
    g.cidoc_classes = CidocClass.get_all()
    g.properties = CidocProperty.get_all()

    from openatlas.models import system
    g.table_headers = system.get_table_headers()
    g.classes = system.get_system_classes()
    g.view_class_mapping = system.view_class_mapping
    g.class_view_mapping = system.get_class_view_mapping()
    g.nodes = Node.get_all_nodes()
    g.reference_systems = ReferenceSystem.get_all()

    # Set max file upload in MB
    app.config['MAX_CONTENT_LENGTH'] = session['settings'][
        'file_upload_max_size'] * 1024 * 1024
예제 #25
0
 def get_type_tree() -> List[Dict[int, Dict[str, Any]]]:
     return [{
         id_: GetTypeTree.serialize_to_json(node)
     } for id_, node in Node.get_all_nodes().items()]
예제 #26
0
    def test_place(self) -> None:
        with app.app_context():  # type: ignore
            rv = self.app.get(url_for('insert', class_='place'))
            assert b'+ Place' in rv.data
            with app.test_request_context():
                app.preprocess_request()  # type: ignore
                unit_node = Node.get_hierarchy('Administrative unit')
                unit_sub1 = g.nodes[unit_node.subs[0]]
                unit_sub2 = g.nodes[unit_node.subs[1]]
                reference = Entity.insert('external_reference',
                                          'https://openatlas.eu')
                place_node = Node.get_hierarchy('Place')
                source = Entity.insert('source', 'Necronomicon')
            geonames = \
                f"reference_system_id_" \
                f"{ReferenceSystem.get_by_name('GeoNames').id}"
            precision = Node.get_hierarchy('External reference match').subs[0]
            data = {
                'name': 'Asgard',
                'alias-0': 'Valhöll',
                unit_node.id: str([unit_sub1.id, unit_sub2.id]),
                geonames: '123456',
                self.precision_geonames: precision,
                self.precision_wikidata: ''
            }
            rv = self.app.post(url_for('insert',
                                       class_='place',
                                       origin_id=reference.id),
                               data=data,
                               follow_redirects=True)
            assert b'Asgard' in rv.data \
                   and b'An entry has been created' in rv.data
            rv = self.app.get(url_for('entity_view', id_=precision))
            assert b'Asgard' in rv.data
            rv = self.app.get(
                url_for('entity_view',
                        id_=ReferenceSystem.get_by_name('GeoNames').id))
            assert b'Asgard' in rv.data

            data['gis_points'] = """[{
                "type": "Feature",
                "geometry": {"type":"Point","coordinates":[9,17]},
                "properties": {
                    "name": "Valhalla",
                    "description": "",
                    "shapeType": "centerpoint"}}]"""
            data['gis_lines'] = """[{
                "type": "Feature",
                "geometry":{
                    "type": "LineString",
                    "coordinates": [
                        [9.75307425847859,17.8111792731339],
                        [9.75315472474904,17.8110005175436],
                        [9.75333711496205,17.8110873417098]]},
                "properties": {
                    "name": "",
                    "description": "",
                    "shapeType": "line"}}]"""
            data['gis_polygons'] = """[{
                "type": "Feature",
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [[
                        [9.75307425847859,17.8111792731339],
                        [9.75315472474904,17.8110005175436],
                        [9.75333711496205,17.8110873417098],
                        [9.75307425847859,17.8111792731339]]]},
                "properties":{
                    "name": "",
                    "description": "",
                    "shapeType": "shape"}}]"""
            data[place_node.id] = place_node.subs
            data['continue_'] = 'yes'
            rv = self.app.post(url_for('insert',
                                       class_='place',
                                       origin_id=source.id),
                               data=data,
                               follow_redirects=True)
            assert b'Necronomicon' in rv.data
            with app.test_request_context():
                app.preprocess_request()  # type: ignore
                places = Entity.get_by_class('place')
                place = places[0]
                place2 = places[1]
                location = place2.get_linked_entity_safe('P53')
                actor = Entity.insert('person', 'Milla Jovovich')
                actor.link('P74', location)
            assert b'Necronomicon' in rv.data
            rv = self.app.get(url_for('index', view='place'))
            assert b'Asgard' in rv.data
            rv = self.app.get(url_for('update', id_=place.id))
            assert b'Valhalla' in rv.data
            data['continue_'] = ''
            data['alias-1'] = 'Val-hall'
            data['geonames_id'] = '321'
            rv = self.app.post(url_for('update', id_=place.id),
                               data=data,
                               follow_redirects=True)
            assert b'Val-hall' in rv.data

            # Test error when viewing the corresponding location
            rv = self.app.get(url_for('entity_view', id_=place.id + 1))
            assert b'be viewed directly' in rv.data

            # Test with same GeoNames id
            rv = self.app.post(url_for('update', id_=place.id),
                               data=data,
                               follow_redirects=True)
            assert b'Val-hall' in rv.data

            # Test with same GeoNames id but different precision
            data['geonames_precision'] = ''
            rv = self.app.post(url_for('update', id_=place.id),
                               data=data,
                               follow_redirects=True)
            assert b'Val-hall' in rv.data

            # Test update without the previous GeoNames id
            data['geonames_id'] = ''
            rv = self.app.post(url_for('update', id_=place.id),
                               data=data,
                               follow_redirects=True)
            assert b'Val-hall' in rv.data

            with app.test_request_context():
                app.preprocess_request()  # type: ignore
                event = Entity.insert('acquisition', 'Valhalla rising')
                event.link('P7', location)
                event.link('P24', location)
            rv = self.app.get(url_for('entity_view', id_=place2.id))
            assert rv.data and b'Valhalla rising' in rv.data

            # Test invalid geom
            data['gis_polygons'] = """[{
                "type": "Feature", 
                "geometry": {
                    "type": "Polygon", 
                    "coordinates": [[
                        [298.9893436362036, -5.888919049309554], 
                        [299.00444983737543, -5.9138487869408545],
                        [299.00650977389887, -5.893358673645309], 
                        [298.9848804404028, -5.9070188333813585],
                        [298.9893436362036, -5.888919049309554]]]},
                "properties": {
                "name": "", 
                "description": "", 
                "shapeType": "shape"}}]"""
            rv = self.app.post(url_for('insert',
                                       class_='place',
                                       origin_id=source.id),
                               data=data,
                               follow_redirects=True)
            assert b'An invalid geometry was entered' in rv.data

            # Test Overlays
            path = \
                pathlib.Path(app.root_path) \
                / 'static' / 'images' / 'layout' / 'logo.png'
            with open(path, 'rb') as img:
                rv = self.app.post(url_for('insert',
                                           class_='file',
                                           origin_id=place.id),
                                   data={
                                       'name': 'X-Files',
                                       'file': img
                                   },
                                   follow_redirects=True)
            assert b'An entry has been created' in rv.data
            with app.test_request_context():
                app.preprocess_request()  # type: ignore
                file = Entity.get_by_class('file')[0]
                link_id = Link.insert(file, 'P67', place)[0]
            rv = self.app.get(
                url_for('overlay_insert',
                        image_id=file.id,
                        place_id=place.id,
                        link_id=link_id))
            assert b'X-Files' in rv.data
            data = {
                'top_left_easting': 42,
                'top_left_northing': 12,
                'top_right_easting': 43,
                'top_right_northing': 13,
                'bottom_left_easting': 10,
                'bottom_left_northing': 20
            }
            rv = self.app.post(url_for('overlay_insert',
                                       image_id=file.id,
                                       place_id=place.id,
                                       link_id=link_id),
                               data=data,
                               follow_redirects=True)
            assert b'Edit' in rv.data
            if os.name == "posix":  # Ignore for other OS e.g. Windows
                with app.test_request_context():
                    app.preprocess_request()  # type: ignore
                    overlay = Overlay.get_by_object(place)
                    overlay_id = overlay[list(overlay.keys())[0]].id
                rv = self.app.get(
                    url_for('overlay_update',
                            id_=overlay_id,
                            place_id=place.id,
                            link_id=link_id))
                assert b'42' in rv.data
                rv = self.app.post(url_for('overlay_update',
                                           id_=overlay_id,
                                           place_id=place.id,
                                           link_id=link_id),
                                   data=data,
                                   follow_redirects=True)
                assert b'Changes have been saved' in rv.data
                self.app.get(url_for('overlay_remove',
                                     id_=overlay_id,
                                     place_id=place.id),
                             follow_redirects=True)

            # Add to place
            rv = self.app.get(url_for('entity_add_file', id_=place.id))
            assert b'Link file' in rv.data

            rv = self.app.post(url_for('entity_add_file', id_=place.id),
                               data={'checkbox_values': str([file.id])},
                               follow_redirects=True)
            assert b'X-Files' in rv.data

            rv = self.app.get(
                url_for('reference_add', id_=reference.id, view='place'))
            assert b'Val-hall' in rv.data
            rv = self.app.get(url_for('entity_add_reference', id_=place.id))
            assert b'Link reference' in rv.data
            rv = self.app.post(url_for('entity_add_reference', id_=place.id),
                               data={
                                   'reference': reference.id,
                                   'page': '777'
                               },
                               follow_redirects=True)
            assert b'777' in rv.data

            # Place types
            rv = self.app.get(url_for('node_move_entities', id_=unit_sub1.id))
            assert b'Asgard' in rv.data

            # Test move entities of multiple node if link to new node exists
            rv = self.app.post(url_for('node_move_entities', id_=unit_sub1.id),
                               follow_redirects=True,
                               data={
                                   unit_node.id: unit_sub2.id,
                                   'selection': location.id,
                                   'checkbox_values': str([location.id])
                               })
            assert b'Entities were updated' in rv.data

            # Test move entities of multiple node
            rv = self.app.post(url_for('node_move_entities', id_=unit_sub2.id),
                               follow_redirects=True,
                               data={
                                   unit_node.id: unit_sub1.id,
                                   'selection': location.id,
                                   'checkbox_values': str([location.id])
                               })
            assert b'Entities were updated' in rv.data

            # Subunits
            data = {
                'name': "Try continue",
                'continue_': 'sub',
                self.precision_geonames: precision,
                self.precision_wikidata: ''
            }
            self.app.get(url_for('insert', class_='place'))
            rv = self.app.post(url_for('insert', class_='place'),
                               data=data,
                               follow_redirects=True)
            assert b'Insert and add strati' in rv.data
            data['name'] = "It's not a bug, it's a feature!"
            rv = self.app.get(
                url_for('insert',
                        class_='stratigraphic_unit',
                        origin_id=place.id))
            assert b'Insert and add find' in rv.data
            rv = self.app.post(url_for('insert',
                                       class_='place',
                                       origin_id=place.id),
                               data=data)
            feat_id = rv.location.split('/')[-1]
            self.app.get(url_for('insert', class_='place', origin_id=feat_id))
            self.app.get(url_for('update', id_=feat_id))
            self.app.post(url_for('update', id_=feat_id), data=data)
            data['name'] = "I'm a stratigraphic unit"
            rv = self.app.post(url_for('insert',
                                       class_='place',
                                       origin_id=feat_id),
                               data=data)
            stratigraphic_id = rv.location.split('/')[-1]
            self.app.get(
                url_for('insert', class_='place', origin_id=stratigraphic_id))
            self.app.get(url_for('update', id_=stratigraphic_id))
            self.app.post(url_for('update', id_=stratigraphic_id),
                          data={'name': "I'm a stratigraphic unit"})
            dimension_node_id = Node.get_hierarchy('Dimensions').subs[0]
            data = {
                'name': 'You never find me',
                dimension_node_id: 50,
                self.precision_geonames: precision,
                self.precision_wikidata: ''
            }
            rv = self.app.post(url_for('insert',
                                       class_='find',
                                       origin_id=stratigraphic_id),
                               data=data)
            find_id = rv.location.split('/')[-1]
            rv = self.app.post(url_for('update', id_=find_id),
                               data=data,
                               follow_redirects=True)
            assert b'50' in rv.data
            self.app.get(url_for('update', id_=find_id))
            data = {
                'name': 'My human remains',
                self.precision_geonames: precision,
                self.precision_wikidata: ''
            }
            rv = self.app.post(url_for('insert',
                                       class_='human_remains',
                                       origin_id=stratigraphic_id),
                               data=data)
            human_remains_id = rv.location.split('/')[-1]
            rv = self.app.get(url_for('update', id_=human_remains_id))
            assert b'My human remains' in rv.data
            rv = self.app.get('/')
            assert b'My human remains' in rv.data

            rv = self.app.get(url_for('entity_view', id_=feat_id))
            assert b'not a bug' in rv.data
            rv = self.app.get(url_for('entity_view', id_=stratigraphic_id))
            assert b'a stratigraphic unit' in rv.data
            rv = self.app.get(url_for('entity_view', id_=find_id))
            assert b'You never' in rv.data
            rv = self.app.get(url_for('index',
                                      view='place',
                                      delete_id=place.id),
                              follow_redirects=True)
            assert b'not possible if subunits' in rv.data
            rv = self.app.get(url_for('index', view='place',
                                      delete_id=find_id),
                              follow_redirects=True)
            assert b'The entry has been deleted.' in rv.data
            rv = self.app.get(
                url_for('index', view='place', delete_id=place2.id))
            assert b'The entry has been deleted.' in rv.data
예제 #27
0
    def test_reference_system(self) -> None:
        with app.app_context():  # type: ignore
            rv = self.app.get(url_for('index', view='reference_system'))
            assert b'GeoNames' in rv.data
            geonames = ReferenceSystem.get_by_name('GeoNames')
            wikidata = ReferenceSystem.get_by_name('Wikidata')
            precision_id = Node.get_hierarchy(
                'External reference match').subs[0]

            rv = self.app.get(url_for('insert', class_='reference_system'))
            assert b'Resolver URL' in rv.data
            data = {
                'name': 'Wikipedia',
                'website_url': 'https://wikipedia.org',
                'resolver_url': 'https://wikipedia.org',
                'forms': [geonames.forms[0]]
            }
            rv = self.app.post(url_for('insert', class_='reference_system'),
                               follow_redirects=True,
                               data=data)
            assert b'An entry has been created.' in rv.data
            wikipedia_id = ReferenceSystem.get_by_name('Wikipedia').id
            rv = self.app.get(url_for('index',
                                      view='reference_system',
                                      delete_id=wikipedia_id),
                              follow_redirects=True)
            assert b'Deletion not possible if forms are attached' in rv.data
            rv = self.app.get(url_for('reference_system_remove_form',
                                      system_id=wikipedia_id,
                                      form_id=geonames.forms[0]),
                              follow_redirects=True)
            assert b'Changes have been saved' in rv.data
            rv = self.app.get(
                url_for('index',
                        view='reference_system',
                        delete_id=wikipedia_id))
            assert b'The entry has been deleted' in rv.data

            rv = self.app.post(url_for('update', id_=geonames.id))
            assert b'Website URL' in rv.data
            data = {
                'name': 'GeoNames',
                Node.get_hierarchy('External reference match').id:
                precision_id,
                'website_url': 'https://www.geonames2.org/',
                'resolver_url': 'https://www.geonames2.org/'
            }
            rv = self.app.post(url_for('update', id_=geonames.id),
                               follow_redirects=True,
                               data=data)
            assert b'Changes have been saved.' in rv.data
            rv = self.app.post(url_for('update', id_=geonames.id),
                               follow_redirects=True,
                               data=data)
            assert b'https://www.geonames2.org/' in rv.data
            rv = self.app.post(url_for('insert', class_='person'),
                               data={
                                   'name': 'Actor test',
                                   'reference_system_id_' + str(wikidata.id):
                                   'Q123',
                                   self.precision_geonames: '',
                                   self.precision_wikidata: precision_id
                               })
            person_id = rv.location.split('/')[-1]
            rv = self.app.get(url_for('entity_view', id_=wikidata.id),
                              follow_redirects=True)
            assert b'Actor test' in rv.data
            rv = self.app.get(url_for('entity_view', id_=person_id),
                              follow_redirects=True)
            assert b'Wikidata' in rv.data
            rv = self.app.get(url_for('update', id_=person_id))
            assert b'Q123' in rv.data

            # Testing errors
            rv = self.app.post(url_for('insert', class_='reference_system'),
                               follow_redirects=True,
                               data={'name': 'GeoNames'})
            assert b'A transaction error occurred' in rv.data
            rv = self.app.get(
                url_for('index',
                        view='reference_system',
                        delete_id=geonames.id))
            assert b'403' in rv.data
            rv = self.app.post(url_for('insert', class_='person'),
                               data={
                                   'name':
                                   'Actor with Wikidata but without precision',
                                   'reference_system_id_' + str(wikidata.id):
                                   'Q123',
                                   self.precision_geonames: '',
                                   self.precision_wikidata: ''
                               })
            assert b'required' in rv.data
            rv = self.app.post(url_for('insert', class_='person'),
                               data={
                                   'name': 'Actor with invalid Wikidata id',
                                   'reference_system_id_' + str(wikidata.id):
                                   'invalid id',
                                   self.precision_geonames: '',
                                   self.precision_wikidata: precision_id
                               })
            assert b'Wrong id format' in rv.data
            rv = self.app.post(url_for('insert', class_='place'),
                               data={
                                   'name': 'Reference test',
                                   'reference_system_id_' + str(geonames.id):
                                   'invalid id',
                                   self.precision_geonames: '',
                                   self.precision_wikidata: ''
                               })
            assert b'Wrong id format' in rv.data
            rv = self.app.get(url_for('reference_system_remove_form',
                                      system_id=geonames.id,
                                      form_id=geonames.forms[0]),
                              follow_redirects=True)
            assert b'Changes have been saved' in rv.data
            rv = self.app.get(
                url_for('index',
                        view='reference_system',
                        delete_id=geonames.id))
            assert b'403 - Forbidden' in rv.data
예제 #28
0
def add_fields(form: Any, class_: str, code: Union[str, None],
               item: Union[Entity, Node, Link,
                           None], origin: Union[Entity, Node, None]) -> None:
    if class_ == 'actor_actor_relation':
        setattr(form, 'inverse', BooleanField(_('inverse')))
        if not item:
            setattr(form, 'actor',
                    TableMultiField(_('actor'), [InputRequired()]))
            setattr(form, 'relation_origin_id', HiddenField())
    elif class_ in ['activity', 'acquisition', 'move']:
        setattr(form, 'event_id', HiddenField())
        setattr(form, 'event', TableField(_('sub event of')))
        if class_ == 'activity':
            setattr(form, 'place', TableField(_('location')))
        if class_ == 'acquisition':
            setattr(form, 'place', TableField(_('location')))
            setattr(form, 'given_place', TableMultiField(_('given place')))
        elif class_ == 'move':
            setattr(form, 'place_from', TableField(_('from')))
            setattr(form, 'place_to', TableField(_('to')))
            setattr(form, 'artifact', TableMultiField())
            setattr(form, 'person', TableMultiField())
    elif class_ == 'file' and not item:
        setattr(form, 'file', FileField(_('file'), [InputRequired()]))
    elif class_ == 'group':
        setattr(form, 'residence', TableField(_('residence')))
        setattr(form, 'begins_in', TableField(_('begins in')))
        setattr(form, 'ends_in', TableField(_('ends in')))
    elif class_ == 'hierarchy':
        if code == 'custom' or (item and not item.value_type):
            setattr(
                form, 'multiple',
                BooleanField(_('multiple'),
                             description=_('tooltip hierarchy multiple')))
        setattr(
            form, 'forms',
            SelectMultipleField(_('classes'),
                                render_kw={'disabled': True},
                                description=_('tooltip hierarchy forms'),
                                choices=[],
                                option_widget=widgets.CheckboxInput(),
                                widget=widgets.ListWidget(prefix_label=False),
                                coerce=int))
    elif class_ == 'involvement':
        if not item and origin:
            involved_with = 'actor' if origin.class_.view == 'event' else 'event'
            setattr(form, involved_with,
                    TableMultiField(_(involved_with), [InputRequired()]))
        setattr(form, 'activity', SelectField(_('activity')))
    elif class_ == 'member' and not item:
        setattr(form, 'member_origin_id', HiddenField())
        setattr(form, 'actor' if code == 'member' else 'group',
                TableMultiField(_('actor'), [InputRequired()]))
    elif class_ in g.classes and g.classes[class_].view == 'type':
        setattr(form, 'is_node_form', HiddenField())
        node = item if item else origin
        root = g.nodes[node.root[-1]] if node.root else node
        setattr(form, str(root.id), TreeField(str(root.id)))
        if root.directional:
            setattr(form, 'name_inverse', StringField(_('inverse')))
    elif class_ == 'person':
        setattr(form, 'residence', TableField(_('residence')))
        setattr(form, 'begins_in', TableField(_('born in')))
        setattr(form, 'ends_in', TableField(_('died in')))
    elif class_ == 'reference_system':
        setattr(
            form, 'website_url',
            StringField(_('website URL'),
                        validators=[OptionalValidator(),
                                    URL()]))
        setattr(
            form, 'resolver_url',
            StringField(_('resolver URL'),
                        validators=[OptionalValidator(),
                                    URL()]))
        setattr(form, 'placeholder', StringField(_('example ID')))
        precision_node_id = str(
            Node.get_hierarchy('External reference match').id)
        setattr(form, precision_node_id, TreeField(precision_node_id))
        choices = ReferenceSystem.get_form_choices(item)
        if choices:
            setattr(
                form, 'forms',
                SelectMultipleField(
                    _('forms'),
                    render_kw={'disabled': True},
                    choices=choices,
                    option_widget=widgets.CheckboxInput(),
                    widget=widgets.ListWidget(prefix_label=False),
                    coerce=int))
    elif class_ == 'source':
        setattr(form, 'artifact', TableMultiField())
예제 #29
0
 def save_nodes(self, form: FlaskForm) -> None:
     from openatlas.models.node import Node
     Node.save_entity_nodes(self, form)
예제 #30
0
    def test_event(self) -> None:
        with app.app_context():  # type: ignore
            # Create entities for file
            with app.test_request_context():
                app.preprocess_request()  # type: ignore
                actor = Entity.insert('person', 'File keeper')
                reference = Entity.insert('edition', 'Ancient Books')
                node_id = Node.get_hierarchy('Sex').subs[0]

            # Insert
            rv = self.app.get(
                url_for('insert', class_='file', origin_id=actor.id))
            assert b'+ File' in rv.data
            logo = \
                pathlib.Path(app.root_path) \
                / 'static' / 'images' / 'layout' / 'logo.png'
            with open(logo, 'rb') as img:
                rv = self.app.post(url_for('insert',
                                           class_='file',
                                           origin_id=actor.id),
                                   data={
                                       'name': 'OpenAtlas logo',
                                       'file': img
                                   },
                                   follow_redirects=True)
            assert b'An entry has been created' in rv.data
            with open(logo, 'rb') as img1, open(logo, 'rb') as img2:
                rv = self.app.post(url_for('insert',
                                           class_='file',
                                           origin_id=actor.id),
                                   data={
                                       'name': 'OpenAtlas logo',
                                       'file': [img1, img2]
                                   },
                                   follow_redirects=True)
            assert b'An entry has been created' in rv.data
            with open(logo, 'rb') as img:
                rv = self.app.post(url_for('insert',
                                           class_='file',
                                           origin_id=reference.id),
                                   data={
                                       'name': 'OpenAtlas logo',
                                       'file': img
                                   },
                                   follow_redirects=True)
            assert b'An entry has been created' in rv.data
            with app.test_request_context():
                app.preprocess_request()  # type: ignore
                files = Entity.get_by_class('file')
                file_id = files[0].id
                file_id2 = files[1].id

            # Logo
            rv = self.app.get(url_for('admin_logo'),
                              data={'file': file_id},
                              follow_redirects=True)
            assert b'OpenAtlas logo' in rv.data
            with self.app.get(
                    url_for('display_logo', filename=str(file_id) + '.png')):
                pass  # Test logo with "with" to prevent unclosed files warning
            rv = self.app.get(url_for('admin_logo', id_=file_id),
                              follow_redirects=True)
            assert b'Remove custom logo' in rv.data
            rv = self.app.get(url_for('admin_index',
                                      action="remove_logo",
                                      id_=0),
                              follow_redirects=True)
            assert b'Logo' in rv.data

            with open(
                    pathlib.Path(app.root_path) / 'views' / 'index.py', 'rb') \
                    as invalid_file:
                rv = self.app.post(url_for('insert',
                                           class_='file',
                                           origin_id=actor.id),
                                   data={
                                       'name': 'Invalid file',
                                       'file': invalid_file
                                   },
                                   follow_redirects=True)
            assert b'File type not allowed' in rv.data

            rv = self.app.post(url_for('insert',
                                       class_='file',
                                       origin_id=actor.id),
                               follow_redirects=True,
                               data={'name': 'This is not a file'})
            assert b'This field is required' in rv.data

            # View
            rv = self.app.get(url_for('entity_view', id_=file_id))
            assert b'OpenAtlas logo' in rv.data
            rv = self.app.get(url_for('entity_view', id_=file_id2))
            assert b'OpenAtlas logo' in rv.data

            with self.app.get(
                    url_for('download_file', filename=str(file_id) + '.png')):
                pass  # Calling with "with" to prevent unclosed files warning
            with self.app.get(
                    url_for('display_file', filename=str(file_id) + '.png')):
                pass  # Calling with "with" to prevent unclosed files warning

            # Index
            rv = self.app.get(url_for('index', view='file'))
            assert b'OpenAtlas logo' in rv.data

            # Set and unset as main image
            self.app.get(url_for('set_profile_image',
                                 id_=file_id,
                                 origin_id=actor.id),
                         follow_redirects=True)
            self.app.get(
                url_for('file_remove_profile_image', entity_id=actor.id))

            # Add to reference
            rv = self.app.get(
                url_for('reference_add', id_=reference.id, view='file'))
            assert b'OpenAtlas logo' in rv.data
            rv = self.app.post(url_for('reference_add',
                                       id_=reference.id,
                                       view='file'),
                               data={
                                   'file': file_id,
                                   'page': '777'
                               },
                               follow_redirects=True)
            assert b'777' in rv.data

            # Update
            rv = self.app.get(url_for('update', id_=file_id))
            assert b'OpenAtlas logo' in rv.data
            rv = self.app.post(url_for('update', id_=file_id),
                               data={'name': 'Updated file'},
                               follow_redirects=True)
            assert b'Changes have been saved' in rv.data \
                   and b'Updated file' in rv.data
            rv = self.app.get(url_for('file_add', id_=file_id, view='actor'))
            assert b'Link actor' in rv.data
            rv = self.app.post(url_for('file_add', id_=file_id, view='actor'),
                               data={'checkbox_values': [actor.id]},
                               follow_redirects=True)
            assert b'File keeper' in rv.data
            rv = self.app.post(url_for('entity_add_file', id_=node_id),
                               data={'checkbox_values': str([file_id])},
                               follow_redirects=True)
            assert b'Updated file' in rv.data

            # Delete
            for file in files:
                rv = self.app.get(
                    url_for('index', view='file', delete_id=file.id))
                assert b'The entry has been deleted' in rv.data