def user_insert() -> Union[str, Response]: form = UserForm() form.group.choices = get_groups() if not session['settings']['mail']: del form.send_info if form.validate_on_submit(): user_id = User.insert(form) flash(_('user created'), 'info') if session['settings']['mail'] and form.send_info.data: # pragma: no cover subject = _('Your account information for %(sitename)s', sitename=session['settings']['site_name']) body = _('Account information for %(username)s', username=form.username.data) + ' ' body += _('at') + ' ' + request.scheme + '://' + request.headers['Host'] + '\n\n' body += uc_first(_('username')) + ': ' + form.username.data + '\n' body += uc_first(_('password')) + ': ' + form.password.data + '\n' if send_mail(subject, body, form.email.data, False): flash(_('Sent account information mail to %(email)s.', email=form.email.data), 'info') else: flash(_('Failed to send account details to %(email)s.', email=form.email.data), 'error') if hasattr(form, 'continue_') and form.continue_.data == 'yes': return redirect(url_for('user_insert')) return redirect(url_for('user_view', id_=user_id)) return render_template( 'user/insert.html', form=form, title=_('user'), crumbs=[[_('admin'), url_for('admin_index') + '#tab-user'], '+ ' + uc_first(_('user'))])
def display_menu(self: Any, entity: Optional[Entity], origin: Optional[Entity]) -> str: """ Returns menu HTML with (bold) marked selected item.""" if not current_user.is_authenticated: return '' view_name = '' if entity: view_name = entity.class_.view if origin: view_name = origin.class_.view html = '' for item in ['source', 'event', 'actor', 'place', 'artifact', 'reference']: css = '' request_parts = request.path.split('/') if (view_name == item) or request.path.startswith('/index/' + item): css = 'active' elif len(request_parts) > 2 and request.path.startswith('/insert/'): name = request_parts[2] if name in g.class_view_mapping and g.class_view_mapping[name] == item: css = 'active' html += '<a href="/index/{item}" class="nav-item nav-link {css}">{label}</a>'.format( css=css, item=item, label=display.uc_first(_(item))) css = '' if request.path.startswith('/types') or request.path.startswith('/insert/type') or ( entity and entity.class_.view == 'type'): css = 'active' html += '<a href="{url}" class="nav-item nav-link {css}">{label}</a>'.format( css=css, url=url_for('node_index'), label=display.uc_first(_('types'))) return html
def add_buttons(form: Any, name: str, entity: Union[Entity, None], origin: Optional[Entity] = None) -> FlaskForm: setattr(form, 'save', SubmitField(_('save') if entity else _('insert'))) if entity: return form if 'continue' in forms[name] and ( name in ['involvement', 'find', 'human_remains', 'type'] or not origin): setattr(form, 'insert_and_continue', SubmitField(uc_first(_('insert and continue')))) setattr(form, 'continue_', HiddenField()) insert_and_add = uc_first(_('insert and add')) + ' ' if name == 'place': setattr(form, 'insert_and_continue', SubmitField(uc_first(_('insert and continue')))) setattr(form, 'continue_', HiddenField()) setattr(form, 'insert_continue_sub', SubmitField(insert_and_add + _('feature'))) elif name == 'feature' and origin and origin.class_.name == 'place': setattr(form, 'insert_and_continue', SubmitField(uc_first(_('insert and continue')))) setattr(form, 'continue_', HiddenField()) setattr(form, 'insert_continue_sub', SubmitField(insert_and_add + _('stratigraphic unit'))) elif name == 'stratigraphic_unit': setattr(form, 'insert_and_continue', SubmitField(uc_first(_('insert and continue')))) setattr(form, 'continue_', HiddenField()) setattr(form, 'insert_continue_sub', SubmitField(insert_and_add + _('find'))) setattr(form, 'insert_continue_human_remains', SubmitField(insert_and_add + _('human remains'))) return form
def build_table_form(class_: str, linked_entities: List[Entity]) -> str: """ Returns a form with a list of entities with checkboxes.""" if class_ == 'file': entities = Entity.get_by_class('file', nodes=True) elif class_ == 'place': entities = Entity.get_by_class('place', nodes=True, aliases=True) else: entities = Entity.get_by_view(class_) linked_ids = [entity.id for entity in linked_entities] table = Table([''] + g.table_headers[class_], order=[[1, 'asc']]) file_stats = get_file_stats() if class_ == 'file' else None for entity in entities: if entity.id in linked_ids: continue # Don't show already linked entries input_ = '<input id="selection-{id}" name="values" type="checkbox" value="{id}">'.format( id=entity.id) table.rows.append([input_] + get_base_table_data(entity, file_stats)) if not table.rows: return uc_first(_('no entries')) return """ <form class="table" id="checkbox-form" method="post"> <input id="csrf_token" name="csrf_token" type="hidden" value="{token}"> <input id="checkbox_values" name="checkbox_values" type="hidden"> {table} <input id="save" class="{class_}" name="save" type="submit" value="{link}"> </form>""".format(link=uc_first(_('link')), token=generate_csrf(), class_=app.config['CSS']['button']['primary'], table=table.display(class_))
def add_row(field: Field, label: Optional[str] = None, value: Optional[str] = None, form_id: Optional[str] = None) -> str: field.label.text = display.uc_first(field.label.text) if field.flags.required and form_id != 'login-form' and field.label.text: field.label.text += ' *' # CSS css_class = 'required' if field.flags.required else '' css_class += ' integer' if isinstance(field, IntegerField) else '' for validator in field.validators: css_class += ' email' if isinstance(validator, Email) else '' errors = ' <span class="error">{errors}</span>'.format( errors=' '.join(display.uc_first(error) for error in field.errors)) if field.errors else '' return """ <div class="table-row {css_row}"> <div>{label} {tooltip}</div> <div class="table-cell">{value} {errors}</div> </div>""".format( label=label if isinstance(label, str) else field.label, tooltip=display.tooltip(field.description), value=value if value else field(class_=css_class).replace('> ', '>'), css_row='external-reference' if field.id.startswith('reference_system_') else '', errors=errors)
def reset_confirm(code: str) -> Response: # pragma: no cover user = User.get_by_reset_code(code) if not user or not user.username or not user.email: logger.log('info', 'auth', 'unknown reset code') flash(_('invalid password reset confirmation code'), 'error') abort(404) hours = session['settings']['reset_confirm_hours'] if datetime.datetime.now() > user.password_reset_date + datetime.timedelta( hours=hours): logger.log('info', 'auth', 'reset code expired') flash(_('This reset confirmation code has expired.'), 'error') abort(404) password = User.generate_password() user.password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') user.password_reset_code = None user.password_reset_date = None user.login_failed_count = 0 user.update() subject = _('New password for %(sitename)s', sitename=session['settings']['site_name']) body = _('New password for %(username)s', username=user.username) + ' ' body += _('at') + ' ' + request.scheme + '://' + request.headers[ 'Host'] + ':\n\n' body += uc_first(_('username')) + ': ' + user.username + '\n' body += uc_first(_('password')) + ': ' + password + '\n' if send_mail(subject, body, user.email, False): flash(_('Send new password mail to %(email)s.', email=user.email), 'info') else: flash( _('Failed to send password mail to %(email)s.', email=user.email), 'error') return redirect(url_for('login'))
def breadcrumb(self: Any, crumbs: List[Any]) -> str: items = [] for item in crumbs: if not item: continue # Item can be None e.g. if a dynamic generated URL has no origin parameter elif isinstance(item, Entity) or isinstance(item, Project) or isinstance(item, User): items.append(display.link(item)) elif isinstance(item, list): items.append('<a href="{url}">{label}</a>'.format( url=item[1], label=display.truncate(display.uc_first(str(item[0]))))) else: items.append(display.uc_first(item)) return Markup(' > '.join(items))
def display_profile_image(self: Any, entity: Entity) -> str: if not entity.image_id: return '' path = display.get_file_path(entity.image_id) if not path: return '' # pragma: no cover if entity.class_.view == 'file': if path.suffix.lower() in app.config['DISPLAY_FILE_EXTENSIONS']: html = ''' <a href="{url}" rel="noopener noreferrer" target="_blank"> <img style="max-width:{width}px;" alt="image" src="{url}"> </a>'''.format( url=url_for('display_file', filename=path.name), width=session['settings']['profile_image_width']) else: html = display.uc_first(_('no preview available')) # pragma: no cover else: html = """ <a href="{url}"> <img style="max-width:{width}px;" alt="image" src="{src}"> </a>""".format( url=url_for('entity_view', id_=entity.image_id), src=url_for('display_file', filename=path.name), width=session['settings']['profile_image_width']) return Markup('<div id="profile_image_div">{html}</div>'.format(html=html))
def relation_insert(origin_id: int) -> Union[str, Response]: origin = Entity.get_by_id(origin_id) form = build_form('actor_actor_relation') form.relation_origin_id.data = origin.id if form.validate_on_submit(): Transaction.begin() try: for actor in Entity.get_by_ids(ast.literal_eval(form.actor.data)): if form.inverse.data: link_ = Link.get_by_id( actor.link('OA7', origin, form.description.data)[0]) else: link_ = Link.get_by_id( origin.link('OA7', actor, form.description.data)[0]) link_.set_dates(form) link_.type = get_link_type(form) link_.update() Transaction.commit() flash(_('entity created'), 'info') except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') if hasattr(form, 'continue_') and form.continue_.data == 'yes': return redirect(url_for('relation_insert', origin_id=origin_id)) return redirect( url_for('entity_view', id_=origin.id) + '#tab-relation') return render_template( 'display_form.html', form=form, title=_('relation'), crumbs=[[_('actor'), url_for('index', view='actor')], origin, '+ ' + uc_first(_('relation'))])
def populate_subs(nodes: Dict[int, Node]) -> None: forms = {} for row in Db.get_web_forms(): forms[row['id']] = { 'id': row['id'], 'name': row['name'], 'label': g.classes[row['name']].label if row['name'] in g.classes else uc_first(_(row['name'].replace('_', ''))), 'extendable': row['extendable'] } hierarchies = {row['id']: row for row in Db.get_hierarchies()} for node in nodes.values(): if node.root: super_ = nodes[node.root[0]] super_.subs.append(node.id) node.root = Node.get_root_path(nodes, node, node.root[0], node.root) node.standard = False node.locked = nodes[node.root[0]].locked else: hierarchy = hierarchies[node.id] node.value_type = hierarchy['value_type'] node.directional = hierarchy['directional'] node.multiple = hierarchy['multiple'] node.standard = hierarchy['standard'] node.locked = hierarchy['locked'] node.forms = { form_id: forms[form_id] for form_id in hierarchy['form_ids'] }
def reference_link_update(link_id: int, origin_id: int) -> Union[str, Response]: link_ = Link.get_by_id(link_id) origin = Entity.get_by_id(origin_id) form = AddReferenceForm() del form.reference if form.validate_on_submit(): link_.description = form.page.data link_.update() flash(_('info update'), 'info') tab = '#tab-' + (link_.range.class_.view if origin.class_.view == 'reference' else 'reference') return redirect(url_for('entity_view', id_=origin.id) + tab) form.save.label.text = _('save') form.page.data = link_.description if link_.domain.class_.name == 'external_reference': form.page.label.text = uc_first(_('link text')) linked_object = link_.domain if link_.domain.id != origin.id else link_.range return render_template('display_form.html', form=form, crumbs=[[ _(origin.class_.view), url_for('index', view=origin.class_.view) ], origin, linked_object, _('edit')])
def profile_settings(category: str) -> Union[str, Response]: if category not in ['profile', 'display'] and not is_authorized('contributor'): abort(403) # pragma: no cover form = getattr( importlib.import_module('openatlas.forms.setting'), uc_first(category) + 'Form')() if form.validate_on_submit(): for field in form: if field.type in ['CSRFTokenField', 'HiddenField', 'SubmitField']: continue if field.name == 'name': current_user.real_name = field.data elif field.name == 'email': current_user.email = field.data else: current_user.settings[field.name] = field.data Transaction.begin() try: current_user.update() current_user.update_settings(form) Transaction.commit() session['language'] = current_user.settings['language'] flash(_('info update'), 'info') except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect(url_for('profile_index') + '#tab-' + category) set_form_settings(form, True) return render_template( 'display_form.html', form=form, manual_page='profile', title=_('profile'), crumbs=[[_('profile'), url_for('profile_index') + '#tab-' + category], _(category)])
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
def display_citation_example(self: Any, code: str) -> str: text = Content.get_translation('citation_example') if not text or code != 'reference': return '' return Markup('<h1>{title}</h1>{text}'.format( title=display.uc_first(_('citation_example')), text=text))
def admin_settings(category: str) -> Union[str, Response]: if category in ['general', 'mail'] and not is_authorized('admin'): abort(403) # pragma: no cover form = getattr(importlib.import_module('openatlas.forms.setting'), uc_first(category) + 'Form')() # Get forms dynamically if form.validate_on_submit(): Transaction.begin() try: Settings.update(form) logger.log('info', 'settings', 'Settings updated') Transaction.commit() flash(_('info update'), 'info') except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') tab = 'data' if category == 'api' else category tab = 'email' if category == 'mail' else tab return redirect(url_for('admin_index') + '#tab-' + tab) set_form_settings(form) return render_template('display_form.html', form=form, manual_page='admin/' + category, title=_('admin'), crumbs=[[ _('admin'), url_for('admin_index') + '#tab-' + ('data' if category == 'api' else category) ], _(category)])
def download_button(self: Any, entity: Entity) -> str: if entity.class_.view != 'file': return '' html = '<span class="error">{msg}</span>'.format(msg=display.uc_first(_('missing file'))) if entity.image_id: path = display.get_file_path(entity.image_id) html = display.button(_('download'), url_for('download_file', filename=path.name)) return Markup(html)
def build_add_reference_form(class_: str) -> FlaskForm: class Form(FlaskForm): # type: ignore pass setattr(Form, class_, TableField(_(class_), [InputRequired()])) setattr(Form, 'page', StringField(_('page'))) setattr(Form, 'save', SubmitField(uc_first(_('insert')))) return Form()
def description(self: Any, entity: Union[Entity, Project]) -> str: if not entity.description: return '' label = _('description') if isinstance(entity, Entity) and entity.class_.name == 'source': label = _('content') return Markup("""<h2>{label}</h2><div class="description more">{description}</div>""".format( label=display.uc_first(label), description=entity.description.replace('\r\n', '<br>')))
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')))
def table_select_model(self: Any, name: str, selected: Union[CidocClass, CidocProperty, None] = None) -> str: if name in ['domain', 'range']: entities = g.cidoc_classes else: entities = g.properties table = Table(['code', 'name'], defs=[ {'orderDataType': 'cidoc-model', 'targets': [0]}, {'sType': 'numeric', 'targets': [0]}]) for id_ in entities: table.rows.append([ """<a onclick="selectFromTable(this, '{name}', '{entity_id}', '{value}')" href="#">{label}</a>""".format( name=name, entity_id=id_, value=entities[id_].code + ' ' + entities[id_].name, label=entities[id_].code), """<a onclick="selectFromTable(this, '{name}', '{entity_id}', '{value}')" href="#">{label}</a>""".format( name=name, entity_id=id_, value=entities[id_].code + ' ' + entities[id_].name, label=entities[id_].name)]) value = selected.code + ' ' + selected.name if selected else '' html = """ <input id="{name}-button" name="{name}-button" class="table-select" type="text" onfocus="this.blur()" readonly="readonly" value="{value}" onclick="$('#{name}-modal').modal('show')"> <div id="{name}-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal-dialog" role="document" style="max-width: 100%!important;"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">{name}</h5> <button type="button" class="btn btn-outline-primary btn-sm" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body">{table}</div> <div class="modal-footer"> <button type="button" class="btn btn-outline-primary btn-sm" data-dismiss="modal">{close_label}</button> </div> </div> </div> </div>""".format( name=name, value=value, close_label=display.uc_first(_('close')), table=table.display(name)) return html
def display_info(self: Any, data: Dict[str, Union[str, List[str]]]) -> str: html = '<div class="data-table">' for label, value in data.items(): if value or value == 0: if isinstance(value, list): value = '<br>'.join(value) html += ''' <div class="table-row"> <div>{label}</div> <div class="table-cell">{value}</div> </div>'''.format(label=display.uc_first(label), value=value) return Markup(html + '</div>')
def translation_insert(source_id: int) -> Union[str, Response]: source = Entity.get_by_id(source_id) form = build_form('source_translation') if form.validate_on_submit(): translation = save(form, source=source) flash(_('entity created'), 'info') if hasattr(form, 'continue_') and form.continue_.data == 'yes': return redirect(url_for('translation_insert', source_id=source.id)) return redirect(url_for('entity_view', id_=translation.id)) return render_template( 'display_form.html', form=form, crumbs=[[_('source'), url_for('index', view='source')], source, '+ ' + uc_first(_('text'))])
def import_project_insert() -> Union[str, Response]: form = ProjectForm() if form.validate_on_submit(): id_ = Import.insert_project(form.name.data, form.description.data) flash(_('project inserted'), 'info') return redirect(url_for('import_project_view', id_=id_)) return render_template( 'display_form.html', form=form, manual_page='admin/import', title=_('import'), crumbs=[[_('admin'), url_for('admin_index') + '#tab-data'], [_('import'), url_for('import_index')], '+ ' + uc_first(_('project'))])
def manual(self: Any, site: str) -> str: # Creates a link to a manual page try: parts = site.split('/') first = parts[0] second = (parts[1] if parts[1] != 'node' else 'type') + '.html' path = pathlib.Path(app.root_path) / 'static' / 'manual' / first / second if not path.exists(): # print('Missing manual link: ' + str(path)) return '' except: # pragma: no cover return '' return Markup(""" <a class="manual" href="/static/manual/{site}.html" target="_blank" title="{label}"> <i class="fas fa-book"></i></a>""".format(site=site, label=display.uc_first('manual')))
def note_insert(entity_id: int) -> Union[str, Response]: entity = Entity.get_by_id(entity_id) form = build_form('note') if form.validate_on_submit(): User.insert_note(entity_id, form.description.data, form.public.data) flash(_('note added'), 'info') return redirect(url_for('entity_view', id_=entity.id) + '#tab-note') return render_template( 'display_form.html', form=form, entity=entity, crumbs=[ [_(entity.class_.view), url_for('index', view=entity.class_.view)], entity, '+ ' + uc_first(_('note'))])
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))])
def reference_add(id_: int, view: str) -> Union[str, Response]: reference = Entity.get_by_id(id_) form = build_add_reference_form(view) if form.validate_on_submit(): entity = Entity.get_by_id(getattr(form, view).data) reference.link('P67', entity, form.page.data) return redirect( url_for('entity_view', id_=reference.id) + '#tab-' + view) if reference.class_.name == 'external_reference': form.page.label.text = uc_first(_('link text')) return render_template( 'display_form.html', form=form, title=_('reference'), crumbs=[[_('reference'), url_for('index', view='reference')], reference, _('link')])
def display_external_references(self: Any, entity: Entity) -> str: system_links = [] for link_ in entity.reference_systems: system = g.reference_systems[link_.domain.id] name = link_.description if system.resolver_url: name = '<a href="{url}" target="_blank" rel="noopener noreferrer">{name}</a>'.format( url=system.resolver_url + name, name=name) system_links.append('''{name} ({match} {at} {system_name})'''.format( name=name, match= g.nodes[link_.type.id].name, at=_('at'), system_name= display.link(link_.domain))) html = '<br>'.join(system_links) if not html: return '' return Markup('<h2>' + display.uc_first(_('external reference systems')) + '</h2>' + html)
def entity_add_reference(id_: int) -> Union[str, Response]: entity = Entity.get_by_id(id_) form = AddReferenceForm() if form.validate_on_submit(): entity.link_string('P67', form.reference.data, description=form.page.data, inverse=True) return redirect(url_for('entity_view', id_=id_) + '#tab-reference') form.page.label.text = uc_first(_('page / link text')) return render_template('display_form.html', entity=entity, form=form, crumbs=[[ _(entity.class_.view), url_for('index', view=entity.class_.view) ], entity, _('link') + ' ' + _('reference')])
def display_move_form(self: Any, form: Any, root_name: str) -> str: from openatlas.forms.field import TreeField html = '' for field in form: if isinstance(field, TreeField): html += '<p>' + root_name + ' ' + str(field) + '</p>' table = Table( header=['#', display.uc_first(_('selection'))], rows=[[item, item.label.text] for item in form.selection]) return html + """ <div class="toolbar"> {select_all} {deselect_all} </div> {table}""".format( select_all=display.button(_('select all'), id_="select-all"), deselect_all=display.button(_('deselect all'), id_="select-none"), table=table.display('move'))