def user_delete(id_): user = UserMapper.get_by_id(id_) if (user.group == 'admin' and current_user.group != 'admin') and user.id != current_user.id: abort(403) # pragma: no cover UserMapper.delete(id_) flash(_('user deleted'), 'info') return redirect(url_for('user_index'))
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 admin_newsletter(): form = NewsLetterForm() if form.validate_on_submit(): # pragma: no cover recipients = 0 for user_id in (request.form.getlist('recipient')): user = UserMapper.get_by_id(user_id) if user.settings['newsletter'] and user.active: code = UserMapper.generate_password() user.unsubscribe_code = code user.update() link_ = request.scheme + '://' + request.headers['Host'] link_ += url_for('index_unsubscribe', code=code) unsubscribe = '\n\n' + _( 'To unsubscribe use the link below.') + '\n\n' + link_ if send_mail(form.subject.data, form.body.data + unsubscribe, user.email): recipients += 1 flash(_('Newsletter send') + ': ' + str(recipients), 'info') return redirect(url_for('admin_index')) table = { 'id': 'user', 'header': ['username', 'email', 'receiver'], 'data': [] } for user in UserMapper.get_all(): if user.settings['newsletter'] and user.active: # pragma: no cover checkbox = '<input value="' + str(user.id) + '" name="recipient"' checkbox += ' type="checkbox" checked="checked">' table['data'].append([user.username, user.email, checkbox]) return render_template('admin/newsletter.html', form=form, table=table)
def get_log_for_advanced_view(entity_id: str) -> dict: sql = """ SELECT ul.created, ul.user_id, ul.entity_id, u.username FROM web.user_log ul JOIN web.user u ON ul.user_id = u.id WHERE ul.entity_id = %(entity_id)s AND ul.action = %(action)s ORDER BY ul.created DESC LIMIT 1;""" g.execute(sql, {'entity_id': entity_id, 'action': 'insert'}) row_insert = g.cursor.fetchone() g.execute(sql, {'entity_id': entity_id, 'action': 'update'}) row_update = g.cursor.fetchone() sql = 'SELECT project_id, origin_id, user_id FROM import.entity WHERE entity_id = %(id)s;' g.execute(sql, {'id': entity_id}) row_import = g.cursor.fetchone() project = ImportMapper.get_project_by_id( row_import.project_id) if row_import else None log = { 'creator': UserMapper.get_by_id(row_insert.user_id) if row_insert else None, 'created': row_insert.created if row_insert else None, 'modifier': UserMapper.get_by_id(row_update.user_id) if row_update else None, 'modified': row_update.created if row_update else None, 'import_project': project, 'import_user': UserMapper.get_by_id(row_import.user_id) if row_import else None, 'import_origin_id': row_import.origin_id if row_import else None } return log
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 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 get_log_for_advanced_view(entity_id): sql = """ SELECT ul.created, ul.user_id, ul.entity_id, u.username FROM web.user_log ul JOIN web.user u ON ul.user_id = u.id WHERE ul.entity_id = %(entity_id)s AND ul.action = %(action)s ORDER BY ul.created DESC LIMIT 1;""" g.cursor.execute(sql, {'entity_id': entity_id, 'action': 'insert'}) debug_model['div sql'] += 1 row_insert = g.cursor.fetchone() g.cursor.execute(sql, {'entity_id': entity_id, 'action': 'update'}) debug_model['div sql'] += 1 row_update = g.cursor.fetchone() sql = 'SELECT project_id, origin_id, user_id FROM import.entity WHERE entity_id = %(id)s;' g.cursor.execute(sql, {'id': entity_id}) debug_model['div sql'] += 1 row_import = g.cursor.fetchone() project = ImportMapper.get_project_by_id(row_import.project_id) if row_import else None log = { 'creator': UserMapper.get_by_id(row_insert.user_id) if row_insert else None, 'created': row_insert.created if row_insert else None, 'modifier': UserMapper.get_by_id(row_update.user_id) if row_update else None, 'modified': row_update.created if row_update else None, 'import_project': project, 'import_user': UserMapper.get_by_id(row_import.user_id) if row_import else None, 'import_origin_id': row_import.origin_id if row_import else None} return log
def save(form, entity, insert: Optional[bool] = True) -> None: g.cursor.execute('BEGIN') try: if insert: UserMapper.insert_note(entity, form.description.data) else: UserMapper.update_note(entity, form.description.data) g.cursor.execute('COMMIT') flash(_('note added') if insert else _('note updated'), 'info') except Exception as e: # pragma: no cover g.cursor.execute('ROLLBACK') logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error')
def admin_log() -> str: form = LogForm() form.user.choices = [(0, _('all'))] + UserMapper.get_users() table = Table(['date', 'priority', 'type', 'message', 'user', 'info'], order='[[0, "desc"]]') logs = logger.get_system_logs(form.limit.data, form.priority.data, form.user.data) for row in logs: user = UserMapper.get_by_id(row.user_id) if row.user_id else None table.rows.append([format_datetime(row.created), str(row.priority) + ' ' + app.config['LOG_LEVELS'][row.priority], row.type, row.message, link(user) if user and user.id else row.user_id, row.info.replace('\n', '<br />')]) return render_template('admin/log.html', table=table, form=form)
def index() -> str: tables = {'overview': Table(paging=False, defs='[{className: "dt-body-right", targets: 1}]'), 'bookmarks': Table(['name', 'class', 'first', 'last'], defs='[{className: "dt-body-right", targets: [2,3]}]'), 'notes': Table(['name', 'class', 'first', 'last', _('note')], defs='[{className: "dt-body-right", targets: [2,3]}]'), 'latest': Table(['name', 'class', 'first', 'last', 'date', 'user'], order='[[4, "desc"]]', defs='[{className: "dt-body-right", targets: [2,3]}]')} if current_user.is_authenticated and hasattr(current_user, 'bookmarks'): for entity_id in current_user.bookmarks: entity = EntityMapper.get_by_id(entity_id) tables['bookmarks'].rows.append([link(entity), g.classes[entity.class_.code].name, entity.first, entity.last, bookmark_toggle(entity.id, True)]) for entity_id, text in UserMapper.get_notes().items(): entity = EntityMapper.get_by_id(entity_id) tables['notes'].rows.append([link(entity), g.classes[entity.class_.code].name, entity.first, entity.last, truncate_string(text)]) for name, count in EntityMapper.get_overview_counts().items(): if count: count = format_number(count) if count else '' url = url_for(name + '_index') if name != 'find' else url_for('place_index') tables['overview'].rows.append([ '<a href="' + url + '">' + uc_first(_(name)) + '</a>', count]) for entity in EntityMapper.get_latest(8): tables['latest'].rows.append([ link(entity), g.classes[entity.class_.code].name, entity.first, entity.last, format_date(entity.created), link(logger.get_log_for_advanced_view(entity.id)['creator'])]) intro = ContentMapper.get_translation('intro') return render_template('index/index.html', intro=intro, tables=tables)
def user_index(): tables = {'user': { 'id': 'user', 'header': ['username', 'group', 'email', 'newsletter', 'created', 'last login', 'entities'], 'data': []}} for user in UserMapper.get_all(): count = UserMapper.get_created_entities_count(user.id) tables['user']['data'].append([ link(user), user.group, user.email if is_authorized('manager') or user.settings['show_email'] else '', _('yes') if user.settings['newsletter'] else '', format_date(user.created), format_date(user.login_last_success), format_number(count) if count else '']) return render_template('user/index.html', tables=tables)
def user_update(id_): user = UserMapper.get_by_id(id_) if user.group == 'admin' and current_user.group != 'admin': abort(403) # pragma: no cover form = UserForm() form.user_id = id_ del form.password, form.password2, form.send_info, form.insert_and_continue, form.show_passwords form.group.choices = get_groups() if form.validate_on_submit(): user.active = True if user.id == current_user.id else form.active.data # no self deactivate user.real_name = form.real_name.data user.username = form.username.data user.email = form.email.data user.description = form.description.data user.group = form.group.data user.update() flash(_('info update'), 'info') return redirect(url_for('user_view', id_=id_)) form.username.data = user.username form.group.data = user.group form.real_name.data = user.real_name form.active.data = user.active form.email.data = user.email form.description.data = user.description if user.id == current_user.id: del form.active return render_template('user/update.html', form=form, user=user)
def user_insert(): form = UserForm() form.group.choices = get_groups() if not session['settings']['mail']: del form.send_info if form.validate_on_submit(): user_id = UserMapper.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') return redirect(url_for('user_index')) if 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)
def object_view(id_: int) -> str: object_ = EntityMapper.get_by_id(id_, nodes=True) object_.note = UserMapper.get_note(object_) tables = { 'info': get_entity_data(object_), 'source': Table(Table.HEADERS['source']), 'event': Table(Table.HEADERS['event']) } for link_ in object_.get_links('P128'): data = get_base_table_data(link_.range) if is_authorized('contributor'): url = url_for('link_delete', id_=link_.id, origin_id=object_.id) data.append( display_remove_link(url + '#tab-' + link_.range.table_name, link_.range.name)) tables['source'].rows.append(data) for link_ in object_.get_links('P25', inverse=True): data = get_base_table_data(link_.domain) if is_authorized('contributor'): url = url_for('link_delete', id_=link_.id, origin_id=object_.id) data.append( display_remove_link(url + '#tab-' + link_.range.table_name, link_.range.name)) tables['event'].rows.append(data) return render_template('object/view.html', object_=object_, tables=tables)
def note_update(entity_id: int) -> str: entity = EntityMapper.get_by_id(entity_id) form = build_form(NoteForm, 'note-form') if form.validate_on_submit(): save(form, entity=entity, insert=False) return redirect(url_for(entity.view_name + '_view', id_=entity.id)) form.description.data = UserMapper.get_note(entity) return render_template('note/update.html', form=form, entity=entity)
def validate(self, extra_validators=None): valid = Form.validate(self) user = UserMapper.get_by_id(self.user_id) if self.user_id else User() if user.username != self.username.data and UserMapper.get_by_username(self.username.data): self.username.errors.append(str(_('error username exists'))) valid = False if user.email != self.email.data and UserMapper.get_by_email(self.email.data): self.email.errors.append(str(_('error email exists'))) valid = False if getattr(self, 'password'): if self.password.data != self.password2.data: self.password.errors.append(_('error passwords must match')) self.password2.errors.append(_('error passwords must match')) valid = False if len(self.password.data) < session['settings']['minimum_password_length']: self.password.errors.append(_('error password too short')) valid = False return valid
def index_unsubscribe(code: str) -> str: user = UserMapper.get_by_unsubscribe_code(code) text = _('unsubscribe link not valid') if user: # pragma: no cover user.settings['newsletter'] = '' user.update() user.unsubscribe_code = '' user.update_settings() text = _('You have successfully unsubscribed. You can subscribe again in your Profile.') return render_template('index/unsubscribe.html', text=text)
def index_unsubscribe(code): user = UserMapper.get_by_unsubscribe_code(code) text = _('unsubscribe link not valid') if user: # pragma: no cover user.settings['newsletter'] = '' user.update() user.unsubscribe_code = '' user.update_settings() text = _('You have successfully unsubscribed. You can subscribe again in your Profile.') return render_template('index/unsubscribe.html', text=text)
def user_activity(user_id=0): form = ActivityForm() form.user.choices = [(0, _('all'))] + UserMapper.get_users() table = {'id': 'activity', 'header': ['date', 'user', 'action', 'entity'], 'data': []} if form.validate_on_submit(): activities = UserMapper.get_activities(form.limit.data, form.user.data, form.action.data) elif user_id: form.user.data = user_id activities = UserMapper.get_activities(100, user_id, 'all') else: activities = UserMapper.get_activities(100, 0, 'all') for row in activities: entity = EntityMapper.get_by_id(row.entity_id, True) user = UserMapper.get_by_id(row.user_id) table['data'].append([ format_date(row.created), link(user) if user else 'id ' + str(row.user_id), _(row.action), link(entity) if entity else 'id ' + str(row.entity_id)]) return render_template('user/activity.html', table=table, form=form)
def user_view(id_): user = UserMapper.get_by_id(id_) data = {'info': [ (_('username'), link(user)), (_('group'), user.group), (_('full name'), user.real_name), (_('email'), user.email if is_authorized('manager') or user.settings['show_email'] else ''), (_('language'), user.settings['language']), (_('last login'), format_date(user.login_last_success)), (_('failed logins'), user.login_failed_count if is_authorized('manager') else '')]} return render_template('user/view.html', user=user, data=data)
def get_log_for_advanced_view(entity_id): sql = """ SELECT ul.created, ul.user_id, ul.entity_id, u.username FROM web.user_log ul JOIN web.user u ON ul.user_id = u.id WHERE ul.entity_id = %(entity_id)s AND ul.action = %(action)s ORDER BY ul.created DESC LIMIT 1;""" g.cursor.execute(sql, {'entity_id': entity_id, 'action': 'insert'}) row_insert = g.cursor.fetchone() g.cursor.execute(sql, {'entity_id': entity_id, 'action': 'update'}) row_update = g.cursor.fetchone() log = { 'creator': UserMapper.get_by_id(row_insert.user_id) if row_insert else None, 'created': row_insert.created if row_insert else None, 'modifier': UserMapper.get_by_id(row_update.user_id) if row_update else None, 'modified': row_update.created if row_update else None } return log
def user_activity(user_id: Optional[int] = 0) -> str: form = ActivityForm() form.user.choices = [(0, _('all'))] + UserMapper.get_users() if form.validate_on_submit(): activities = UserMapper.get_activities(form.limit.data, form.user.data, form.action.data) elif user_id: form.user.data = user_id activities = UserMapper.get_activities(100, user_id, 'all') else: activities = UserMapper.get_activities(100, 0, 'all') table = Table(['date', 'user', 'action', 'entity']) for row in activities: entity = EntityMapper.get_by_id(row.entity_id, ignore_not_found=True) user = UserMapper.get_by_id(row.user_id) table.rows.append([ format_date(row.created), link(user) if user else 'id ' + str(row.user_id), _(row.action), link(entity) if entity else 'id ' + str(row.entity_id) ]) return render_template('user/activity.html', table=table, form=form)
def reset_password() -> str: 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 reference_view(id_: int) -> str: reference = EntityMapper.get_by_id(id_, nodes=True) reference.note = UserMapper.get_note(reference) tables = { 'info': get_entity_data(reference), 'file': Table(Table.HEADERS['file'] + ['page', _('main image')]) } for name in [ 'source', 'event', 'actor', 'place', 'feature', 'stratigraphic-unit', 'find' ]: header_label = 'link text' if reference.system_type == 'external reference' else 'page' tables[name] = Table(Table.HEADERS[name] + [header_label]) for link_ in reference.get_links('P67', True): domain = link_.domain data = get_base_table_data(domain) if is_authorized('contributor'): url = url_for('link_delete', id_=link_.id, origin_id=reference.id) + '#tab-file' data.append(display_remove_link(url, domain.name)) tables['file'].rows.append(data) profile_image_id = reference.get_profile_image_id() for link_ in reference.get_links(['P67', 'P128']): range_ = link_.range data = get_base_table_data(range_) data.append(truncate_string(link_.description)) if range_.view_name == 'file': # pragma: no cover ext = data[3].replace('.', '') data.append( get_profile_image_table_link(range_, reference, ext, profile_image_id)) if not profile_image_id and ext in app.config[ 'DISPLAY_FILE_EXTENSIONS']: profile_image_id = range_.id if is_authorized('contributor'): url = url_for('reference_link_update', link_id=link_.id, origin_id=reference.id) data.append('<a href="' + url + '">' + uc_first(_('edit')) + '</a>') url = url_for('link_delete', id_=link_.id, origin_id=reference.id) data.append( display_remove_link(url + '#tab-' + range_.table_name, range_.name)) tables[range_.table_name].rows.append(data) return render_template('reference/view.html', reference=reference, tables=tables, profile_image_id=profile_image_id)
def login() -> str: 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 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 load_user(user_id): return UserMapper.get_by_id(user_id, True)
def test_user(self): data = { 'active': '', 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'you_never_guess_this', 'group': 'admin', 'name': 'Ripley Weaver', 'description': '', 'send_info': '' } data2 = { 'active': '', 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'you_never_guess_this', 'group': 'admin', 'name': 'Newt', 'continue_': 'yes', 'send_info': '' } with app.app_context(): rv = self.app.get(url_for('user_insert'), follow_redirects=True) assert b'Password' in rv.data self.app.post('/login', data={ 'username': '******', 'password': '******' }) rv = self.app.get(url_for('user_insert'), follow_redirects=True) assert b'403 - Forbidden' in rv.data self.app.get(url_for('logout'), follow_redirects=True) self.login() with app.test_request_context(): app.preprocess_request() logged_in_user = UserMapper.get_by_username('Alice') rv = self.app.get(url_for('user_insert')) assert b'+ User' in rv.data rv = self.app.post(url_for('user_insert'), data=data) user_id = rv.location.split('/')[-1] data['password'] = '******' rv = self.app.post(url_for('user_insert'), data=data) assert b'match' in rv.data # Test insert with continue rv = self.app.post(url_for('user_insert'), follow_redirects=True, data=data2) assert b'Newt' not in rv.data rv = self.app.get(url_for('user_view', id_=user_id)) assert b'Ripley' in rv.data rv = self.app.get(url_for('user_update', id_=logged_in_user.id)) assert b'Alice' in rv.data data['description'] = 'The warrant officer' rv = self.app.post(url_for('user_update', id_=user_id), data=data, follow_redirects=True) assert b'The warrant officer' in rv.data rv = self.app.get(url_for('user_delete', id_=user_id), follow_redirects=True) assert b'User deleted' in rv.data # Test activity log data = { 'name': 'test', 'description': 'test' } # insert a reference to show something self.app.post(url_for('reference_insert', code='bibliography'), data=data) rv = self.app.get(url_for('user_activity')) assert b'Activity' in rv.data rv = self.app.get(url_for('user_activity', user_id=user_id)) assert b'Activity' in rv.data data = {'limit': 'all', 'action': 'all', 'user': '******'} rv = self.app.post(url_for('user_activity', data=data)) assert b'Activity' in rv.data
def load_user(user_id: int): return UserMapper.get_by_id(user_id, True)
def test_user(self): data = { 'active': '', 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'you_never_guess_this', 'group': 'admin', 'name': 'Ripley Weaver', 'description': '', 'send_info': ''} data2 = { 'active': '', 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'you_never_guess_this', 'group': 'admin', 'name': 'Newt', 'continue_': 'yes', 'send_info': ''} with app.app_context(): rv = self.app.get(url_for('user_insert'), follow_redirects=True) assert b'Password' in rv.data self.app.post('/login', data={'username': '******', 'password': '******'}) rv = self.app.get(url_for('user_insert'), follow_redirects=True) assert b'403 - Forbidden' in rv.data self.app.get(url_for('logout'), follow_redirects=True) self.login() with app.test_request_context(): app.preprocess_request() logged_in_user_id = UserMapper.get_by_username('Alice').id rv = self.app.get(url_for('user_insert')) assert b'+ User' in rv.data rv = self.app.post(url_for('user_insert'), data=data) user_id = rv.location.split('/')[-1] data['password'] = '******' rv = self.app.post(url_for('user_insert'), data=data) assert b'match' in rv.data # Test with insert with continue rv = self.app.post(url_for('user_insert'), follow_redirects=True, data=data2) assert b'Newt' not in rv.data rv = self.app.get(url_for('user_view', id_=user_id)) assert b'Ripley' in rv.data rv = self.app.get(url_for('user_update', id_=logged_in_user_id)) assert b'Alice' in rv.data data['description'] = 'The warrant officer' rv = self.app.post( url_for('user_update', id_=user_id), data=data, follow_redirects=True) assert b'The warrant officer' in rv.data rv = self.app.get(url_for('user_delete', id_=user_id), follow_redirects=True) assert b'A user was deleted' in rv.data # Test activity log data = {'name': 'test', 'description': 'test'} # insert a reference to show something self.app.post(url_for('reference_insert', code='bibliography'), data=data) rv = self.app.get(url_for('user_activity')) assert b'Activity' in rv.data rv = self.app.get(url_for('user_activity', user_id=user_id)) assert b'Activity' in rv.data data = {'limit': 'all', 'action': 'all', 'user': '******'} rv = self.app.post(url_for('user_activity', data=data)) assert b'Activity' in rv.data
def event_view(id_: int) -> str: event = EntityMapper.get_by_id(id_, nodes=True) event.note = UserMapper.get_note(event) tables = { 'info': get_entity_data(event), 'file': Table(Table.HEADERS['file'] + [_('main image')]), 'subs': Table(Table.HEADERS['event']), 'source': Table(Table.HEADERS['source']), 'actor': Table( ['actor', 'class', 'involvement', 'first', 'last', 'description'], defs='[{className: "dt-body-right", targets: [3,4]}]'), 'reference': Table(Table.HEADERS['reference'] + ['page / link text']) } for link_ in event.get_links(['P11', 'P14', 'P22', 'P23']): first = link_.first if not link_.first and event.first: first = '<span class="inactive" style="float:right;">' + event.first + '</span>' last = link_.last if not link_.last and event.last: last = '<span class="inactive" style="float:right;">' + event.last + '</span>' data = ([ link(link_.range), g.classes[link_.range.class_.code].name, link_.type.name if link_.type else '', first, last, truncate_string(link_.description) ]) if is_authorized('contributor'): update_url = url_for('involvement_update', id_=link_.id, origin_id=event.id) unlink_url = url_for( 'link_delete', id_=link_.id, origin_id=event.id) + '#tab-actor' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, link_.range.name)) tables['actor'].rows.append(data) profile_image_id = event.get_profile_image_id() for link_ in event.get_links('P67', True): domain = link_.domain data = get_base_table_data(domain) if domain.view_name == 'file': extension = data[3].replace('.', '') data.append( get_profile_image_table_link(domain, event, extension, profile_image_id)) if not profile_image_id and extension in app.config[ 'DISPLAY_FILE_EXTENSIONS']: profile_image_id = domain.id if domain.view_name not in ['source', 'file']: if domain.system_type == 'external reference': event.external_references.append(link_) data.append(truncate_string(link_.description)) if is_authorized('contributor'): url = url_for('reference_link_update', link_id=link_.id, origin_id=event.id) data.append('<a href="' + url + '">' + uc_first(_('edit')) + '</a>') if is_authorized('contributor'): url = url_for('link_delete', id_=link_.id, origin_id=event.id) data.append( display_remove_link(url + '#tab-' + domain.view_name, domain.name)) tables[domain.view_name].rows.append(data) for sub_event in event.get_linked_entities('P117', inverse=True, nodes=True): tables['subs'].rows.append(get_base_table_data(sub_event)) objects = [] for location in event.get_linked_entities(['P7', 'P26', 'P27']): objects.append(location.get_linked_entity('P53', True)) return render_template( 'event/view.html', event=event, tables=tables, profile_image_id=profile_image_id, gis_data=GisMapper.get_all(objects) if objects else None)
def note_delete(entity_id: int) -> str: entity = EntityMapper.get_by_id(entity_id) UserMapper.delete_note(entity) flash(_('note deleted'), 'info') return redirect(url_for(entity.view_name + '_view', id_=entity.id))
def source_view(id_: int) -> str: source = EntityMapper.get_by_id(id_, nodes=True) source.note = UserMapper.get_note(source) tables = { 'info': get_entity_data(source), 'text': Table(['text', 'type', 'content']), 'file': Table(Table.HEADERS['file'] + [_('main image')]), 'reference': Table(Table.HEADERS['reference'] + ['page']) } for text in source.get_linked_entities('P73', nodes=True): tables['text'].rows.append([ link(text), next(iter(text.nodes)).name if text.nodes else '', truncate_string(text.description) ]) for name in [ 'actor', 'event', 'place', 'feature', 'stratigraphic-unit', 'find' ]: tables[name] = Table(Table.HEADERS[name]) tables['actor'].defs = '[{className: "dt-body-right", targets: [2,3]}]' tables['event'].defs = '[{className: "dt-body-right", targets: [3,4]}]' tables['place'].defs = '[{className: "dt-body-right", targets: [2,3]}]' for link_ in source.get_links('P67'): range_ = link_.range data = get_base_table_data(range_) if is_authorized('contributor'): url = url_for('link_delete', id_=link_.id, origin_id=source.id) data.append( display_remove_link(url + '#tab-' + range_.table_name, range_.name)) tables[range_.table_name].rows.append(data) profile_image_id = source.get_profile_image_id() for link_ in source.get_links(['P67'], True): domain = link_.domain data = get_base_table_data(domain) if domain.view_name == 'file': # pragma: no cover extension = data[3].replace('.', '') data.append( get_profile_image_table_link(domain, source, extension, profile_image_id)) if not profile_image_id and extension in app.config[ 'DISPLAY_FILE_EXTENSIONS']: profile_image_id = domain.id if domain.view_name not in ['file']: data.append(link_.description) if domain.system_type == 'external reference': source.external_references.append(link_) if is_authorized('contributor'): url = url_for('reference_link_update', link_id=link_.id, origin_id=source.id) data.append('<a href="' + url + '">' + uc_first(_('edit')) + '</a>') if is_authorized('contributor'): url = url_for('link_delete', id_=link_.id, origin_id=source.id) data.append( display_remove_link(url + '#tab-' + domain.view_name, domain.name)) tables[domain.view_name].rows.append(data) return render_template('source/view.html', source=source, tables=tables, profile_image_id=profile_image_id)
def actor_view(id_: int) -> str: actor = EntityMapper.get_by_id(id_, nodes=True, aliases=True) actor.note = UserMapper.get_note(actor) info = [] if actor.aliases: info.append( (uc_first(_('alias')), '<br />'.join(actor.aliases.values()))) tables = { 'info': info, 'file': Table(Table.HEADERS['file'] + [_('main image')]), 'source': Table(Table.HEADERS['source']), 'reference': Table(Table.HEADERS['reference'] + ['page / link text']), 'event': Table( ['event', 'class', 'involvement', 'first', 'last', 'description'], defs='[{className: "dt-body-right", targets: [3,4]}]'), 'relation': Table(['relation', 'actor', 'first', 'last', 'description'], defs='[{className: "dt-body-right", targets: [2,3]}]'), 'member_of': Table(['member of', 'function', 'first', 'last', 'description'], defs='[{className: "dt-body-right", targets: [2,3]}]') } profile_image_id = actor.get_profile_image_id() for link_ in actor.get_links('P67', True): domain = link_.domain data = get_base_table_data(domain) if domain.view_name == 'file': extension = data[3].replace('.', '') data.append( get_profile_image_table_link(domain, actor, extension, profile_image_id)) if not profile_image_id and extension in app.config[ 'DISPLAY_FILE_EXTENSIONS']: profile_image_id = domain.id if domain.view_name not in ['source', 'file']: data.append(truncate_string(link_.description)) if domain.system_type == 'external reference': actor.external_references.append(link_) if is_authorized('contributor'): url = url_for('reference_link_update', link_id=link_.id, origin_id=actor.id) data.append('<a href="' + url + '">' + uc_first(_('edit')) + '</a>') if is_authorized('contributor'): url = url_for('link_delete', id_=link_.id, origin_id=actor.id) data.append( display_remove_link(url + '#tab-' + domain.view_name, domain.name)) tables[domain.view_name].rows.append(data) # Todo: Performance - getting every place of every object for every event is very costly event_links = actor.get_links(['P11', 'P14', 'P22', 'P23', 'P25'], True) objects = [] for link_ in event_links: event = link_.domain place = event.get_linked_entity('P7') link_.object_ = None if place: object_ = place.get_linked_entity('P53', True) objects.append(object_) link_.object_ = object_ # May be used later for first/last appearance info first = link_.first if not link_.first and event.first: first = '<span class="inactive" style="float:right;">' + event.first + '</span>' last = link_.last if not link_.last and event.last: last = '<span class="inactive" style="float:right;">' + event.last + '</span>' data = ([ link(event), g.classes[event.class_.code].name, link_.type.name if link_.type else '', first, last, truncate_string(link_.description) ]) if is_authorized('contributor'): update_url = url_for('involvement_update', id_=link_.id, origin_id=actor.id) unlink_url = url_for( 'link_delete', id_=link_.id, origin_id=actor.id) + '#tab-event' if link_.domain.class_.code != 'E9': data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') else: data.append('') data.append(display_remove_link(unlink_url, link_.domain.name)) tables['event'].rows.append(data) # Add info of dates and places begin_place = actor.get_linked_entity('OA8') begin_object = None if begin_place: begin_object = begin_place.get_linked_entity('P53', True) objects.append(begin_object) end_place = actor.get_linked_entity('OA9') end_object = None if end_place: end_object = end_place.get_linked_entity('P53', True) objects.append(end_object) label = uc_first(_('born') if actor.class_.code == 'E21' else _('begin')) info.append((label, format_entry_begin(actor, begin_object))) label = uc_first(_('died') if actor.class_.code == 'E21' else _('end')) info.append((label, format_entry_end(actor, end_object))) appears_first, appears_last = get_appearance(event_links) info.append((_('appears first'), appears_first)) info.append((_('appears last'), appears_last)) residence_place = actor.get_linked_entity('P74') if residence_place: residence_object = residence_place.get_linked_entity('P53', True) objects.append(residence_object) info.append((uc_first(_('residence')), link(residence_object))) add_type_data(actor, info) add_system_data(actor, info) for link_ in actor.get_links('OA7') + actor.get_links('OA7', True): if actor.id == link_.domain.id: type_ = link_.type.get_name_directed() if link_.type else '' related = link_.range else: type_ = link_.type.get_name_directed(True) if link_.type else '' related = link_.domain data = ([ type_, link(related), link_.first, link_.last, truncate_string(link_.description) ]) if is_authorized('contributor'): update_url = url_for('relation_update', id_=link_.id, origin_id=actor.id) unlink_url = url_for('link_delete', id_=link_.id, origin_id=actor.id) + '#tab-relation' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, related.name)) tables['relation'].rows.append(data) for link_ in actor.get_links('P107', True): data = ([ link(link_.domain), link_.type.name if link_.type else '', link_.first, link_.last, truncate_string(link_.description) ]) if is_authorized('contributor'): update_url = url_for('member_update', id_=link_.id, origin_id=actor.id) unlink_url = url_for('link_delete', id_=link_.id, origin_id=actor.id) + '#tab-member-of' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, link_.domain.name)) tables['member_of'].rows.append(data) if actor.class_.code in app.config['CLASS_CODES']['group']: tables['member'] = Table( ['member', 'function', 'first', 'last', 'description'], defs='[{className: "dt-body-right", targets: [2,3]}]') for link_ in actor.get_links('P107'): data = ([ link(link_.range), link_.type.name if link_.type else '', link_.first, link_.last, truncate_string(link_.description) ]) if is_authorized('contributor'): update_url = url_for('member_update', id_=link_.id, origin_id=actor.id) unlink_url = url_for('link_delete', id_=link_.id, origin_id=actor.id) + '#tab-member' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, link_.range.name)) tables['member'].rows.append(data) gis_data = GisMapper.get_all(objects) if objects else None if gis_data and gis_data['gisPointSelected'] == '[]': gis_data = None return render_template('actor/view.html', actor=actor, tables=tables, gis_data=gis_data, profile_image_id=profile_image_id)
def ajax_bookmark() -> str: label = UserMapper.toggle_bookmark(request.form['entity_id']) return jsonify(uc_first(label))
def place_view(id_: int) -> str: object_ = EntityMapper.get_by_id(id_, nodes=True, aliases=True) object_.note = UserMapper.get_note(object_) location = object_.get_linked_entity('P53', nodes=True) tables = { 'info': get_entity_data(object_, location), 'file': Table(Table.HEADERS['file'] + [_('main image')]), 'source': Table(Table.HEADERS['source']), 'event': Table(Table.HEADERS['event'], defs='[{className: "dt-body-right", targets: [3,4]}]'), 'reference': Table(Table.HEADERS['reference'] + ['page / link text']), 'actor': Table([_('actor'), _('property'), _('class'), _('first'), _('last')]) } if object_.system_type == 'place': tables['feature'] = Table(Table.HEADERS['place'] + [_('description')]) if object_.system_type == 'feature': tables['stratigraphic-unit'] = Table(Table.HEADERS['place'] + [_('description')]) if object_.system_type == 'stratigraphic unit': tables['find'] = Table(Table.HEADERS['place'] + [_('description')]) profile_image_id = object_.get_profile_image_id() overlays = None if current_user.settings['module_map_overlay']: overlays = OverlayMapper.get_by_object(object_) if is_authorized('editor'): tables['file'].header.append(uc_first(_('overlay'))) for link_ in object_.get_links('P67', inverse=True): domain = link_.domain data = get_base_table_data(domain) if domain.view_name == 'file': extension = data[3].replace('.', '') data.append( get_profile_image_table_link(domain, object_, extension, profile_image_id)) if not profile_image_id and extension in app.config[ 'DISPLAY_FILE_EXTENSIONS']: profile_image_id = domain.id if is_authorized( 'editor') and current_user.settings['module_map_overlay']: if extension in app.config['DISPLAY_FILE_EXTENSIONS']: if domain.id in overlays: url = url_for('overlay_update', id_=overlays[domain.id].id) data.append('<a href="' + url + '">' + uc_first(_('edit')) + '</a>') else: url = url_for('overlay_insert', image_id=domain.id, place_id=object_.id, link_id=link_.id) data.append('<a href="' + url + '">' + uc_first(_('add')) + '</a>') else: # pragma: no cover data.append('') if domain.view_name not in ['source', 'file']: data.append(truncate_string(link_.description)) if domain.system_type.startswith('external reference'): object_.external_references.append(link_) if is_authorized( 'contributor' ) and domain.system_type != 'external reference geonames': url = url_for('reference_link_update', link_id=link_.id, origin_id=object_.id) data.append('<a href="' + url + '">' + uc_first(_('edit')) + '</a>') else: data.append('') if is_authorized('contributor'): url = url_for('link_delete', id_=link_.id, origin_id=object_.id) data.append( display_remove_link(url + '#tab-' + domain.view_name, domain.name)) tables[domain.view_name].rows.append(data) event_ids = [] # Keep track of already inserted events to prevent doubles for event in location.get_linked_entities(['P7', 'P26', 'P27'], inverse=True): tables['event'].rows.append(get_base_table_data(event)) event_ids.append(event.id) for event in object_.get_linked_entities(['P24'], inverse=True): if event.id not in event_ids: # Don't add again if already in table tables['event'].rows.append(get_base_table_data(event)) has_subunits = False for entity in object_.get_linked_entities('P46', nodes=True): has_subunits = True data = get_base_table_data(entity) data.append(truncate_string(entity.description)) tables[entity.system_type.replace(' ', '-')].rows.append(data) for link_ in location.get_links(['P74', 'OA8', 'OA9'], inverse=True): actor = EntityMapper.get_by_id(link_.domain.id) tables['actor'].rows.append([ link(actor), g.properties[link_.property.code].name, actor.class_.name, actor.first, actor.last ]) gis_data = GisMapper.get_all(object_) if location else None if gis_data['gisPointSelected'] == '[]' and gis_data['gisPolygonSelected'] == '[]' \ and gis_data['gisLineSelected'] == '[]': gis_data = None place = None feature = None stratigraphic_unit = None if object_.system_type == 'find': stratigraphic_unit = object_.get_linked_entity('P46', True) feature = stratigraphic_unit.get_linked_entity('P46', True) place = feature.get_linked_entity('P46', True) elif object_.system_type == 'stratigraphic unit': feature = object_.get_linked_entity('P46', True) place = feature.get_linked_entity('P46', True) elif object_.system_type == 'feature': place = object_.get_linked_entity('P46', True) return render_template('place/view.html', object_=object_, tables=tables, gis_data=gis_data, place=place, feature=feature, stratigraphic_unit=stratigraphic_unit, has_subunits=has_subunits, profile_image_id=profile_image_id, overlays=overlays)
def ajax_bookmark(): label = UserMapper.toggle_bookmark(request.form['entity_id'], current_user) return jsonify(uc_first(label))