def reset_password(): if current_user.is_authenticated: # Prevent password reset if already logged in return redirect(url_for('index')) form = PasswordResetForm() if form.validate_on_submit() and session['settings']['mail']: # pragma: no cover user = UserMapper.get_by_email(form.email.data) if not user: logger.log('info', 'password', 'Password reset for non existing ' + form.email.data) flash(_('error non existing email'), 'error') else: code = UserMapper.generate_password() user.password_reset_code = code user.password_reset_date = datetime.datetime.now() user.update() link = request.scheme + '://' + request.headers['Host'] link += url_for('reset_confirm', code=code) subject = _('Password reset request for %(site_name)s', site_name=session['settings']['site_name']) body = _('We received a password reset request for %(username)s', username=user.username) body += ' ' + _('at') + ' ' body += request.headers['Host'] + '\n\n' + _('reset password link') + ':\n\n' body += link + '\n\n' + _('The link is valid for') + ' ' body += str(session['settings']['reset_confirm_hours']) + ' ' + _('hours') + '.' if send_mail(subject, body, form.email.data): flash(_('A password reset confirmation mail was send to %(email)s.', email=form.email.data), 'info') else: flash(_('Failed to send password reset confirmation mail to %(email)s.', email=form.email.data), 'error') return redirect(url_for('login')) return render_template('login/reset_password.html', form=form)
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 export_csv() -> str: path = app.config['EXPORT_FOLDER_PATH'] + '/csv' writeable = True if os.access(path, os.W_OK) else False form = ExportCsvForm() if form.validate_on_submit() and writeable: Export.export_csv(form) logger.log('info', 'database', 'CSV export') flash(_('data was exported as CSV'), 'info') return redirect(url_for('export_csv')) table = Table(['name', 'size'], order='[[0, "desc"]]') for file in [ f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f)) ]: name = basename(file) if name == '.gitignore': continue link = '<a href="{url}">{label}</a>'.format(url=url_for('download_csv', filename=name), label=uc_first( _('download'))) data = [name, convert_size(os.path.getsize(path + '/' + name)), link] if is_authorized('admin') and writeable: confirm = ' onclick="return confirm(\'' + _('Delete %(name)s?', name=name) + '\')"' delete = '<a href="' + url_for('delete_csv', filename=name) delete += '" ' + confirm + '>' + uc_first(_('delete')) + '</a>' data.append(delete) table.rows.append(data) return render_template('export/export_csv.html', form=form, table=table, writeable=writeable)
def reset_confirm(code): # pragma: no cover user = UserMapper.get_by_reset_code(code) if not user: 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 = UserMapper.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 delete_entity(id_: int) -> Optional[str]: url = None entity = Entity.get_by_id(id_) if not is_authorized(entity.class_.write_access): abort(403) # pragma: no cover if isinstance(entity, ReferenceSystem): if entity.system: abort(403) if entity.forms: flash(_('Deletion not possible if forms are attached'), 'error') return url_for('entity_view', id_=id_) if entity.class_.view in ['artifact', 'place']: if entity.get_linked_entities('P46'): flash(_('Deletion not possible if subunits exists'), 'error') return url_for('entity_view', id_=id_) parent = None \ if entity.class_.name == 'place' \ else entity.get_linked_entity('P46', True) entity.delete() logger.log_user(id_, 'delete') flash(_('entity deleted'), 'info') if parent: tab = f"#tab-{entity.class_.name.replace('_', '-')}" url = url_for('entity_view', id_=parent.id) + tab else: Entity.delete_(id_) logger.log_user(id_, 'delete') flash(_('entity deleted'), 'info') if entity.class_.name == 'file': try: delete_files(id_) except Exception as e: # pragma: no cover logger.log('error', 'file', 'file deletion failed', e) flash(_('error file delete'), 'error') return url
def member_insert(origin_id: int) -> str: origin = EntityMapper.get_by_id(origin_id) form = build_form(MemberForm, 'Member') del form.group form.origin_id.data = origin.id if form.validate_on_submit(): g.cursor.execute('BEGIN') try: for actor in EntityMapper.get_by_ids( ast.literal_eval(form.actor.data)): link_ = LinkMapper.get_by_id( origin.link('P107', actor, form.description.data)) link_.set_dates(form) link_.type = get_link_type(form) link_.update() g.cursor.execute('COMMIT') flash(_('entity created'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') if form.continue_.data == 'yes': return redirect(url_for('member_insert', origin_id=origin_id)) return redirect(url_for('actor_view', id_=origin.id) + '#tab-member') return render_template('member/insert.html', origin=origin, form=form)
def relation_update(id_, origin_id): link_ = LinkMapper.get_by_id(id_) domain = EntityMapper.get_by_id(link_.domain.id) range_ = EntityMapper.get_by_id(link_.range.id) origin = range_ if origin_id == range_.id else domain related = range_ if origin_id == domain.id else domain form = build_form(RelationForm, 'Actor Actor Relation', link_, request) del form.actor, form.insert_and_continue, form.origin_id if form.validate_on_submit(): g.cursor.execute('BEGIN') try: link_.delete() if form.inverse.data: link_id = related.link('OA7', origin, form.description.data) else: link_id = origin.link('OA7', related, form.description.data) DateMapper.save_link_dates(link_id, form) NodeMapper.save_link_nodes(link_id, form) g.cursor.execute('COMMIT') flash(_('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect(url_for('actor_view', id_=origin.id) + '#tab-relation') if origin.id == range_.id: form.inverse.data = True form.save.label.text = _('save') link_.set_dates() form.populate_dates(link_) return render_template('relation/update.html', origin=origin, form=form, related=related)
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 admin_file_delete(filename: str) -> Response: # pragma: no cover if filename != 'all': # Delete one file try: (app.config['UPLOAD_DIR'] / filename).unlink() flash(f"{filename} {_('was deleted')}", 'info') except Exception as e: logger.log('error', 'file', f'deletion of {filename} failed', e) flash(_('error file delete'), 'error') return redirect(f"{url_for('admin_orphans')}#tab-orphaned-files") if is_authorized('admin'): # Delete all files with no corresponding entity entity_file_ids = [entity.id for entity in Entity.get_by_class('file')] for file in app.config['UPLOAD_DIR'].iterdir(): if file.name != '.gitignore' and int( file.stem) not in entity_file_ids: try: (app.config['UPLOAD_DIR'] / file.name).unlink() except Exception as e: logger.log( 'error', 'file', f'deletion of {file.name} failed', e) flash(_('error file delete'), 'error') return redirect(f"{url_for('admin_orphans')}#tab-orphaned-files")
def member_update(id_, origin_id): link_ = LinkMapper.get_by_id(id_) domain = EntityMapper.get_by_id(link_.domain.id) range_ = EntityMapper.get_by_id(link_.range.id) origin = range_ if origin_id == range_.id else domain form = build_form(MemberForm, 'Member', link_, request) del form.actor, form.group, form.insert_and_continue if form.validate_on_submit(): g.cursor.execute('BEGIN') try: link_.delete() link_id = domain.link('P107', range_, form.description.data) DateMapper.save_link_dates(link_id, form) NodeMapper.save_link_nodes(link_id, form) g.cursor.execute('COMMIT') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') tab = '#tab-member-of' if origin.id == range_.id else '#tab-member' return redirect(url_for('actor_view', id_=origin.id) + tab) form.save.label.text = _('save') link_.set_dates() form.populate_dates(link_) related = range_ if origin_id == domain.id else domain return render_template('member/update.html', origin=origin, form=form, related=related)
def save(form, source=None, origin=None): g.cursor.execute('BEGIN') try: log_action = 'update' if not source: source = EntityMapper.insert('E33', form.name.data, 'source content') log_action = 'insert' source.name = form.name.data source.description = form.description.data source.update() source.save_nodes(form) url = url_for('source_view', id_=source.id) if origin: url = url_for(get_view_name(origin) + '_view', id_=origin.id) + '#tab-source' if get_view_name(origin) == 'reference': link_ = origin.link('P67', source) url = url_for('reference_link_update', link_id=link_, origin_id=origin) elif get_view_name(origin) == 'file': origin.link('P67', source) else: source.link('P67', origin) g.cursor.execute('COMMIT') if form.continue_.data == 'yes': url = url_for('source_insert', origin_id=origin.id if origin else None) logger.log_user(source.id, log_action) flash(_('entity created') if log_action == 'insert' else _('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('source_insert', origin_id=origin.id if origin else None) return url
def save(form, reference=None, code: Optional[str] = None, origin=None) -> str: g.cursor.execute('BEGIN') log_action = 'update' try: if not reference: log_action = 'insert' system_type = code.replace('_', ' ') reference = EntityMapper.insert('E31', form.name.data, system_type) reference.name = form.name.data reference.description = form.description.data reference.update() reference.save_nodes(form) url = url_for('reference_view', id_=reference.id) if origin: link_id = reference.link('P67', origin) url = url_for('reference_link_update', link_id=link_id, origin_id=origin.id) if form.continue_.data == 'yes' and code: url = url_for('reference_insert', code=code) g.cursor.execute('COMMIT') logger.log_user(reference.id, log_action) flash( _('entity created') if log_action == 'insert' else _('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('reference_index') return url
def save(form, reference=None, code=None, origin=None): g.cursor.execute('BEGIN') log_action = 'update' try: if not reference: log_action = 'insert' class_code = 'E84' if code == 'carrier' else 'E31' system_type = 'information carrier' if code == 'carrier' else code reference = EntityMapper.insert(class_code, form.name.data, system_type) reference.name = form.name.data reference.description = form.description.data reference.update() reference.save_nodes(form) url = url_for('reference_view', id_=reference.id) if origin: link_id = reference.link('P67', origin) url = url_for('reference_link_update', link_id=link_id, origin_id=origin.id) if form.continue_.data == 'yes' and code: url = url_for('reference_insert', code=code) g.cursor.execute('COMMIT') logger.log_user(reference.id, log_action) flash(_('entity created') if log_action == 'insert' else _('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('reference_index') return url
def insert_files(form: FlaskForm, origin: Optional[Entity] = None) -> Union[str, Response]: filenames = [] url = url_for('index', view=g.classes['file'].view) try: Transaction.begin() entity_name = form.name.data.strip() for count, file in enumerate(form.file.data): entity = Entity.insert('file', file.filename) url = get_redirect_url(form, entity, origin) # Add 'a' to prevent emtpy temporary filename, has no side effects filename = secure_filename(f'a{file.filename}') new_name = f"{entity.id}.{filename.rsplit('.', 1)[1].lower()}" file.save(str(app.config['UPLOAD_DIR'] / new_name)) filenames.append(new_name) if g.settings['image_processing']: resize_image(new_name) if len(form.file.data) > 1: form.name.data = f'{entity_name}_{str(count + 1).zfill(2)}' if origin: url = f"{url_for('view', id_=origin.id)}#tab-file" entity.update(process_form_data(form, entity, origin)) logger.log_user(entity.id, 'insert') Transaction.commit() flash(_('entity created'), 'info') except Exception as e: # pragma: no cover Transaction.rollback() for filename in filenames: (app.config['UPLOAD_DIR'] / filename).unlink() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('index', view=g.classes['file'].view) return url
def save(form, object_=None) -> str: g.cursor.execute('BEGIN') log_action = 'update' try: if not object_: log_action = 'insert' object_ = EntityMapper.insert('E84', form.name.data, 'information carrier') object_.name = form.name.data object_.description = form.description.data object_.update() object_.save_nodes(form) url = url_for('object_view', id_=object_.id) url = url_for('object_insert') if form.continue_.data == 'yes' else url g.cursor.execute('COMMIT') logger.log_user(object_.id, log_action) flash( _('entity created') if log_action == 'insert' else _('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('object_index') return url
def settings_update(): form = SettingsForm() if form.validate_on_submit(): g.cursor.execute('BEGIN') try: SettingsMapper.update(form) logger.log('info', 'settings', 'Settings updated') g.cursor.execute('COMMIT') flash(_('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect(url_for('settings_index')) for field in SettingsMapper.fields: if field.startswith('file_'): continue if field in ['mail_recipients_feedback']: getattr(form, field).data = ';'.join(session['settings'][field]) elif field in ['default_table_rows', 'log_level']: getattr(form, field).data = int(session['settings'][field]) else: getattr(form, field).data = session['settings'][field] return render_template('settings/update.html', form=form, settings=session['settings'])
def save(form, source=None, origin=None): g.cursor.execute('BEGIN') log_action = 'update' try: if not source: source = EntityMapper.insert('E33', form.name.data, 'source content') log_action = 'insert' source.name = form.name.data source.description = form.description.data source.update() source.save_nodes(form) url = url_for('source_view', id_=source.id) if origin: url = url_for(origin.view_name + '_view', id_=origin.id) + '#tab-source' if origin.view_name == 'reference': link_ = origin.link('P67', source) url = url_for('reference_link_update', link_id=link_, origin_id=origin) elif origin.view_name == 'file': origin.link('P67', source) else: source.link('P67', origin) g.cursor.execute('COMMIT') if form.continue_.data == 'yes': url = url_for('source_insert', origin_id=origin.id if origin else None) logger.log_user(source.id, log_action) flash(_('entity created') if log_action == 'insert' else _('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('source_insert', origin_id=origin.id if origin else None) return url
def __init__(self, row): if not row: logger.log('error', 'model', 'invalid id') abort(418) self.id = row.id self.nodes = dict() if hasattr(row, 'nodes') and row.nodes: for node in row.nodes: self.nodes[g.nodes[node['f1']]] = node['f2'] # f1 = node id, f2 = value self.name = row.name self.root = None self.description = row.description if row.description else '' self.system_type = row.system_type self.created = row.created self.modified = row.modified self.first = int(row.first) if hasattr(row, 'first') and row.first else None self.last = int(row.last) if hasattr(row, 'last') and row.last else None self.class_ = g.classes[row.class_code] self.dates = {} self.view_name = None # view_name is used to build urls if self.system_type == 'file': self.view_name = 'file' elif self.class_.code in app.config['CODE_CLASS']: self.view_name = app.config['CODE_CLASS'][self.class_.code] self.table_name = self.view_name # table_name is used to build tables if self.view_name == 'place': self.table_name = self.system_type.replace(' ', '-')
def insert(code: str, name: str, system_type: Optional[str] = None, description: Optional[str] = None) -> Entity: from openatlas.util.util import sanitize from openatlas import logger if not name: # pragma: no cover logger.log('error', 'database', 'Insert entity without name') abort(422) sql = """ INSERT INTO model.entity (name, system_type, class_code, description) VALUES (%(name)s, %(system_type)s, %(code)s, %(description)s) RETURNING id;""" params = { 'name': str(name).strip(), 'code': code, 'system_type': system_type.strip() if system_type else None, 'description': sanitize(description, 'description') if description else None } g.execute(sql, params) return EntityMapper.get_by_id(g.cursor.fetchone()[0])
def relation_update(link_: Link, domain: Entity, range_: Entity, origin: Entity) -> Union[str, Response]: origin = range_ if origin.id == range_.id else domain related = range_ if origin.id == domain.id else domain form = build_form('actor_actor_relation', link_) if form.validate_on_submit(): Transaction.begin() try: link_.delete() if form.inverse.data: link_ = Link.get_by_id( related.link('OA7', origin, form.description.data)[0]) else: link_ = Link.get_by_id( origin.link('OA7', related, form.description.data)[0]) link_.set_dates(process_form_dates(form)) link_.type = get_link_type(form) link_.update() 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') return redirect(f"{url_for('view', id_=origin.id)}#tab-relation") if origin.id == range_.id: form.inverse.data = True return render_template( 'display_form.html', form=form, title=_('relation'), crumbs=[[_('actor'), url_for('index', view='actor')], origin, related, _('edit')])
def involvement_update(id_, origin_id): link_ = LinkMapper.get_by_id(id_) event = EntityMapper.get_by_id(link_.domain.id) actor = EntityMapper.get_by_id(link_.range.id) origin = event if origin_id == event.id else actor form = build_form(ActorForm, 'Involvement', link_, request) form.save.label.text = _('save') del form.actor, form.event, form.insert_and_continue form.activity.choices = [('P11', g.properties['P11'].name)] if event.class_.code in ['E7', 'E8', 'E12']: form.activity.choices.append(('P14', g.properties['P14'].name)) if event.class_.code == 'E8': form.activity.choices.append(('P22', g.properties['P22'].name)) form.activity.choices.append(('P23', g.properties['P23'].name)) if form.validate_on_submit(): g.cursor.execute('BEGIN') try: link_.delete() link_id = event.link(form.activity.data, actor, form.description.data) DateMapper.save_link_dates(link_id, form) NodeMapper.save_link_nodes(link_id, form) g.cursor.execute('COMMIT') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') tab = 'actor' if origin.view_name == 'event' else 'event' return redirect(url_for(origin.view_name + '_view', id_=origin.id) + '#tab-' + tab) form.activity.data = link_.property.code form.description.data = link_.description link_.set_dates() form.populate_dates(link_) return render_template('involvement/update.html', origin=origin, form=form, linked_object=event if origin_id != event.id else actor)
def member_update(id_: int, origin_id: int) -> Union[str, Response]: link_ = Link.get_by_id(id_) domain = Entity.get_by_id(link_.domain.id) range_ = Entity.get_by_id(link_.range.id) origin = range_ if origin_id == range_.id else domain form = build_form('actor_function', link_) if form.validate_on_submit(): Transaction.begin() try: link_.delete() link_ = Link.get_by_id( domain.link('P107', range_, form.description.data)[0]) link_.set_dates(process_form_dates(form)) link_.type = get_link_type(form) link_.update() Transaction.commit() except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect( f"{url_for('view', id_=origin.id)}" f"#tab-member{'-of' if origin.id == range_.id else ''}") form.save.label.text = _('save') related = range_ if origin_id == domain.id else domain return render_template( 'display_form.html', form=form, crumbs=[[_('actor'), url_for('index', view='actor')], origin, related, _('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 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 = g.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=g.settings['site_name']) body = _('New password for %(username)s', username=user.username) + ' ' body += f"{_('at')} {request.scheme}://{request.headers['Host']}:\n\n" body += f"{uc_first(_('username'))}: {user.username}\n" body += f"{uc_first(_('password'))}: {password}\n" if send_mail(subject, body, user.email, False): flash(_('A new password was sent 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 reset_confirm(code: str) -> str: # pragma: no cover user = UserMapper.get_by_reset_code(code) if not user: 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 = UserMapper.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 member_update(id_, origin_id): link_ = LinkMapper.get_by_id(id_) domain = EntityMapper.get_by_id(link_.domain.id) range_ = EntityMapper.get_by_id(link_.range.id) origin = range_ if origin_id == range_.id else domain related = range_ if origin_id == domain.id else domain form = build_form(MemberForm, 'Member', link_, request) del form.actor, form.group, form.insert_and_continue if form.validate_on_submit(): g.cursor.execute('BEGIN') try: link_.delete() link_id = domain.link('P107', range_, form.description.data) DateMapper.save_link_dates(link_id, form) NodeMapper.save_link_nodes(link_id, form) g.cursor.execute('COMMIT') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') tab = '#tab-member-of' if origin.id == range_.id else '#tab-member' return redirect(url_for('actor_view', id_=origin.id) + tab) form.save.label.text = _('save') link_.set_dates() form.populate_dates(link_) return render_template('member/update.html', origin=origin, form=form, related=related)
def export_sql(): path = app.config['EXPORT_FOLDER_PATH'] + '/sql' writeable = True if os.access(path, os.W_OK) else False form = ExportSqlForm() if form.validate_on_submit() and writeable: if Export.export_sql(): logger.log('info', 'database', 'SQL export') flash(_('data was exported as SQL'), 'info') else: # pragma: no cover logger.log('error', 'database', 'SQL export failed') flash(_('SQL export failed'), 'error') return redirect(url_for('export_sql')) table = {'id': 'sql', 'header': ['name', 'size'], 'data': [], 'sort': 'sortList: [[0, 1]],headers: {0: { sorter: "text" }}'} for file in [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]: name = basename(file) if name == '.gitignore': continue url = url_for('download_sql', filename=name) data = [name, convert_size(os.path.getsize(path + '/' + name)), '<a href="' + url + '">' + uc_first(_('download')) + '</a>'] if is_authorized('admin') and writeable: confirm = ' onclick="return confirm(\'' + _('Delete %(name)s?', name=name) + '\')"' delete = '<a href="' + url_for('delete_sql', filename=name) delete += '" ' + confirm + '>' + uc_first(_('delete')) + '</a>' data.append(delete) table['data'].append(data) return render_template('export/export_sql.html', form=form, table=table, writeable=writeable)
def admin_check_link_duplicates(delete: Optional[str] = None) -> str: if delete: delete_count = str(LinkMapper.delete_link_duplicates()) logger.log('info', 'admin', 'Deleted duplicate links: ' + delete_count) flash(_('deleted links') + ': ' + delete_count, 'info') return redirect(url_for('admin_check_link_duplicates')) table = Table(['domain', 'range', 'property_code', 'description', 'type_id', 'begin_from', 'begin_to', 'begin_comment', 'end_from', 'end_to', 'end_comment', 'count']) for result in LinkMapper.check_link_duplicates(): table.rows.append([link(EntityMapper.get_by_id(result.domain_id)), link(EntityMapper.get_by_id(result.range_id)), link(g.properties[result.property_code]), truncate_string(result.description), link(g.nodes[result.type_id]) if result.type_id else '', format_date(result.begin_from), format_date(result.begin_to), truncate_string(result.begin_comment), format_date(result.end_from), format_date(result.end_to), truncate_string(result.end_comment), result.count]) duplicates = False if table.rows: duplicates = True else: # If no exact duplicates where found check if single types are used multiple times table = Table(['entity', 'class', 'base type', 'incorrect multiple types'], rows=LinkMapper.check_single_type_duplicates()) return render_template('admin/check_link_duplicates.html', table=table, duplicates=duplicates)
def admin_file_delete(filename: str) -> str: # pragma: no cover if filename != 'all': try: os.remove(app.config['UPLOAD_FOLDER_PATH'] + '/' + filename) flash(filename + ' ' + _('was deleted'), 'info') except Exception as e: logger.log('error', 'file', 'deletion of ' + filename + ' failed', e) flash(_('error file delete'), 'error') return redirect(url_for('admin_orphans') + '#tab-orphaned-files') if is_authorized('admin'): # Get all files with entities file_ids = [str(entity.id) for entity in EntityMapper.get_by_system_type('file')] # Get orphaned files (no corresponding entity) path = app.config['UPLOAD_FOLDER_PATH'] for file in [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]: filename = basename(file) if filename != '.gitignore' and splitext(filename)[0] not in file_ids: try: os.remove(app.config['UPLOAD_FOLDER_PATH'] + '/' + filename) except Exception as e: logger.log('error', 'file', 'deletion of ' + filename + ' failed', e) flash(_('error file delete'), 'error') return redirect(url_for('admin_orphans') + '#tab-orphaned-files')
def insert(entity: Entity, property_code: str, range_: Union[Entity, list[Entity]], description: Optional[str] = None, inverse: bool = False, type_id: Optional[int] = None) -> list[int]: property_ = g.properties[property_code] entities = range_ if isinstance(range_, list) else [range_] new_link_ids = [] for linked_entity in entities: domain = linked_entity if inverse else entity range_ = entity if inverse else linked_entity domain_error = True range_error = True if property_.find_object('domain_class_code', domain.class_.cidoc_class.code): domain_error = False if property_.find_object('range_class_code', range_.class_.cidoc_class.code): range_error = False if domain_error or range_error: # pragma: no cover text = \ f"invalid CIDOC link {domain.class_.cidoc_class.code}" \ f" > {property_code} > {range_.class_.cidoc_class.code}" logger.log('error', 'model', text) abort(400, text) id_ = Db.insert({ 'property_code': property_code, 'domain_id': domain.id, 'range_id': range_.id, 'description': description, 'type_id': type_id }) new_link_ids.append(id_) return new_link_ids
def export_csv(): path = app.config['EXPORT_FOLDER_PATH'] + '/csv' writeable = True if os.access(path, os.W_OK) else False form = ExportCsvForm() if form.validate_on_submit() and writeable: Export.export_csv(form) logger.log('info', 'database', 'CSV export') flash(_('data was exported as CSV'), 'info') return redirect(url_for('export_csv')) table = {'id': 'csv', 'header': ['name', 'size'], 'data': [], 'sort': 'sortList: [[0, 1]],headers: {0: { sorter: "text" }}'} for file in [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]: name = basename(file) if name == '.gitignore': continue link = '<a href="{url}">{label}</a>'.format(url=url_for('download_csv', filename=name), label=uc_first(_('download'))) data = [name, convert_size(os.path.getsize(path + '/' + name)), link] if is_authorized('admin') and writeable: confirm = ' onclick="return confirm(\'' + _('Delete %(name)s?', name=name) + '\')"' delete = '<a href="' + url_for('delete_csv', filename=name) delete += '" ' + confirm + '>' + uc_first(_('delete')) + '</a>' data.append(delete) table['data'].append(data) return render_template('export/export_csv.html', form=form, table=table, writeable=writeable)
def sql_execute() -> str: file_data = get_backup_file_data() response = '' form = SqlForm() if form.validate_on_submit() and not file_data['backup_too_old']: Transaction.begin() try: g.cursor.execute(form.statement.data) response = f'<p>Rows affected: {g.cursor.rowcount}</p>' try: response += f'<p>{g.cursor.fetchall()}</p>' except Exception: # pragma: no cover pass # Assuming no SELECT statement so returning rowcount Transaction.commit() flash(_('SQL executed'), 'info') logger.log('info', 'database', 'SQL executed', form.statement.data) except Exception as e: Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) response = str(e) flash(_('error transaction'), 'error') return render_template( 'sql/execute.html', form=form, response=response, file_data=file_data, title=_('SQL'), crumbs=[[_('admin'), f"{url_for('admin_index')}#tab-data"], [_('SQL'), url_for('sql_index')], _('execute')])
def hierarchy_insert(category: str) -> Union[str, Response]: form = build_form('hierarchy', code=category) form.classes.choices = Type.get_class_choices() if form.validate_on_submit(): if Type.check_hierarchy_exists(form.name.data): flash(_('error name exists'), 'error') return render_template('display_form.html', form=form) try: Transaction.begin() type_ = Entity.insert('type', sanitize(form.name.data)) Type.insert_hierarchy( type_, # type: ignore category, form.classes.data, is_multiple(form, category)) type_.update(process_form_data(form, type_)) Transaction.commit() except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') abort(418) flash(_('entity created'), 'info') return redirect(f"{url_for('type_index')}#menu-tab-{category}") return render_template( 'display_form.html', form=form, manual_page='entity/type', title=_('types'), crumbs=[ [_('types'), url_for('type_index')], f'+ {uc_first(_(category))}'])
def was_modified(form: FlaskForm, entity: Entity) -> bool: # pragma: no cover if not entity.modified or not form.opened.data: return False if entity.modified < datetime.fromtimestamp(float(form.opened.data)): return False logger.log('info', 'multi user', 'Multi user overwrite prevented.') return True
def save(form: FlaskForm, entity: Optional[Entity] = None, class_: Optional[str] = None, origin: Optional[Entity] = None) -> Union[str, Response]: if class_ == 'file' and not entity: return insert_file(form, origin) Transaction.begin() action = 'update' try: if not entity: action = 'insert' entity = insert_entity(form, class_, origin) if isinstance(entity, ReferenceSystem): entity.name = entity.name \ if hasattr(entity, 'system') and entity.system \ else form.name.data entity.description = form.description.data entity.website_url = form.website_url.data \ if form.website_url.data else None entity.resolver_url = form.resolver_url.data \ if form.resolver_url.data else None entity.placeholder = form.placeholder.data \ if form.placeholder.data else None entity.update_system(form) if hasattr(form, 'forms'): entity.add_forms(form) else: entity.update(form) class_ = entity.class_.name update_links(entity, form, action, origin) url = link_and_get_redirect_url(form, entity, class_, origin) logger.log_user(entity.id, action) Transaction.commit() flash( _('entity created') if action == 'insert' else _('info update'), 'info') except InvalidGeomException as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed because of invalid geom', e) flash(_('Invalid geom entered'), 'error') if action == 'update' and entity: url = url_for('update', id_=entity.id, origin_id=origin.id if origin else None) else: url = url_for('index', view=g.classes[class_].view) except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') if action == 'update' and entity: url = url_for('update', id_=entity.id, origin_id=origin.id if origin else None) else: url = url_for('index', view=g.classes[class_].view) if class_ in ['administrative_unit', 'type']: url = url_for('node_index') return url
def relation_insert(origin_id): origin = EntityMapper.get_by_id(origin_id) form = build_form(RelationForm, 'Actor Actor Relation') form.origin_id.data = origin.id if form.validate_on_submit(): g.cursor.execute('BEGIN') try: for actor_id in ast.literal_eval(form.actor.data): if form.inverse.data: link_id = LinkMapper.insert(actor_id, 'OA7', origin.id, form.description.data) else: link_id = origin.link('OA7', actor_id, form.description.data) DateMapper.save_link_dates(link_id, form) NodeMapper.save_link_nodes(link_id, form) g.cursor.execute('COMMIT') flash(_('entity created'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') if form.continue_.data == 'yes': return redirect(url_for('relation_insert', origin_id=origin_id)) return redirect(url_for('actor_view', id_=origin.id) + '#tab-relation') return render_template('relation/insert.html', origin=origin, form=form)
def create_folder(folder: Path) -> bool: try: folder.mkdir() return True except OSError as e: # pragma: no cover logger.log('info', 'image processing', 'failed to create a folder', e) return False
def get_linked_entity(entity_param, code, inverse=False): result = LinkMapper.get_linked_entities(entity_param, code, inverse) if len(result) > 1: # pragma: no cover logger.log('error', 'model', 'multiple linked entities found for ' + code) flash(_('error multiple linked entities found'), 'error') return if result: return result[0]
def reference_system_remove_form(system_id: int, form_id: int) -> Response: try: g.reference_systems[system_id].remove_form(form_id) flash(_('info update'), 'info') except Exception as e: # pragma: no cover logger.log('error', 'database', 'remove form failed', e) flash(_('error database'), 'error') return redirect(url_for('entity_view', id_=system_id))
def profile_update() -> str: form = ProfileForm() user = current_user if form.validate_on_submit(): user.real_name = form.name.data user.email = form.email.data user.settings['show_email'] = form.show_email.data user.settings['newsletter'] = form.newsletter.data user.settings['language'] = form.language.data user.settings['table_rows'] = form.table_rows.data user.settings['module_geonames'] = form.module_geonames.data user.settings['module_map_overlay'] = form.module_map_overlay.data user.settings['module_notes'] = form.module_notes.data user.settings['max_zoom'] = form.max_zoom.data user.settings[ 'table_show_aliases'] = 'True' if form.table_show_aliases.data == 'on' else 'False' user.settings['layout'] = form.layout.data g.cursor.execute('BEGIN') try: user.update() user.update_settings() g.cursor.execute('COMMIT') session['language'] = form.language.data flash(_('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect(url_for('profile_index')) form.name.data = current_user.real_name form.name.label.text = uc_first(_('full name')) form.email.data = current_user.email form.email.label.text = uc_first(_('email')) form.show_email.data = current_user.settings['show_email'] form.show_email.label.text = uc_first(_('show email')) form.newsletter.data = current_user.settings['newsletter'] form.newsletter.label.text = uc_first(_('newsletter')) language = user.settings['language'] if user.settings[ 'language'] else session['language'] form.language.data = language form.language.label.text = uc_first(_('language')) form.table_rows.data = user.settings['table_rows'] form.table_rows.label.text = uc_first(_('table rows')) form.table_show_aliases.data = 'on' if user.settings[ 'table_show_aliases'] else 'off' form.table_show_aliases.label.text = uc_first(_('show aliases in tables')) form.layout.data = user.settings['layout'] form.layout.label.text = uc_first(_('layout')) form.max_zoom.data = user.settings['max_zoom'] form.max_zoom.label.text = uc_first(_('max map zoom')) form.module_geonames.data = user.settings['module_geonames'] form.module_geonames.label.text = 'GeoNames' form.module_map_overlay.data = user.settings['module_map_overlay'] form.module_map_overlay.label.text = uc_first(_('map overlay')) form.module_notes.data = user.settings['module_notes'] form.module_notes.label.text = uc_first(_('notes')) form.save.label.text = uc_first(_('save')) return render_template('profile/update.html', form=form)
def delete_sql(filename): try: os.remove(app.config['EXPORT_FOLDER_PATH'] + '/sql/' + filename) logger.log('info', 'file', 'SQL file deleted') flash(_('file deleted'), 'info') except Exception as e: # pragma: no cover logger.log('error', 'file', 'SQL file deletion failed', e) flash(_('error file delete'), 'error') return redirect(url_for('export_sql'))
def hierarchy_remove_form(id_, remove_id): root = g.nodes[id_] if NodeMapper.get_form_count(root, remove_id): abort(403) # pragma: no cover try: NodeMapper.remove_form_from_hierarchy(root, remove_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_))
def save(form, actor=None, code=None, origin=None): g.cursor.execute('BEGIN') try: log_action = 'update' if actor: actor.delete_links(['P74', 'OA8', 'OA9']) for alias in actor.get_linked_entities('P131'): alias.delete() else: actor = EntityMapper.insert(code, form.name.data) log_action = 'insert' actor.name = form.name.data actor.description = form.description.data actor.update() actor.save_dates(form) actor.save_nodes(form) url = url_for('actor_view', id_=actor.id) if form.residence.data: object_ = EntityMapper.get_by_id(form.residence.data) actor.link('P74', object_.get_linked_entity('P53')) if form.appears_first.data: object_ = EntityMapper.get_by_id(form.appears_first.data) actor.link('OA8', object_.get_linked_entity('P53')) if form.appears_last.data: object_ = EntityMapper.get_by_id(form.appears_last.data) actor.link('OA9', object_.get_linked_entity('P53')) for alias in form.alias.data: if alias.strip(): # Check if it isn't empty actor.link('P131', EntityMapper.insert('E82', alias)) if origin: if origin.view_name == 'reference': link_id = origin.link('P67', actor) url = url_for('reference_link_update', link_id=link_id, origin_id=origin.id) elif origin.view_name == 'source': origin.link('P67', actor) url = url_for('source_view', id_=origin.id) + '#tab-actor' elif origin.view_name == 'event': link_id = origin.link('P11', actor) url = url_for('involvement_update', id_=link_id, origin_id=origin.id) elif origin.view_name == 'actor': link_id = origin.link('OA7', actor) url = url_for('relation_update', id_=link_id, origin_id=origin.id) if form.continue_.data == 'yes' and code: url = url_for('actor_insert', code=code) logger.log_user(actor.id, log_action) g.cursor.execute('COMMIT') flash(_('entity created') if log_action == 'insert' else _('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect(url_for('actor_index')) return url
def insert(code, name, system_type=None, description=None): if not name: # pragma: no cover logger.log('error', 'database', 'Insert entity without name and date') return sql = """ INSERT INTO model.entity (name, system_type, class_code, description) VALUES (%(name)s, %(system_type)s, %(code)s, %(description)s) RETURNING id;""" params = {'name': name.strip(), 'code': code, 'system_type': system_type.strip() if system_type else None, 'description': description.strip() if description else None} g.cursor.execute(sql, params) debug_model['div sql'] += 1 return EntityMapper.get_by_id(g.cursor.fetchone()[0])
def source_add(origin_id): """ Link an entity to source coming from the entity.""" origin = EntityMapper.get_by_id(origin_id) if request.method == 'POST': g.cursor.execute('BEGIN') try: for entity in EntityMapper.get_by_ids(request.form.getlist('values')): entity.link('P67', origin) g.cursor.execute('COMMIT') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect(url_for(origin.view_name + '_view', id_=origin.id) + '#tab-source') form = build_table_form('source', origin.get_linked_entities('P67', True)) return render_template('source/add.html', origin=origin, form=form)
def save(form, event=None, code=None, origin=None): g.cursor.execute('BEGIN') try: log_action = 'insert' if event: log_action = 'update' event.delete_links(['P117', 'P7', 'P24']) else: event = EntityMapper.insert(code, form.name.data) event.name = form.name.data event.description = form.description.data event.update() event.save_dates(form) event.save_nodes(form) if form.event.data: entity = EntityMapper.get_by_id(form.event.data) event.link('P117', entity) if form.place.data: place = LinkMapper.get_linked_entity(int(form.place.data), 'P53') event.link('P7', place) if event.class_.code == 'E8' and form.given_place.data: # Link place for acquisition places = [EntityMapper.get_by_id(i) for i in ast.literal_eval(form.given_place.data)] event.link('P24', places) url = url_for('event_view', id_=event.id) if origin: url = url_for(origin.view_name + '_view', id_=origin.id) + '#tab-event' if origin.view_name == 'reference': link_id = origin.link('P67', event) url = url_for('reference_link_update', link_id=link_id, origin_id=origin.id) elif origin.view_name == 'source': origin.link('P67', event) elif origin.view_name == 'actor': link_id = event.link('P11', origin) url = url_for('involvement_update', id_=link_id, origin_id=origin.id) elif origin.view_name == 'file': origin.link('P67', event) if form.continue_.data == 'yes': url = url_for('event_insert', code=code, origin_id=origin.id if origin else None) g.cursor.execute('COMMIT') logger.log_user(event.id, log_action) flash(_('entity created') if log_action == 'insert' else _('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('event_index') return url
def __init__(self, row) -> None: if not row: logger.log('error', 'model', 'invalid id') abort(418) self.id = row.id self.nodes = {} # type: Dict if hasattr(row, 'nodes') and row.nodes: for node in row.nodes: self.nodes[g.nodes[node['f1']]] = node['f2'] # f1 = node id, f2 = value self.aliases = {} # type: Dict if hasattr(row, 'aliases') and row.aliases: for alias in row.aliases: self.aliases[alias['f1']] = alias['f2'] # f1 = alias id, f2 = alias name self.aliases = OrderedDict(sorted(self.aliases.items(), key=lambda kv: (kv[1], kv[0]))) self.name = row.name self.root = None # type: Optional[list] self.description = row.description if row.description else '' self.system_type = row.system_type self.created = row.created self.modified = row.modified self.begin_from = None self.begin_to = None self.begin_comment = None self.end_from = None self.end_to = None self.end_comment = None self.origin_id = None # type: Optional[int] if hasattr(row, 'begin_from'): self.begin_from = DateMapper.timestamp_to_datetime64(row.begin_from) self.begin_to = DateMapper.timestamp_to_datetime64(row.begin_to) self.begin_comment = row.begin_comment self.end_from = DateMapper.timestamp_to_datetime64(row.end_from) self.end_to = DateMapper.timestamp_to_datetime64(row.end_to) self.end_comment = row.end_comment self.first = DateForm.format_date(self.begin_from, 'year') if self.begin_from else None self.last = DateForm.format_date(self.end_from, 'year') if self.end_from else None self.last = DateForm.format_date(self.end_to, 'year') if self.end_to else self.last self.class_ = g.classes[row.class_code] self.view_name = None # view_name is used to build urls self.external_references = [] # type: list if self.system_type == 'file': self.view_name = 'file' elif self.class_.code in app.config['CODE_CLASS']: self.view_name = app.config['CODE_CLASS'][self.class_.code] self.table_name = self.view_name # table_name is used to build tables if self.view_name == 'place': self.table_name = self.system_type.replace(' ', '-')
def insert(code, name, system_type=None, description=None, date=None): if not name and not date: # pragma: no cover logger.log('error', 'database', 'Insert entity without name and date') return # Something went wrong so don't insert sql = """ INSERT INTO model.entity (name, system_type, class_code, description, value_timestamp) VALUES (%(name)s, %(system_type)s, %(code)s, %(description)s, %(value_timestamp)s) RETURNING id;""" params = { 'name': name.strip(), 'code': code, 'system_type': system_type.strip() if system_type else None, 'description': description.strip() if description else None, 'value_timestamp': DateMapper.datetime64_to_timestamp(date) if date else None} g.cursor.execute(sql, params) debug_model['div sql'] += 1 return EntityMapper.get_by_id(g.cursor.fetchone()[0])
def save(form, node=None, root=None): g.cursor.execute('BEGIN') try: if node: log_action = 'update' root = g.nodes[node.root[-1]] if node.root else None super_ = g.nodes[node.root[0]] if node.root else None else: log_action = 'insert' node = NodeMapper.insert(root.class_.code, form.name.data) super_ = 'new' new_super_id = getattr(form, str(root.id)).data new_super = g.nodes[int(new_super_id)] if new_super_id else g.nodes[root.id] if new_super.id == node.id: flash(_('error node self as super'), 'error') return if new_super.root and node.id in new_super.root: flash(_('error node sub as super'), 'error') return node.name = form.name.data if root.directional and form.name_inverse.data.strip(): node.name += ' (' + form.name_inverse.data.strip() + ')' if not root.directional: node.name = node.name.replace('(', '').replace(')', '') node.description = form.description.data node.update() # Update super if changed and node is not a root node if super_ and (super_ == 'new' or super_.id != new_super_id): property_code = 'P127' if node.class_.code == 'E55' else 'P89' node.delete_links(property_code) node.link(property_code, new_super) g.cursor.execute('COMMIT') url = url_for('node_view', id_=node.id) if form.continue_.data == 'yes': url = url_for('node_insert', root_id=root.id, super_id=new_super_id if new_super_id else None) logger.log_user(node.id, log_action) flash(_('entity created') if log_action == 'insert' else _('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') url = url_for('node_index') return url
def save(form, node=None, value_type=False): g.cursor.execute('BEGIN') try: if not node: node = NodeMapper.insert('E55', sanitize(form.name.data, 'node')) NodeMapper.insert_hierarchy(node, form, value_type) else: node = g.nodes[node.id] NodeMapper.update_hierarchy(node, form) node.name = sanitize(form.name.data, 'node') node.description = form.description.data node.update() g.cursor.execute('COMMIT') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return node
def insert(entity, property_code: str, linked_entities, description: Optional[str] = None, inverse: Optional[bool] = False): from openatlas.models.entity import Entity, EntityMapper # linked_entities can be an entity, an entity id or a list of them if not entity or not linked_entities: # pragma: no cover return property_ = g.properties[property_code] try: linked_entities = ast.literal_eval(linked_entities) except (SyntaxError, ValueError): pass linked_entities = linked_entities if type(linked_entities) is list else [linked_entities] if type(linked_entities[0]) is not Entity: linked_entities = EntityMapper.get_by_ids(linked_entities) result = None for linked_entity in linked_entities: domain = linked_entity if inverse else entity range_ = entity if inverse else linked_entity domain_error = True range_error = True if property_.find_object('domain_class_code', g.classes[domain.class_.code].code): domain_error = False if property_.find_object('range_class_code', g.classes[range_.class_.code].code): range_error = False if domain_error or range_error: text = _('error link') + ': ' + g.classes[domain.class_.code].code + ' > ' text += property_code + ' > ' + g.classes[range_.class_.code].code logger.log('error', 'model', text) flash(text, 'error') continue sql = """ INSERT INTO model.link (property_code, domain_id, range_id, description) VALUES (%(property_code)s, %(domain_id)s, %(range_id)s, %(description)s) RETURNING id;""" # Todo: build only one sql and get execution out of loop g.cursor.execute(sql, {'property_code': property_code, 'domain_id': domain.id, 'range_id': range_.id, 'description': description}) debug_model['link sql'] += 1 result = g.cursor.fetchone()[0] return result
def update_content(name, form): g.cursor.execute('BEGIN') try: for language in app.config['LANGUAGES'].keys(): sql = 'DELETE FROM web.i18n WHERE name = %(name)s AND language = %(language)s' g.cursor.execute(sql, {'name': name, 'language': language}) debug_model['div sql'] += 1 sql = """ INSERT INTO web.i18n (name, language, text) VALUES (%(name)s, %(language)s, %(text)s);""" g.cursor.execute(sql, { 'name': name, 'language': language, 'text': form.__getattribute__(language).data.strip()}) debug_model['div sql'] += 1 g.cursor.execute('COMMIT') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error')
def __init__(self, row): if not row: logger.log('error', 'model', 'invalid id') abort(418) self.id = row.id self.nodes = dict() if hasattr(row, 'nodes') and row.nodes: for node in row.nodes: self.nodes[g.nodes[node['f1']]] = node['f2'] # f1 = node id, f2 = value self.name = row.name self.root = None self.description = row.description if row.description else '' self.system_type = row.system_type self.created = row.created self.modified = row.modified self.begin_from = None self.begin_to = None self.begin_comment = None self.end_from = None self.end_to = None self.end_comment = None if hasattr(row, 'begin_from'): self.begin_from = DateMapper.timestamp_to_datetime64(row.begin_from) self.begin_to = DateMapper.timestamp_to_datetime64(row.begin_to) self.begin_comment = row.begin_comment self.end_from = DateMapper.timestamp_to_datetime64(row.end_from) self.end_to = DateMapper.timestamp_to_datetime64(row.end_to) self.end_comment = row.end_comment self.first = DateForm.format_date(self.begin_from, 'year') if self.begin_from else None self.last = DateForm.format_date(self.end_from, 'year') if self.end_from else None self.last = DateForm.format_date(self.end_to, 'year') if self.end_to else self.last self.class_ = g.classes[row.class_code] self.view_name = None # view_name is used to build urls self.external_references = [] # Used in view info tab for display if self.system_type == 'file': self.view_name = 'file' elif self.class_.code in app.config['CODE_CLASS']: self.view_name = app.config['CODE_CLASS'][self.class_.code] self.table_name = self.view_name # table_name is used to build tables if self.view_name == 'place': self.table_name = self.system_type.replace(' ', '-')
def member_insert(origin_id): origin = EntityMapper.get_by_id(origin_id) form = build_form(MemberForm, 'Member') del form.group form.origin_id.data = origin.id if form.validate_on_submit(): g.cursor.execute('BEGIN') try: for actor in EntityMapper.get_by_ids(ast.literal_eval(form.actor.data)): link_id = origin.link('P107', actor, form.description.data) DateMapper.save_link_dates(link_id, form) NodeMapper.save_link_nodes(link_id, form) g.cursor.execute('COMMIT') flash(_('entity created'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') if form.continue_.data == 'yes': return redirect(url_for('member_insert', origin_id=origin_id)) return redirect(url_for('actor_view', id_=origin.id) + '#tab-member') return render_template('member/insert.html', origin=origin, form=form)
def profile_update(): form = ProfileForm() if form.validate_on_submit(): current_user.real_name = form.name.data current_user.email = form.email.data current_user.settings['show_email'] = form.show_email.data current_user.settings['newsletter'] = form.newsletter.data g.cursor.execute('BEGIN') try: current_user.update() current_user.update_settings() g.cursor.execute('COMMIT') flash(_('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect(url_for('profile_index')) form.name.data = current_user.real_name form.email.data = current_user.email form.show_email.data = current_user.settings['show_email'] form.newsletter.data = current_user.settings['newsletter'] return render_template('profile/update.html', form=form)
def login(): if current_user.is_authenticated: return redirect('/') form = LoginForm() if form.validate_on_submit(): user = UserMapper.get_by_username(request.form['username']) if user: if user.login_attempts_exceeded(): logger.log('notice', 'auth', 'Login attempts exceeded: ' + user.username) flash(_('error login attempts exceeded'), 'error') return render_template('login/index.html', form=form) hash_ = hashpw(request.form['password'].encode('utf-8'), user.password.encode('utf-8')) if hash_ == user.password.encode('utf-8'): if user.active: login_user(user) session['login_previous_success'] = user.login_last_success session['login_previous_failures'] = user.login_failed_count if user.settings['language']: session['language'] = user.settings['language'] user.login_last_success = datetime.datetime.now() user.login_failed_count = 0 user.update() logger.log('info', 'auth', 'Login of ' + user.username) return redirect(request.args.get('next') or url_for('index')) else: logger.log('notice', 'auth', 'Inactive login try ' + user.username) flash(_('error inactive'), 'error') else: logger.log('notice', 'auth', 'Wrong password: '******'error wrong password'), 'error') else: logger.log('notice', 'auth', 'Wrong username: '******'username']) flash(_('error username'), 'error') return render_template('login/index.html', form=form)
def profile_index(): user = current_user data = {'info': [ (_('username'), user.username), (_('full name'), user.real_name), (_('email'), user.email), (_('show email'), uc_first(_('on')) if user.settings['show_email'] else uc_first(_('off'))), (_('newsletter'), uc_first(_('on')) if user.settings['newsletter'] else uc_first(_('off'))) ]} form = DisplayForm() if form.validate_on_submit(): user.settings['language'] = form.language.data user.settings['theme'] = form.theme.data user.settings['table_rows'] = form.table_rows.data user.settings['layout'] = form.layout.data g.cursor.execute('BEGIN') try: user.update_settings() g.cursor.execute('COMMIT') session['language'] = form.language.data flash(_('info update'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect(url_for('profile_index')) form.language.data = user.settings['language'] form.theme.data = user.settings['theme'] form.table_rows.data = user.settings['table_rows'] form.layout.data = user.settings['layout'] data['display'] = [ (form.language.label, form.language), (str(form.table_rows.label) + display_tooltip(form.table_rows.description), form.table_rows), (str(form.layout.label) + display_tooltip(form.layout.description), form.layout)] return render_template('profile/index.html', data=data, form=form)
def involvement_insert(origin_id): origin = EntityMapper.get_by_id(origin_id) form = build_form(ActorForm, 'Involvement') if origin.view_name == 'event': del form.event else: del form.actor form.activity.choices = [('P11', g.properties['P11'].name_inverse)] if origin.class_.code in ['E7', 'E8', 'E12']: form.activity.choices.append(('P14', g.properties['P14'].name_inverse)) if origin.class_.code == 'E8': form.activity.choices.append(('P22', g.properties['P22'].name_inverse)) form.activity.choices.append(('P23', g.properties['P23'].name_inverse)) if form.validate_on_submit(): g.cursor.execute('BEGIN') try: if origin.view_name == 'event': for actor in EntityMapper.get_by_ids(ast.literal_eval(form.actor.data)): link_id = origin.link(form.activity.data, actor, form.description.data) DateMapper.save_link_dates(link_id, form) NodeMapper.save_link_nodes(link_id, form) else: for event in EntityMapper.get_by_ids(ast.literal_eval(form.event.data)): link_id = event.link(form.activity.data, origin, form.description.data) DateMapper.save_link_dates(link_id, form) NodeMapper.save_link_nodes(link_id, form) g.cursor.execute('COMMIT') flash(_('entity created'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') if form.continue_.data == 'yes': return redirect(url_for('involvement_insert', origin_id=origin_id)) tab = 'actor' if origin.view_name == 'event' else 'event' return redirect(url_for(origin.view_name + '_view', id_=origin.id) + '#tab-' + tab) return render_template('involvement/insert.html', origin=origin, form=form)
def import_data(project_id, class_code): project = ImportMapper.get_project_by_id(project_id) form = ImportForm() table = None imported = False messages = {'error': [], 'warn': []} if form.validate_on_submit(): file_ = request.files['file'] file_path = app.config['IMPORT_FOLDER_PATH'] + '/' + secure_filename(file_.filename) columns = {'allowed': ['name', 'id', 'description'], 'valid': [], 'invalid': []} try: file_.save(file_path) if file_path.rsplit('.', 1)[1].lower() in ['xls', 'xlsx']: df = pd.read_excel(file_path, keep_default_na=False) else: df = pd.read_csv(file_path, keep_default_na=False) headers = list(df.columns.values) if 'name' not in headers: # pragma: no cover messages['error'].append(_('missing name column')) raise Exception() for item in headers: # pragma: no cover if item not in columns['allowed']: columns['invalid'].append(item) del df[item] if columns['invalid']: # pragma: no cover messages['warn'].append(_('invalid columns') + ': ' + ','.join(columns['invalid'])) headers = list(df.columns.values) # Read cleaned headers again table_data = [] checked_data = [] origin_ids = [] names = [] missing_name_count = 0 for index, row in df.iterrows(): if not row['name']: # pragma: no cover missing_name_count += 1 continue table_row = [] checked_row = {} for item in headers: table_row.append(row[item]) checked_row[item] = row[item] if item == 'name' and form.duplicate.data: names.append(row['name'].lower()) if item == 'id' and row[item]: origin_ids.append(str(row['id'])) table_data.append(table_row) checked_data.append(checked_row) table = {'id': 'import', 'header': headers, 'data': table_data} # Checking for data inconsistency if missing_name_count: # pragma: no cover messages['warn'].append(_('empty names') + ': ' + str(missing_name_count)) doubles = [item for item, count in collections.Counter(origin_ids).items() if count > 1] if doubles: # pragma: no cover messages['error'].append(_('double IDs in import') + ': ' + ', '.join(doubles)) existing = ImportMapper.check_origin_ids(project, origin_ids) if origin_ids else None if existing: messages['error'].append(_('IDs already in database') + ': ' + ', '.join(existing)) if form.duplicate.data: # Check for possible duplicates duplicates = ImportMapper.check_duplicates(class_code, names) if duplicates: # pragma: no cover messages['warn'].append(_('possible duplicates') + ': ' + ', '.join(duplicates)) if messages['error']: raise Exception() except Exception as e: # pragma: no cover flash(_('error at import'), 'error') return render_template('import/import_data.html', project=project, form=form, class_code=class_code, messages=messages) if not form.preview.data and checked_data: g.cursor.execute('BEGIN') try: ImportMapper.import_data(project, class_code, checked_data) g.cursor.execute('COMMIT') logger.log('info', 'import', 'import: ' + str(len(checked_data))) flash(_('import of') + ': ' + str(len(checked_data)), 'info') imported = True except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'import', 'import failed', e) flash(_('error transaction'), 'error') return render_template('import/import_data.html', project=project, form=form, class_code=class_code, table=table, imported=imported, messages=messages)