Define a user object
| 194 | |
| 195 | |
| 196 | class User(db.Model, UserMixin): |
| 197 | """Define a user object""" |
| 198 | __tablename__ = 'user' |
| 199 | id = db.Column(db.Integer, primary_key=True) |
| 200 | email = db.Column(db.String(256), nullable=True) |
| 201 | username = db.Column(db.String(64), unique=True, nullable=False) |
| 202 | password = db.Column(PgAdminDbBinaryString()) |
| 203 | active = db.Column(db.Boolean(), nullable=False) |
| 204 | confirmed_at = db.Column(db.DateTime()) |
| 205 | masterpass_check = db.Column(PgAdminDbBinaryString()) |
| 206 | roles = db.relationship('Role', secondary=roles_users, |
| 207 | backref=db.backref('users', lazy='dynamic')) |
| 208 | auth_source = db.Column(db.String(16), unique=True, nullable=False) |
| 209 | # fs_uniquifier is required by flask-security-too >= 4. |
| 210 | fs_uniquifier = db.Column(db.String(255), unique=True, nullable=False, |
| 211 | default=(lambda _: uuid.uuid4().hex)) |
| 212 | login_attempts = db.Column(db.Integer, default=0) |
| 213 | locked = db.Column(db.Boolean(), default=False) |
| 214 | |
| 215 | @property |
| 216 | def is_active(self): |
| 217 | # Treat a locked account as inactive so Flask-Login's login_user() |
| 218 | # refuses to mint a session, regardless of which view authenticated |
| 219 | # the password. Without this, a lockout set by /authenticate/login |
| 220 | # is bypassed by a direct POST to Flask-Security's /login. |
| 221 | return self.active and not self.locked |
| 222 | |
| 223 | def is_locked(self, form_error=None): |
| 224 | # Flask-Security's LoginForm.validate() calls this after password |
| 225 | # verification and treats the return value inverted: True means |
| 226 | # "not locked, proceed"; False means "locked, fail validation". |
| 227 | # The default UserMixin.is_locked unconditionally returns True, |
| 228 | # which is what allows the /login bypass on a locked account. |
| 229 | if self.locked: |
| 230 | if form_error is not None: |
| 231 | form_error.append(gettext( |
| 232 | 'Your account is locked. Please contact the ' |
| 233 | 'Administrator.')) |
| 234 | return False |
| 235 | return True |
| 236 | |
| 237 | |
| 238 | class Setting(db.Model, UserScopedMixin): |