def document_send(doc_id): doc = get_document(doc_id) recipient = request.form.get("recipient") user_msg = request.form.get("message") site_name = "[{}] ".format(current_app.config["SITE_NAME"]) sender_name = current_user.name subject = site_name + _("{sender} sent you a file").format( sender=sender_name) msg = Message(subject) msg.sender = current_user.email msg.recipients = [recipient] msg.body = render_template_i18n( "documents/mail_file_sent.txt", sender_name=sender_name, message=user_msg, document_url=url_for(doc), filename=doc.title, ) filename = doc.title msg.attach(filename, doc.content_type, doc.content) mail.send(msg) flash(_("Email successfully sent"), "success") return redirect(url_for(doc))
def do_login(form): email = form.get('email', "").lower() password = form.get('password') next_url = form.get('next', u'') res = dict(username=email, email=email, next_url=next_url) if not email or not password: res['error'] = _(u"You must provide your email and password.") res['code'] = 401 return res try: user = User.query\ .filter(sql.func.lower(User.email) == email, User.can_login == True)\ .one() except NoResultFound: res['error'] = _(u"Sorry, we couldn't find an account for " u"email '{email}'.").format(email=email) res['code'] = 401 return res if user and not user.authenticate(password): res['error'] = _(u"Sorry, wrong password.") res['code'] = 401 return res # Login successful login_user(user) res['user'] = user res['email'] = user.email return res
def do_delete(self): data = request.form confirm = data.get("confirm_delete", False, type=bool) if not confirm: flash(_("Please fix the error(s) below"), "error") self.form_errors["confirm_delete"] = _( "Must be checked to ensure you " "intent to delete these tags") return self.get(self.ns) session = db.session() tags = self._get_selected_tags() if not tags: flash(_("No action performed: no tags selected"), "warning") return self.redirect_to_view() count = len(tags) entities_to_reindex = get_entities_for_reindex(tags) success_message = _n( "%(tag)s deleted", "%(num)d tags deleted:\n%(tags)s", count, tag=tags[0].label, tags=", ".join(t.label for t in tags), ) for tag in tags: session.delete(tag) session.commit() flash(success_message) schedule_entities_reindex(entities_to_reindex) return self.redirect_to_view()
def validate_photo(self, field): data = request.form.get(field.name) if not data: return data = field.data filename = data.filename valid = any(filename.lower().endswith(ext) for ext in ('.png', '.jpg', '.jpeg')) if not valid: raise ValidationError( _(u'Only PNG or JPG image files are accepted')) img_type = imghdr.what('ignored', data.read()) if img_type not in ('png', 'jpeg'): raise ValidationError( _(u'Only PNG or JPG image files are accepted')) data.seek(0) try: # check this is actually an image file im = PIL.Image.open(data) im.load() except: raise ValidationError(_(u'Could not decode image file')) # convert to jpeg # FIXME: better do this at model level? jpeg = BytesIO() im.convert('RGBA').save(jpeg, 'JPEG') field.data = jpeg.getvalue()
def __init__(self, e): render = render_template_string self.entry = e self.date = e.happened_at.strftime('%Y-%m-%d %H:%M') self.manager = render( '<img src="{{ user_photo_url(e.manager, size=16) }}" alt="" />' '<a href="{{ url_for("social.user", user_id=e.manager_id) }}">' '{{ e.manager.name }}</a>', e=e) if e.op == e.SET_INHERIT: msg = _('On {date}, {manager} has activated inheritance') elif e.op == e.UNSET_INHERIT: msg = _('On {date}, {manager} has deactivated inheritance') elif e.op == e.GRANT: msg = _( 'On {date}, {manager} has given role "{role}" to {principal}' ) elif e.op == e.REVOKE: msg = _('On {date}, {manager} has revoked role "{role}" from ' '{principal}') else: raise Exception("Unknown audit entry type %s" % e.op) principal = '' if self.entry.user: principal = render(self._USER_FMT, user=self.entry.user) elif self.entry.group: principal = render(self._GROUP_FMT, group=self.entry.group) self.msg = Markup( msg.format(date=self.date, manager=self.manager, role=self.entry.role, principal=principal))
def validate_photo(self, field): data = request.files.get(field.name) if not data: return filename = data.filename valid = any(filename.lower().endswith(ext) for ext in ('.png', '.jpg', '.jpeg')) if not valid: raise ValidationError(_(u'Only PNG or JPG image files are accepted')) img_type = imghdr.what('ignored', data.read()) if not img_type in ('png', 'jpeg'): raise ValidationError(_(u'Only PNG or JPG image files are accepted')) data.stream.seek(0) try: # check this is actually an image file im = PIL.Image.open(data.stream) im.load() except: raise ValidationError(_(u'Could not decode image file')) # convert to jpeg #FIXME: better do this at model level? jpeg = StringIO() im.save(jpeg, 'JPEG') field.data = jpeg.getvalue()
def document_send(doc_id): doc = get_document(doc_id) recipient = request.form.get("recipient") user_msg = request.form.get("message") site_name = "[{}] ".format(current_app.config["SITE_NAME"]) sender_name = current_user.name subject = site_name + _("{sender} sent you a file").format(sender=sender_name) msg = Message(subject) msg.sender = current_user.email msg.recipients = [recipient] msg.body = render_template_i18n( "documents/mail_file_sent.txt", sender_name=sender_name, message=user_msg, document_url=url_for(doc), filename=doc.title, ) filename = doc.title msg.attach(filename, doc.content_type, doc.content) mail.send(msg) flash(_("Email successfully sent"), "success") return redirect(url_for(doc))
def post(self): # Manual security check, should be done by the framework instead. if not self.is_accessible(): raise InternalServerError() if request.form['_action'] == 'cancel': return redirect(url_for('.user')) form = UserPreferencesForm(request.form, prefix=self.id) if form.validate(): if request.csrf_failed: current_app.extensions[ 'csrf-handler'].flash_csrf_failed_message() return render_template('preferences/user.html', form=form) del form.confirm_password if form.password.data: g.user.set_password(form.password.data) flash(_(u'Password changed'), 'success') del form.password form.populate_obj(g.user) current_app.db.session.commit() flash(_(u"Preferences saved."), "info") return redirect(url_for(".user")) else: return render_template('preferences/user.html', form=form)
def do_delete(self): data = request.form confirm = data.get('confirm_delete', False, type=bool) if not confirm: flash(_(u'Please fix the error(s) below'), 'error') self.form_errors['confirm_delete'] = _( u'Must be checked to ensure you ' u'intent to delete these tags') return self.get(self.ns) session = current_app.db.session() tags = self._get_selected_tags() if not tags: flash(_(u'No action performed: no tags selected'), 'warning') return self.redirect_to_view() count = len(tags) entities_to_reindex = get_entities_for_reindex(tags) success_message = _n(u'%(tag)s deleted', u'%(num)d tags deleted:\n%(tags)s', count, tag=tags[0].label, tags=u', '.join(t.label for t in tags)) map(session.delete, tags) session.commit() flash(success_message) schedule_entities_reindex(entities_to_reindex) return self.redirect_to_view()
def check_valid_name(): """Check if name is valid for content creation in this folder.""" object_id = int(request.args.get("object_id")) action = request.args.get("action") title = request.args.get("title") get_object = get_document if action == "document-edit" else get_folder obj = get_object(object_id) check_read_access(obj) if action == "new": parent = obj help_text = _('An element named "{name}" is already present in folder') elif action in ("folder-edit", "document-edit"): parent = obj.parent help_text = _('Cannot rename: "{name}" is already present in parent ' "folder") else: raise InternalServerError() existing = {e.title for e in parent.children} if action in ("folder-edit", "document-edit"): try: existing.remove(obj.title) except KeyError: pass result = {} valid = result["valid"] = title not in existing if not valid: result["help_text"] = help_text.format(name=title) return jsonify(result)
def check_valid_name(): """Check if name is valid for content creation in this folder.""" object_id = int(request.args.get('object_id')) action = request.args.get('action') title = request.args.get('title') get_object = get_document if action == 'document-edit' else get_folder obj = get_object(object_id) check_read_access(obj) if action == 'new': parent = obj help_text = _('An element named "{name}" is already present in folder') elif action in ('folder-edit', 'document-edit'): parent = obj.parent help_text = _('Cannot rename: "{name}" is already present in parent ' 'folder') else: raise InternalServerError() existing = set((e.title for e in parent.children)) if action in ('folder-edit', 'document-edit'): try: existing.remove(obj.title) except KeyError: pass result = {} valid = result['valid'] = title not in existing if not valid: result['help_text'] = help_text.format(name=title) return jsonify(result)
def do_delete(self): data = request.form confirm = data.get('confirm_delete', False, type=bool) if not confirm: flash(_(u'Please fix the error(s) below'), 'error') self.form_errors['confirm_delete'] = _(u'Must be checked to ensure you ' u'intent to delete these tags') return self.get(self.ns) session = current_app.db.session() tags = self._get_selected_tags() if not tags: flash(_(u'No action performed: no tags selected'), 'warning') return self.redirect_to_view() count = len(tags) entities_to_reindex = get_entities_for_reindex(tags) success_message = _n(u'%(tag)s deleted', u'%(num)d tags deleted:\n%(tags)s', count, tag=tags[0].label, tags=u', '.join(t.label for t in tags)) map(session.delete, tags) session.commit() flash(success_message) schedule_entities_reindex(entities_to_reindex) return self.redirect_to_view()
def forgotten_pw(new_user=False): """Reset password for users who have already activated their accounts.""" email = request.form.get("email", "").lower() action = request.form.get("action") if action == "cancel": return redirect(url_for("login.login_form")) if not email: flash(_("You must provide your email address."), "error") return render_template("login/forgotten_password.html") try: user = User.query.filter( sql.func.lower(User.email) == email, User.can_login == True ).one() except NoResultFound: flash( _("Sorry, we couldn't find an account for " "email '{email}'.").format( email=email ), "error", ) return render_template("login/forgotten_password.html"), 401 if user.can_login and not user.password: user.set_password(random_password()) db.session.commit() send_reset_password_instructions(user) flash( _("Password reset instructions have been sent to your email address."), "info" ) return redirect(url_for("login.login_form"))
def do_login(form): email = form.get("email", "").lower() password = form.get("password") next_url = form.get("next", "") res = dict(username=email, email=email, next_url=next_url) if not email or not password: res["error"] = _("You must provide your email and password.") res["code"] = 401 return res try: user = User.query.filter( sql.func.lower(User.email) == email, User.can_login == True ).one() except NoResultFound: auth_failed.send(unwrap(current_app), email=email) res["error"] = _( "Sorry, we couldn't find an account for " "email '{email}'." ).format(email=email) res["code"] = 401 return res if user and not user.authenticate(password): auth_failed.send(unwrap(current_app), email=email) res["error"] = _("Sorry, wrong password.") res["code"] = 401 return res # Login successful login_user(user) res["user"] = user res["email"] = user.email return res
def post(self): # Manual security check, should be done by the framework instead. if not self.is_accessible(): raise InternalServerError() if request.form["_action"] == "cancel": return redirect(url_for(".user")) form = UserPreferencesForm(request.form, prefix=self.id) if form.validate(): if request.csrf_failed: current_app.extensions["csrf-handler"].flash_csrf_failed_message() return render_template("preferences/user.html", form=form) del form.confirm_password if form.password.data: g.user.set_password(form.password.data) flash(_("Password changed"), "success") del form.password form.populate_obj(g.user) db.session.commit() flash(_("Preferences saved."), "info") return redirect(url_for(".user")) else: return render_template("preferences/user.html", form=form)
def do_delete(self): data = request.form confirm = data.get("confirm_delete", False, type=bool) if not confirm: flash(_("Please fix the error(s) below"), "error") self.form_errors["confirm_delete"] = _( "Must be checked to ensure you " "intent to delete these tags" ) return self.get(self.ns) session = db.session() tags = self._get_selected_tags() if not tags: flash(_("No action performed: no tags selected"), "warning") return self.redirect_to_view() count = len(tags) entities_to_reindex = get_entities_for_reindex(tags) success_message = _n( "%(tag)s deleted", "%(num)d tags deleted:\n%(tags)s", count, tag=tags[0].label, tags=", ".join(t.label for t in tags), ) for tag in tags: session.delete(tag) session.commit() flash(success_message) schedule_entities_reindex(entities_to_reindex) return self.redirect_to_view()
def render(self): render = render_template_string e = self.entry user = render(self._USER_FMT, user=e.user) self.entity_deleted = e.entity is None entity_html = e.entity_name if not self.entity_deleted: try: entity_url = url_for(e.entity) except (BuildError, ValueError): pass else: entity_html = Markup(render( u'<a href="{{ url }}">{{ entity.path or entity.name }}</a>', url=entity_url, entity=e.entity)) if e.type == 0: msg = _(u'{user} created {entity_type} {entity_id} "{entity}"') elif e.related or e.op == 1: msg = _(u'{user} made changes on {entity_type} {entity_id} "{entity}"') elif e.op == 2: msg = _(u'{user} has deleted {entity_type}: {entity_id} "{entity}"') else: raise Exception("Bad entry type: {}".format(e.type)) self.msg = Markup(msg.format(user=user, entity=entity_html, entity_type=e.entity_type.rsplit('.', 1)[-1], entity_id=e.entity_id,)) tmpl = get_template_attribute('admin/_macros.html', 'm_audit_entry') return tmpl(self)
def do_login(form): email = form.get('email', "").lower() password = form.get('password') next_url = form.get('next', u'') res = dict(username=email, email=email, next_url=next_url) if not email or not password: res['error'] = _(u"You must provide your email and password.") res['code'] = 401 return res try: user = User.query \ .filter(sql.func.lower(User.email) == email, User.can_login == True) \ .one() except NoResultFound: res['error'] = _(u"Sorry, we couldn't find an account for " u"email '{email}'.").format(email=email) res['code'] = 401 return res if user and not user.authenticate(password): res['error'] = _(u"Sorry, wrong password.") res['code'] = 401 return res # Login successful login_user(user) res['user'] = user res['email'] = user.email return res
def __call__(self, field, **kwargs): kwargs.setdefault('id', field.id) kwargs['name'] = field.name kwargs['type'] = 'file' kwargs['disabled'] = 'disabled' # JS widget will activate it input_elem = u'<input {}>'.format(html_params(**kwargs)) button_label = _(u'Add file') if 'multiple' in kwargs else _(u'Select file') existing = self.build_exisiting_files_list(field) uploads = self.build_uploads_list(field) if not field.multiple and uploads: # single file field: exising file replaced by new upload, don't show # existing existing = [] else: for data in existing: # this might be a very big bytes object: in any case it will not be used # in widget's template, and during development it makes very large pages # due to debugtoolbar capturing template parameters del data['file'] return Markup( render_template(self.template, id=field.id, field=field, widget=self, input=input_elem, button_label=button_label, existing=existing, uploaded=uploads,) )
def _validate_siret(form, field, siret=""): """SIRET validator. A WTForm validator wants a form and a field as parameters. We also want to give directly a siret, for a scripting use. """ if field is not None: siret = (field.data or "").strip() if len(siret) != 14: msg = _("SIRET must have exactly 14 characters ({count})").format( count=len(siret) ) raise validators.ValidationError(msg) if not all(("0" <= c <= "9") for c in siret): if not siret[-3:] in SIRET_CODES: msg = _( "SIRET looks like special SIRET but geographical " "code seems invalid (%(code)s)", code=siret[-3:], ) raise validators.ValidationError(msg) elif not luhn(siret): msg = _("SIRET number is invalid (length is ok: verify numbers)") raise validators.ValidationError(msg)
def do_login(form): email = form.get("email", "").lower() password = form.get("password") next_url = form.get("next", "") res = {"username": email, "email": email, "next_url": next_url} if not email or not password: res["error"] = _("You must provide your email and password.") res["code"] = 401 return res try: user = User.query.filter( sql.func.lower(User.email) == email, User.can_login == True ).one() except NoResultFound: auth_failed.send(unwrap(current_app), email=email) res["error"] = _( "Sorry, we couldn't find an account for " "email '{email}'." ).format(email=email) res["code"] = 401 return res if user and not user.authenticate(password): auth_failed.send(unwrap(current_app), email=email) res["error"] = _("Sorry, wrong password.") res["code"] = 401 return res # Login successful login_user(user) res["user"] = user res["email"] = user.email return res
def validate_photo(self, field): data = request.form.get(field.name) if not data: return data = field.data filename = data.filename valid = any(filename.lower().endswith(ext) for ext in (".png", ".jpg", ".jpeg")) if not valid: raise ValidationError(_("Only PNG or JPG image files are accepted")) img_type = imghdr.what("ignored", data.read()) if img_type not in ("png", "jpeg"): raise ValidationError(_("Only PNG or JPG image files are accepted")) data.seek(0) try: # check this is actually an image file im = PIL.Image.open(data) im.load() except Exception: raise ValidationError(_("Could not decode image file")) # convert to jpeg # FIXME: better do this at model level? jpeg = BytesIO() im.convert("RGB").save(jpeg, "JPEG") field.data = jpeg.getvalue()
def _validate_siret(form: Form, field: Field, siret: str = "") -> None: """SIRET validator. A WTForm validator wants a form and a field as parameters. We also want to give directly a siret, for a scripting use. """ if field is not None: # pyre-fixme[16]: `Field` has no attribute `data`. siret = (field.data or "").strip() if len(siret) != 14: msg = _("SIRET must have exactly 14 characters ({count})").format( count=len(siret)) raise validators.ValidationError(msg) if not all(("0" <= c <= "9") for c in siret): if not siret[-3:] in SIRET_CODES: msg = _( "SIRET looks like special SIRET but geographical " "code seems invalid (%(code)s)", code=siret[-3:], ) raise validators.ValidationError(msg) elif not luhn(siret): msg = _("SIRET number is invalid (length is ok: verify numbers)") raise validators.ValidationError(msg)
def _validate_siret(form, field, siret=""): """SIRET validator. A WTForm validator wants a form and a field as parameters. We also want to give directly a siret, for a scripting use. """ if field is not None: siret = (field.data or '').strip() if len(siret) != 14: msg = _('SIRET must have exactly 14 characters ({count})').format( count=len(siret), ) raise validators.ValidationError(msg) if not all(('0' <= c <= '9') for c in siret): if not siret[-3:] in SIRET_CODES: msg = _( 'SIRET looks like special SIRET but geographical ' 'code seems invalid (%s)', code=siret[-3:], ) raise validators.ValidationError(msg) elif not luhn(siret): msg = _('SIRET number is invalid (length is ok: verify numbers)') raise validators.ValidationError(msg)
def validate_photo(self, field: FileField) -> None: data = request.form.get(field.name) if not data: return data = field.data filename = data.filename valid = any(filename.lower().endswith(ext) for ext in (".png", ".jpg", ".jpeg")) if not valid: raise ValidationError( _("Only PNG or JPG image files are accepted")) img_type = imghdr.what("ignored", data.read()) if img_type not in ("png", "jpeg"): raise ValidationError( _("Only PNG or JPG image files are accepted")) data.seek(0) try: # check this is actually an image file im = PIL.Image.open(data) im.load() except Exception: raise ValidationError(_("Could not decode image file")) # convert to jpeg # FIXME: better do this at model level? jpeg = BytesIO() im.convert("RGB").save(jpeg, "JPEG") field.data = jpeg.getvalue()
def reset_password(token): expired, invalid, user = reset_password_token_status(token) if invalid: flash(_("Invalid reset password token."), "error") elif expired: flash(_("Password reset expired"), "error") if invalid or expired: return redirect(url_for("login.forgotten_pw")) return render_template_i18n("login/password_reset.html")
def folder_edit(folder): check_write_access(folder) changed = edit_object(folder) if changed: db.session.commit() flash(_("Folder properties successfully edited."), "success") else: flash(_("You didn't change any property."), "success") return redirect(url_for(folder))
def get(self): login_entries = LoginSession.query \ .order_by(LoginSession.started_at.asc()) \ .all() # .options(sa.orm.joinedload(LoginSession.user)) daily, weekly, monthly = uniquelogins(login_entries) new_logins, total_users = newlogins(login_entries) stats = { 'today': stats_since(timedelta(days=1)), 'this_week': stats_since(timedelta(days=7)), 'this_month': stats_since(timedelta(days=30)), } # let's format the data into NVD3 datastructures connections = [ { 'key': _('Daily'), 'color': '#7777ff', 'values': daily }, { 'key': _('Weekly'), 'color': '#2ca02c', 'values': weekly, 'disabled': True, }, { 'key': _('Monthly'), 'color': '#ff7f0e', 'values': monthly, 'disabled': True, }, ] new_logins = [ { 'key': _('New'), 'color': '#ff7f0e', "bar": True, 'values': new_logins, }, { 'key': _('Total'), 'color': '#2ca02c', 'values': total_users }, ] return render_template( "admin/dashboard.html", stats=stats, connections=connections, new_logins=new_logins, )
def get(self) -> str: login_entries = LoginSession.query.order_by( LoginSession.started_at.asc()).all() # .options(sa.orm.joinedload(LoginSession.user)) daily, weekly, monthly = uniquelogins(login_entries) new_logins, total_users = newlogins(login_entries) stats = { "today": stats_since(timedelta(days=1)), "this_week": stats_since(timedelta(days=7)), "this_month": stats_since(timedelta(days=30)), } # let's format the data into NVD3 datastructures connections = [ { "key": _("Daily"), "color": "#7777ff", "values": daily }, { "key": _("Weekly"), "color": "#2ca02c", "values": weekly, "disabled": True, }, { "key": _("Monthly"), "color": "#ff7f0e", "values": monthly, "disabled": True, }, ] new_logins = [ { "key": _("New"), "color": "#ff7f0e", "bar": True, "values": new_logins }, { "key": _("Total"), "color": "#2ca02c", "values": total_users }, ] return render_template( "admin/dashboard.html", stats=stats, connections=connections, new_logins=new_logins, )
def render(self): aoColumns = [{'asSorting': []}] if self.show_controls else [] aoColumns += [{'asSorting': col['sorting'], 'bSortable': col['sortable']} for col in self.columns] datatable_options = { 'sDom': 'fFriltip', 'aoColumns': aoColumns, 'bFilter': True, 'oLanguage': { 'sSearch': self.options.get('search_label', _(u'Filter records:')), 'oPaginate': { 'sPrevious': _(u'Previous'), 'sNext': _(u'Next'), }, 'sLengthMenu': _(u'Entries per page: _MENU_'), 'sInfo': _(u'Showing _START_ to _END_ of _TOTAL_ entries'), 'sInfoEmpty': _(u'Showing _START_ to _END_ of _TOTAL_ entries'), 'sInfoFiltered': _(u'(filtered from _MAX_ total entries)'), 'sAddAdvancedFilter': _(u'Add a filter'), 'sZeroRecords': _(u'No matching records found'), 'sEmptyTable': _(u'No matching records found'), }, 'bPaginate': self.paginate, 'sPaginationType': "bootstrap", 'bLengthChange': True, 'iDisplayLength': 25, 'bStateSave': self.save_state, 'bProcessing': True, 'bServerSide': True, 'sAjaxSource': self.ajax_source, } advanced_search_filters = [] for c in self.search_criterions: if not c.has_form_filter: continue d = dict(name=c.name, label=unicode(c.label), type=c.form_filter_type, args=c.form_filter_args, unset=c.form_unset_value,) if c.has_form_default_value: d['defaultValue'] = c.form_default_value advanced_search_filters.append(d) if advanced_search_filters: datatable_options['aoAdvancedSearchFilters'] = advanced_search_filters return Markup(render_template('widgets/render_ajax_table.html', datatable_options=datatable_options, view=self))
def make_tabs(user): return [ dict(id='profile', label=_(u'Profile'), link=url_for(user, tab='profile')), # dict(id='conversations', label=_(u'Conversations'), link=url_for(user), is_online=True), dict(id='documents', label=_(u'Documents'), link=url_for(user, tab='documents')), dict(id='images', label=_(u'Images'), link=url_for(user, tab='images')), dict(id='audit', label=_(u'Audit'), link=url_for(user, tab='audit')), ]
def document_edit(doc_id): doc = get_document(doc_id) check_write_access(doc) changed = edit_object(doc) if changed: db.session.commit() flash(_(u"Document properties successfully edited."), "success") else: flash(_(u"You didn't change any property."), "success") return redirect(url_for(doc))
def wizard_check_data(): """Filter and detect existing members, existing accounts and new emails.""" if request.method == "GET": return redirect(url_for(".members", community_id=g.community.slug)) g.breadcrumb.append( BreadcrumbItem( label=_("Members"), url=Endpoint("communities.members", community_id=g.community.slug), ) ) is_csv = False if request.form.get("wizard-emails"): wizard_emails = request.form.get("wizard-emails").split(",") existing_accounts_object, existing_members_objects, final_email_list = wizard_extract_data( wizard_emails ) final_email_list_json = json.dumps(final_email_list) else: is_csv = True accounts_data = wizard_read_csv(request.files["csv_file"]) if not accounts_data: flash(_("To add new members, please follow the CSV file model."), "warning") return redirect( url_for(".wizard_data_insertion", community_id=g.community.slug) ) existing_accounts, existing_members_objects, final_email_list = wizard_extract_data( accounts_data, is_csv=True ) existing_accounts_object = existing_accounts["account_objects"] existing_accounts_csv_roles = existing_accounts["csv_roles"] final_email_list_json = json.dumps(final_email_list) if not final_email_list: flash(_("No new members were found"), "warning") return redirect( url_for(".wizard_data_insertion", community_id=g.community.slug) ) ctx = { "existing_accounts_object": existing_accounts_object, "csv_roles": existing_accounts_csv_roles if is_csv else False, "wizard_emails": final_email_list_json, "existing_members_objects": existing_members_objects, } return render_template("community/wizard_check_members.html", **ctx)
def message(self, ignore_community=False): try: # another quick&dirty approach for now. FIXME later. entry = self._model object_class = entry.object_type.split(".")[-1] object_class_localized = _(object_class) ctx = {} ctx["verb"] = entry.verb ctx["object_name"] = entry.object.name or getattr( entry.object, "title", "???") ctx["object_url"] = url_for(entry.object) ctx["object_type"] = object_class_localized ctx["object"] = OBJ_TEMPLATE.render(**ctx) if entry.target: ctx["target_name"] = entry.target.name ctx["target_url"] = url_for(entry.target) ctx["target"] = OBJ_TEMPLATE.render( object_name=ctx["target_name"], object_url=ctx["target_url"]) msg = MESSAGES.get((entry.verb, entry.object.__class__)) if msg: msg = msg.format(**ctx) if entry.target and not ignore_community: msg += " " + _("in the community {target}.").format(**ctx) else: msg += "." elif entry.verb == "post": msg = _("has posted an object of type {object_type} " 'called "{object}"').format(**ctx) if entry.target and not ignore_community: msg += " " + _("in the community {target}.").format(**ctx) else: msg += "." elif entry.verb == "join": msg = _("has joined the community {object}.").format(**ctx) elif entry.verb == "leave": msg = _("has left the community {object}.").format(**ctx) elif entry.verb == "update": msg = _("has updated {object_type} {object}.").format(**ctx) else: msg = _('has done action "{verb}" on object "{object}".' ).format(**ctx) return Markup(msg) except BaseException: logger.exception("Exception while presenting activity message") raise
def message(self, ignore_community=False): try: # another quick&dirty approach for now. FIXME later. entry = self._model object_class = entry.object_type.split('.')[-1] object_class_localized = _(object_class) ctx = {} ctx['verb'] = entry.verb ctx['object_name'] = entry.object.name or getattr( entry.object, 'title', "???") ctx['object_url'] = url_for(entry.object) ctx['object_type'] = object_class_localized ctx['object'] = OBJ_TEMPLATE.render(**ctx) if entry.target: ctx['target_name'] = entry.target.name ctx['target_url'] = url_for(entry.target) ctx['target'] = OBJ_TEMPLATE.render( object_name=ctx['target_name'], object_url=ctx['target_url']) msg = MESSAGES.get((entry.verb, entry.object.__class__)) if msg: msg = msg.format(**ctx) if entry.target and not ignore_community: msg += " " + _('in the community {target}.').format(**ctx) else: msg += "." elif entry.verb == 'post': msg = _('has posted an object of type {object_type} ' 'called "{object}"').format(**ctx) if entry.target and not ignore_community: msg += " " + _('in the community {target}.').format(**ctx) else: msg += "." elif entry.verb == 'join': msg = _('has joined the community {object}.').format(**ctx) elif entry.verb == 'leave': msg = _('has left the community {object}.').format(**ctx) elif entry.verb == 'update': msg = _('has updated {object_type} {object}.').format(**ctx) else: msg = _('has done action "{verb}" on object "{object}".' ).format(**ctx) return Markup(msg) except: logger.exception('Exception while presenting activity message') raise
def __call__(self, form, field): l = field.data and len(field.data) or 0 if l < self.min or self.max != -1 and l > self.max: message = self.message if message is None: if self.max == -1: message = _n( u'Field must be at least %(min)d character long.', u'Field must be at least %(min)d characters long.', self.min, min=self.min) elif self.min == -1: message = _n( u'Field cannot be longer than %(max)d character.', u'Field cannot be longer than %(max)d characters.', self.max, max=self.max) else: message = _( u'Field must be between %(min)d and %(max)d characters long.', min=self.min, max=self.max) raise ValidationError(message % dict(min=self.min, max=self.max, length=l))
def folder_post(folder_id): """A POST on a folder can result on several different actions (depending on the `action` parameter).""" folder = get_folder(folder_id) action = request.form.get("action") if action == "edit": return folder_edit(folder) elif action == "upload": return upload_new(folder) elif action == "download": return download_multiple(folder) elif action == "delete": return delete_multiple(folder) elif action == "new": return create_subfolder(folder) elif action == "move": return move_multiple(folder) elif action == "change-owner": return change_owner(folder) else: # Probably an error or a hack attempt. # Logger will inform sentry if enabled logger = logging.getLogger(__name__) logger.error("Unknown folder action.", extra={"stack": True}) flash(_("Unknown action."), "error") return redirect(url_for(folder))
def url_value_preprocess(self, endpoint, view_args): Model = view_args.pop('Model', None) group = view_args.pop('group', _MARKER) if group == u'_': # "General" group group = None if group is not _MARKER: view_args['group'] = group if Model is not None: svc = self.svc Model = svc.get_vocabulary(name=Model, group=group) g.breadcrumb.append( BreadcrumbItem( label=Model.Meta.group if group else _('Global'), url=url_for('.vocabularies_group', group=group or u'_'), )) g.breadcrumb.append( BreadcrumbItem( label=Model.Meta.label, url=url_for('.vocabularies_model', group=group or u'_', Model=Model.Meta.name), )) view_args['Model'] = Model
def get(self): geoips = [] for filename in DATA_FILES: try: geoips.append(pygeoip.GeoIP(filename)) except (pygeoip.GeoIPError, IOError): pass sessions = LoginSession.query.order_by( LoginSession.id.desc()).limit(50).all() unknown_country = _(u'Country unknown') for session in sessions: country = unknown_country if geoips and session.ip_address: ip_address = session.ip_address multiple = ip_address.split(',') if multiple: # only use last ip in the list, most likely the public address ip_address = multiple[-1] for g in geoips: try: country = g.country_name_by_addr(ip_address) except: # noqa continue if country: break else: country = unknown_country session.country = country return render_template("admin/login_sessions.html", **locals())
def url_value_preprocess(self, endpoint, view_args): Model = view_args.pop('Model', None) group = view_args.pop('group', _MARKER) if group == u'_': # "General" group group = None if group is not _MARKER: view_args['group'] = group if Model is not None: svc = self.svc Model = svc.get_vocabulary(name=Model, group=group) g.breadcrumb.append(BreadcrumbItem( label=Model.Meta.group if group else _('Global'), url=url_for('.vocabularies_group', group=group or u'_'), )) g.breadcrumb.append(BreadcrumbItem( label=Model.Meta.label, url=url_for('.vocabularies_model', group=group or u'_', Model=Model.Meta.name), )) view_args['Model'] = Model
def __call__(self, form, field): field_data_length = field.data and len(field.data) or 0 if (field_data_length < self.min or self.max != -1 and field_data_length > self.max): message = self.message if message is None: if self.max == -1: message = _n( "Field must be at least %(min)d character long.", "Field must be at least %(min)d characters long.", self.min, min=self.min, ) elif self.min == -1: message = _n( "Field cannot be longer than %(max)d character.", "Field cannot be longer than %(max)d characters.", self.max, max=self.max, ) else: message = _( "Field must be between %(min)d and %(max)d characters long.", min=self.min, max=self.max, ) raise validators.ValidationError(message % { "min": self.min, "max": self.max, "length": field_data_length })
def wizard_new_accounts(): """Complete new emails information.""" if request.method == "GET": return redirect(url_for(".members", community_id=g.community.slug)) g.breadcrumb.append( BreadcrumbItem( label=_("Members"), url=Endpoint("communities.members", community_id=g.community.slug), ) ) wizard_emails = request.form.get("wizard-emails") wizard_accounts = json.loads(wizard_emails) wizard_existing_account = {} new_accounts = [] for user in wizard_accounts: if user["status"] == "existing": wizard_existing_account[user["email"]] = user["role"] elif user["status"] == "new": new_accounts.append(user) existing_account = json.dumps(wizard_existing_account) return render_template( "community/wizard_new_accounts.html", existing_account=existing_account, new_accounts=new_accounts, )
def page_compare(): title = request.args["title"].strip() try: page = get_page_by_title(title) except NoResultFound: return redirect( url_for(".page_edit", title=title, community_id=g.community.slug) ) revisions = page.revisions revisions = sorted(revisions, key=lambda x: x.number) revs_to_compare = [] for arg in request.args: if arg.startswith("rev"): revs_to_compare.append(int(arg[3:])) if len(revs_to_compare) != 2: flash(_("You must check exactly 2 revisions."), "error") url = url_for(".page_changes", title=title, community_id=g.community.slug) return redirect(url) revs_to_compare.sort() from_rev = revisions[revs_to_compare[0]] to_rev = revisions[revs_to_compare[1]] assert from_rev.number == revs_to_compare[0] assert to_rev.number == revs_to_compare[1] from_lines = from_rev.body_src.splitlines(1) to_lines = to_rev.body_src.splitlines(1) differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) diff = differ.compare(from_lines, to_lines) diff = [line for line in diff if not line.startswith("?")] actions.context["object"] = page ctx = {"page": page, "diff": diff, "rev1": from_rev, "rev2": to_rev} return render_template("wiki/compare.html", **ctx)
def delete(self): session = db.session() session.delete(self.obj) activity.send( self, actor=g.user, verb="delete", object=self.obj, target=self.activity_target, ) try: session.commit() except sa.exc.IntegrityError as e: rv = self.handle_commit_exception(e) if rv is not None: return rv session.rollback() logger.error(e) flash( _("This entity is referenced by another object and cannot be deleted." ), "error", ) return self.redirect_to_view() else: flash(self.message_success(), "success") # FIXME: for DELETE verb response in case of success should be 200, 202 # (accepted) or 204 (no content) return self.redirect_to_index()
def data(self, *args, **kwargs): task_id = request.args.get("task_id") task = celery.result.AsyncResult(task_id) result = dict(state=task.state, exported=0, total=0) if task.state in ("REVOKED", "PENDING", "STARTED"): return result if task.state == "PROGRESS": result.update(task.result) return result if task.state == "FAILURE": result["message"] = _("An error happened during generation of file.") return result if task.state == "SUCCESS": result.update(task.result) handle = result["handle"] uploads = current_app.extensions["uploads"] filemeta = uploads.get_metadata(current_user, handle) result["filename"] = filemeta.get("filename", "export.xlsx") result["downloadUrl"] = url_for( "uploads.handle", handle=handle, _external=True ) return result # unattended state, return data anyway # FIXME: log at error level for sentry? return result
def url_value_preprocess(self, endpoint, view_args): model_name = view_args.pop("Model", None) group = view_args.pop("group", _MARKER) if group == "_": # "General" group group = "" if group is not _MARKER: view_args["group"] = group if model_name is not None: svc = get_service("vocabularies") Model = svc.get_vocabulary(name=model_name, group=group) g.breadcrumb.append( BreadcrumbItem( label=Model.Meta.group if group else _("Global"), url=url_for(".vocabularies_group", group=group or "_"), )) g.breadcrumb.append( BreadcrumbItem( label=Model.Meta.label, url=url_for(".vocabularies_model", group=group or "_", Model=Model.Meta.name), )) view_args["Model"] = Model
def delete(self): session = db.session() session.delete(self.obj) activity.send( self, actor=g.user, verb="delete", object=self.obj, target=self.activity_target, ) try: session.commit() except sa.exc.IntegrityError as e: rv = self.handle_commit_exception(e) if rv is not None: return rv session.rollback() logger.error(e) flash( _("This entity is referenced by another object and cannot be deleted."), "error", ) return self.redirect_to_view() else: flash(self.message_success(), "success") # FIXME: for DELETE verb response in case of success should be 200, 202 # (accepted) or 204 (no content) return self.redirect_to_index()
def __call__(self, form, field): field_data_length = field.data and len(field.data) or 0 if ( field_data_length < self.min or self.max != -1 and field_data_length > self.max ): message = self.message if message is None: if self.max == -1: message = _n( "Field must be at least %(min)d character long.", "Field must be at least %(min)d characters long.", self.min, min=self.min, ) elif self.min == -1: message = _n( "Field cannot be longer than %(max)d character.", "Field cannot be longer than %(max)d characters.", self.max, max=self.max, ) else: message = _( "Field must be between %(min)d and %(max)d characters long.", min=self.min, max=self.max, ) raise validators.ValidationError( message % {"min": self.min, "max": self.max, "length": field_data_length} )
def wizard_saving(): """Automatically add existing accounts to the current community. Create accounts for new emails, add them to the community and send them a password reset email. """ community = g.community._model existing_accounts = request.form.get("existing_account") existing_accounts = json.loads(existing_accounts) new_accounts = request.form.get("new_accounts") new_accounts = json.loads(new_accounts) if not (existing_accounts or new_accounts): flash(_("No new members were found"), "warning") return redirect(url_for(".members", community_id=g.community.slug)) if existing_accounts: for email, role in existing_accounts.items(): user = User.query.filter(User.email == email).first() community.set_membership(user, role) app = unwrap(current_app) activity.send(app, actor=user, verb="join", object=community) db.session.commit() if new_accounts: for account in new_accounts: email = account["email"] first_name = account["first_name"] last_name = account["last_name"] role = account["role"] user = User( email=email, last_name=last_name, first_name=first_name, can_login=True ) db.session.add(user) community.set_membership(user, role) app = unwrap(current_app) activity.send(app, actor=user, verb="join", object=community) db.session.commit() send_reset_password_instructions(user) flash(_("New members added successfully"), "success") return redirect(url_for(".members", community_id=community.slug))
def do_merge(self): target_id = request.form.get("merge_to", type=int) if not target_id: flash(_("You must select a target tag to merge to"), "error") return self.get(self.ns) target = Tag.query.filter(Tag.ns == self.ns, Tag.id == target_id).scalar() if not target: flash(_("Target tag not found, no action performed"), "error") return self.get(self.ns) merge_from = set(self._get_selected_tags()) if target in merge_from: merge_from.remove(target) if not merge_from: flash(_("No tag selected for merging"), "warning") return self.get(self.ns) session = db.session() merge_from_ids = [t.id for t in merge_from] tbl = entity_tag_tbl entities_to_reindex = get_entities_for_reindex(merge_from) already_tagged = sa.sql.select([tbl.c.entity_id]).where( tbl.c.tag_id == target.id ) del_dup = tbl.delete().where( sa.sql.and_( tbl.c.tag_id.in_(merge_from_ids), tbl.c.entity_id.in_(already_tagged) ) ) session.execute(del_dup) update = ( tbl.update() .where(tbl.c.tag_id.in_(merge_from_ids)) .values(tag_id=target.id) ) session.execute(update) for merged in merge_from: session.delete(merged) session.commit() schedule_entities_reindex(entities_to_reindex) return self.redirect_to_view()
def __call__(self, form, field): svc = get_service('antivirus') if not svc: return res = svc.scan(field.data) if res is False: raise ValidationError(_(u'Virus detected!'))
def validate_password(self, field): pwd = field.data confirmed = self['confirm_password'].data if pwd != confirmed: raise ValidationError( _(u'Passwords differ. Ensure you have typed same password in both' u' "password" field and "confirm password" field.'))
def __init__(self, *args, **kwargs): if len(args) == 0: kwargs.setdefault('name', 'tags') if len(args) < 2: kwargs.setdefault('label', _(u'Tags')) super(TagCriterion, self).__init__(*args, **kwargs)
def page_delete(): title = request.form["title"].strip() try: page = get_page_by_title(title) except NoResultFound: flash(_("This page doesn't exist"), "error") return redirect(url_for(".index", community_id=g.community.slug)) db.session.delete(page) app = unwrap(current_app) community = g.community._model activity.send(app, actor=current_user, verb="delete", object=page, target=community) db.session.commit() flash(_("Page %(title)s deleted.", title=title)) return redirect(url_for(".index", community_id=g.community.slug))