Release v2.1: GDPR, passkeys, session management, admin redesign
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -96,6 +96,8 @@ class User(UserMixin, db.Model):
|
||||
is_admin = db.Column(db.Boolean, nullable=False, default=False)
|
||||
is_active = db.Column(db.Boolean, nullable=False, default=True)
|
||||
group_id = db.Column(db.Integer, db.ForeignKey("user_groups.id"), nullable=True, index=True)
|
||||
gdpr_accepted_at = db.Column(db.DateTime, nullable=True)
|
||||
cookie_analytics = db.Column(db.Boolean, nullable=False, default=False)
|
||||
created_at = db.Column(
|
||||
db.DateTime,
|
||||
nullable=False,
|
||||
@@ -126,6 +128,63 @@ class User(UserMixin, db.Model):
|
||||
return int(result or 0)
|
||||
|
||||
|
||||
class UserSession(db.Model):
|
||||
__tablename__ = "user_sessions"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False, index=True)
|
||||
session_key = db.Column(db.String(64), unique=True, nullable=False, index=True)
|
||||
ip_address = db.Column(db.String(45), nullable=True)
|
||||
user_agent = db.Column(db.String(512), nullable=True)
|
||||
created_at = db.Column(
|
||||
db.DateTime,
|
||||
nullable=False,
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
)
|
||||
last_seen_at = db.Column(
|
||||
db.DateTime,
|
||||
nullable=False,
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
)
|
||||
revoked = db.Column(db.Boolean, nullable=False, default=False)
|
||||
|
||||
user = db.relationship("User", backref=db.backref("sessions", lazy="dynamic"))
|
||||
|
||||
@property
|
||||
def device_label(self):
|
||||
if not self.user_agent:
|
||||
return "Неизвестное устройство"
|
||||
ua = self.user_agent.lower()
|
||||
if "mobile" in ua or "android" in ua or "iphone" in ua:
|
||||
return "Мобильное устройство"
|
||||
if "windows" in ua:
|
||||
return "Windows"
|
||||
if "mac" in ua:
|
||||
return "macOS"
|
||||
if "linux" in ua:
|
||||
return "Linux"
|
||||
return "Браузер"
|
||||
|
||||
|
||||
class UserPasskey(db.Model):
|
||||
__tablename__ = "user_passkeys"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False, index=True)
|
||||
credential_id = db.Column(db.String(512), unique=True, nullable=False, index=True)
|
||||
public_key = db.Column(db.Text, nullable=False)
|
||||
sign_count = db.Column(db.Integer, nullable=False, default=0)
|
||||
name = db.Column(db.String(120), nullable=False, default="Passkey")
|
||||
created_at = db.Column(
|
||||
db.DateTime,
|
||||
nullable=False,
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
)
|
||||
last_used_at = db.Column(db.DateTime, nullable=True)
|
||||
|
||||
user = db.relationship("User", backref=db.backref("passkeys", lazy="dynamic"))
|
||||
|
||||
|
||||
class UserGroup(db.Model):
|
||||
__tablename__ = "user_groups"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user