Release v2.1: GDPR, passkeys, session management, admin redesign

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-07 02:43:57 +03:00
parent d4f0eaa7d9
commit 0a51001791
32 changed files with 1529 additions and 193 deletions
+59
View File
@@ -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"