My problem arises in the fact that I want to make a panel like with the help of flask-admin, but for a user who logs into his personal account and there at least a panel with links is displayed with filling forms. So that when the user fills them, they are sent to the admin in the database! Is it possible? Can you advise something?
At the moment the code is like this:
import os from flask import Flask, render_template, url_for, redirect, request, session, flash, abort from flask_sqlalchemy import SQLAlchemy from flask_admin import helpers, expose from flask_admin import helpers as admin_helpers import flask_admin as admin import flask_login as login from datetime import datetime from flask_admin.contrib import sqla from flask_security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin, login_user, \ login_required, logout_user, current_user from wtforms import form, StringField, PasswordField, BooleanField, validators, fields from flask_security.utils import encrypt_password from werkzeug.security import generate_password_hash, check_password_hash app = Flask(__name__) app.config['DATABASE_FILE'] = 'sample_db.sqlite' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE'] app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True app.config['SECRET_KEY'] = 'thisissecret' db = SQLAlchemy(app) # Define models roles_users = db.Table( 'roles_users', db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), db.Column('role_id', db.Integer(), db.ForeignKey('role.id')) ) class Role(RoleMixin, db.Model): id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80), unique=True) description = db.Column(db.String(255)) def __str__(self): return self.name class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) login = db.Column(db.String(255)) email = db.Column(db.String(50), unique=True) password = db.Column(db.String(100)) active = db.Column(db.Boolean()) registered_on = db.Column('registered_on', db.DateTime) roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic')) # Flask-Login integration def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return self.id # Required for administrative interface def __unicode__(self): return self.login def __repr__(self): return '<User %r>' % self.login def __str__(self): return self.email # Setup Flask-Security user_datastore = SQLAlchemyUserDatastore(db, User, Role) security = Security(app, user_datastore) # Define login and registration forms (for flask-login) class LoginForm(form.Form): user_message = 'Mailing address should be no more than 60 characters' user_required = 'Please enter your login.' pass_message = 'Password should be no more than 50 characters' pass_required = 'Please enter your password.' login = fields.StringField('Username', validators=[validators.Length(message=user_message, max=60), validators.required(user_required)]) password = fields.PasswordField('Password', validators=[validators.Length(message=pass_message, max=50), validators.required(pass_required)]) def get_user(self): return db.session.query(User).filter_by(login=self.login.data).first() def validate_login(self, field): user = self.get_user() if user is None: raise validators.ValidationError('Invalid user') # we're comparing the plaintext pw with the the hash from the db if not check_password_hash(user.password, self.password.data): # to compare plain text passwords use # if user.password != self.password.data: raise validators.ValidationError('Invalid password') class RegistrationForm(form.Form): username_message = 'The name must be at least 4 letters and no more than 25 characters' username_required = 'Please enter your login.' email_address_message = 'Mailing address should be no more than 60 characters' email_address_required = 'Please enter your email address.' password_message = 'Passwords must match' login = fields.StringField('Username', validators=[validators.Length(message=username_message, min=4, max=25), validators.required(username_required)]) email = fields.StringField('Email', validators=[validators.Length(message=email_address_message, max=60), validators.required(email_address_required)]) password = fields.PasswordField('Password', validators=[validators.required(password_message), validators.EqualTo('confirm', message='Passwords must match')]) confirm = fields.PasswordField('Repeat Password') def validate_login(self, field): if db.session.query(User).filter_by(login=self.login.data).count() > 0: raise validators.ValidationError('Duplicate username') if db.session.query(User).filter_by(email=self.email.data).count() > 0: raise validators.ValidationError('Duplicate email') # Initialize flask-login def init_login(): login_manager = login.LoginManager() login_manager.init_app(app) # Create user loader function @login_manager.user_loader def load_user(user_id): return db.session.query(User).get(user_id) # Create customized model view class class MyModelView(sqla.ModelView): def is_accessible(self): if not current_user.is_active or not current_user.is_authenticated: return False if current_user.has_role('superuser'): return True return False def _handle_view(self, name, **kwargs): """ Override builtin _handle_view in order to redirect users when a view is not accessible. """ if not self.is_accessible(): if current_user.is_authenticated: # permission denied abort(403) else: # login return redirect(url_for('admin.login_view', next=request.url)) # Create customized index view class that handles login & registration class MyAdminIndexView(admin.AdminIndexView): @expose('/') def index(self): if not login.current_user.is_authenticated: return redirect(url_for('.login_view')) return super(MyAdminIndexView, self).index() @expose('/login/', methods=['GET', 'POST']) def login_view(self): # handle user login form = LoginForm(request.form) if helpers.validate_form_on_submit(form): user = form.get_user() login.login_user(user) if login.current_user.is_authenticated: return redirect(url_for('.index')) link = '<p>Don\'t have an account? <a href="' + url_for('.register_view') + '">Click here to register.</a></p>' self._template_args['form'] = form self._template_args['link'] = link return super(MyAdminIndexView, self).index() @expose('/register/', methods=['GET', 'POST']) def register_view(self): form = RegistrationForm(request.form) if helpers.validate_form_on_submit(form): user = User() form.populate_obj(user) # we hash the users password to avoid saving it as plaintext in the db, # remove to use plain text: user.password = generate_password_hash(form.password.data) db.session.add(user) db.session.commit() login.login_user(user) return redirect(url_for('.index')) link = '<p>Already have an account? <a href="' + url_for('.login_view') + '">Click here to log in.</a></p>' self._template_args['form'] = form self._template_args['link'] = link return super(MyAdminIndexView, self).index() @expose('/logout/') def logout_view(self): login.logout_user() return redirect(url_for('.index')) # Flask views @app.route('/') def index(): return render_template('index.html') # Initialize flask-login init_login() # Create admin admin = admin.Admin(app, index_view=MyAdminIndexView(), base_template='my_master.html') # Add view admin.add_view(MyModelView(User, db.session)) admin.add_view(MyModelView(Role, db.session)) # define a context processor for merging flask-admin's template context into the # flask-security views. @security.context_processor def security_context_processor(): return dict( admin_base_template=admin.base_template, admin_view=admin.index_view, h=admin_helpers, get_url=url_for ) def build_sample_db(): """ Populate a small db with some example entries. """ db.create_all() with app.app_context(): user_role = Role(name='user') super_user_role = Role(name='superuser') db.session.add(user_role) db.session.add(super_user_role) db.session.commit() test_user = user_datastore.create_user( login='Admin', email='admin', password=generate_password_hash('admin'), roles=[user_role, super_user_role] ) db.session.add(test_user) db.session.commit() return if __name__ == '__main__': # Build a sample db on the fly, if one does not exist yet. app_dir = os.path.realpath(os.path.dirname(__file__)) database_path = os.path.join(app_dir, app.config['DATABASE_FILE']) if not os.path.exists(database_path): build_sample_db() # Start app app.run(debug=True)