From 3e8c490851bd31cba98e540a248b135fd8ca60d4 Mon Sep 17 00:00:00 2001 From: bwstudio Date: Wed, 9 Sep 2026 19:17:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(plugins):=20Cookie=20=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=EF=BC=88=E8=B4=A6=E5=8F=B7/=E7=AB=99?= =?UTF-8?q?=E7=82=B9=20+=20=E5=88=B7=E6=96=B0=E8=AE=B0=E5=BD=95=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 以插件方式新增 Cookie 管理模块,不改动 framework 业务逻辑。 数据层 - CookieUser / CookieSite 两个模型(applications/models/admin_cookie.py) - 对应 ManageSchema(applications/schemas/admin_cookie.py) - 模型与 schema 在 applications/{models,schemas}/__init__.py 中注册,便于 Alembic 跟踪 - 新增两个迁移脚本(cookie_site / cookie_user + cookie 站点表) 插件 - plugins/cookieManager/:入口 __init__.py + 三个视图(概览 / 账号 / 站点) - 后台模板:cookie_user 与 cookie_site 各自的 main/add/edit - 路由前缀 /system/cookie-user/*、/system/cookie-site/* --- applications/models/__init__.py | 1 + applications/models/admin_cookie.py | 73 ++++++ applications/schemas/__init__.py | 1 + applications/schemas/admin_cookie.py | 21 ++ ..._add_cookie_user_and_cookie_site_tables.py | 78 +++++++ .../9ae98ba6025b_add_cookie_manager_table.py | 45 ++++ plugins/cookieManager/__init__.json | 5 + plugins/cookieManager/__init__.py | 17 ++ plugins/cookieManager/models/__init__.py | 43 ++++ plugins/cookieManager/schemas/__init__.py | 13 ++ .../templates/system/cookie_site/add.html | 125 ++++++++++ .../templates/system/cookie_site/edit.html | 128 ++++++++++ .../templates/system/cookie_site/main.html | 163 +++++++++++++ .../templates/system/cookie_user/add.html | 118 ++++++++++ .../templates/system/cookie_user/edit.html | 120 ++++++++++ .../templates/system/cookie_user/main.html | 158 +++++++++++++ plugins/cookieManager/view/cookie.py | 220 ++++++++++++++++++ plugins/cookieManager/view/cookie_site.py | 160 +++++++++++++ plugins/cookieManager/view/cookie_user.py | 159 +++++++++++++ 19 files changed, 1648 insertions(+) create mode 100644 applications/models/admin_cookie.py create mode 100644 applications/schemas/admin_cookie.py create mode 100644 migrations/versions/1230ff234df9_add_cookie_user_and_cookie_site_tables.py create mode 100644 migrations/versions/9ae98ba6025b_add_cookie_manager_table.py create mode 100644 plugins/cookieManager/__init__.json create mode 100644 plugins/cookieManager/__init__.py create mode 100644 plugins/cookieManager/models/__init__.py create mode 100644 plugins/cookieManager/schemas/__init__.py create mode 100644 plugins/cookieManager/templates/system/cookie_site/add.html create mode 100644 plugins/cookieManager/templates/system/cookie_site/edit.html create mode 100644 plugins/cookieManager/templates/system/cookie_site/main.html create mode 100644 plugins/cookieManager/templates/system/cookie_user/add.html create mode 100644 plugins/cookieManager/templates/system/cookie_user/edit.html create mode 100644 plugins/cookieManager/templates/system/cookie_user/main.html create mode 100644 plugins/cookieManager/view/cookie.py create mode 100644 plugins/cookieManager/view/cookie_site.py create mode 100644 plugins/cookieManager/view/cookie_user.py diff --git a/applications/models/__init__.py b/applications/models/__init__.py index 669d734..2f44513 100644 --- a/applications/models/__init__.py +++ b/applications/models/__init__.py @@ -14,3 +14,4 @@ from .admin_about import About from .admin_friend import Friend from .admin_stat import VisitLog, PageStat from .admin_nav_click import NavClick +from .admin_cookie import CookieUser, CookieSite diff --git a/applications/models/admin_cookie.py b/applications/models/admin_cookie.py new file mode 100644 index 0000000..95276a1 --- /dev/null +++ b/applications/models/admin_cookie.py @@ -0,0 +1,73 @@ +"""Cookie管理数据模型""" +import datetime +from applications.extensions import db + + +class CookieUser(db.Model): + """登录用户 - 保存已登录用户的Cookie信息""" + __tablename__ = 'admin_cookie_user' + + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + username = db.Column(db.String(100), nullable=False, comment='用户名') + nickname = db.Column(db.String(100), default='', comment='昵称') + website_url = db.Column(db.String(255), nullable=False, comment='网站URL') + website_name = db.Column(db.String(100), default='', comment='网站名称') + cookie_value = db.Column(db.Text, nullable=False, comment='Cookie值') + domain = db.Column(db.String(255), default='', comment='Cookie域名') + expiry = db.Column(db.DateTime, comment='过期时间') + enable = db.Column(db.Integer, default=1, comment='状态(1启用,0禁用)') + create_by = db.Column(db.String(50), default='admin', comment='创建者') + create_at = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间') + update_at = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='更新时间') + + def to_dict(self): + return { + 'id': self.id, + 'username': self.username, + 'nickname': self.nickname, + 'website_url': self.website_url, + 'website_name': self.website_name, + 'cookie_value': self.cookie_value, + 'domain': self.domain, + 'expiry': self.expiry.strftime('%Y-%m-%d %H:%M:%S') if self.expiry else '', + 'enable': self.enable, + 'create_by': self.create_by, + 'create_at': self.create_at.strftime('%Y-%m-%d %H:%M:%S') if self.create_at else '', + 'update_at': self.update_at.strftime('%Y-%m-%d %H:%M:%S') if self.update_at else '', + } + + +class CookieSite(db.Model): + """登录网站 - 保存网站的Cookie信息""" + __tablename__ = 'admin_cookie_site' + + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name = db.Column(db.String(100), nullable=False, comment='网站名称') + url = db.Column(db.String(255), nullable=False, comment='网站URL') + cookie_value = db.Column(db.Text, nullable=False, comment='Cookie值') + domain = db.Column(db.String(255), default='', comment='Cookie域名') + path = db.Column(db.String(255), default='/', comment='Cookie路径') + expiry = db.Column(db.DateTime, comment='过期时间') + secure = db.Column(db.Integer, default=0, comment='是否安全') + http_only = db.Column(db.Integer, default=0, comment='是否HTTPOnly') + enable = db.Column(db.Integer, default=1, comment='状态(1启用,0禁用)') + create_by = db.Column(db.String(50), default='admin', comment='创建者') + create_at = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间') + update_at = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='更新时间') + + def to_dict(self): + return { + 'id': self.id, + 'name': self.name, + 'url': self.url, + 'cookie_value': self.cookie_value, + 'domain': self.domain, + 'path': self.path, + 'expiry': self.expiry.strftime('%Y-%m-%d %H:%M:%S') if self.expiry else '', + 'secure': self.secure, + 'http_only': self.http_only, + 'enable': self.enable, + 'create_by': self.create_by, + 'create_at': self.create_at.strftime('%Y-%m-%d %H:%M:%S') if self.create_at else '', + 'update_at': self.update_at.strftime('%Y-%m-%d %H:%M:%S') if self.update_at else '', + } diff --git a/applications/schemas/__init__.py b/applications/schemas/__init__.py index f5abec3..6eaea9a 100644 --- a/applications/schemas/__init__.py +++ b/applications/schemas/__init__.py @@ -9,3 +9,4 @@ from .admin_mail import MailOutSchema from .admin_nav import NavOutSchema, NavManageSchema from .admin_nav_category import NavCategorySchema from .admin_friend import FriendOutSchema, FriendManageSchema +from .admin_cookie import CookieUserManageSchema, CookieSiteManageSchema diff --git a/applications/schemas/admin_cookie.py b/applications/schemas/admin_cookie.py new file mode 100644 index 0000000..f4237f9 --- /dev/null +++ b/applications/schemas/admin_cookie.py @@ -0,0 +1,21 @@ +"""Cookie管理Schema""" +from flask_marshmallow.sqla import SQLAlchemyAutoSchema + +from applications.extensions import ma +from applications.models import CookieUser, CookieSite + + +class CookieUserManageSchema(SQLAlchemyAutoSchema): + """登录用户管理用:序列化为表格数据 / 表单回填""" + class Meta: + model = CookieUser + include_fk = True + load_instance = True + + +class CookieSiteManageSchema(SQLAlchemyAutoSchema): + """登录网站管理用:序列化为表格数据 / 表单回填""" + class Meta: + model = CookieSite + include_fk = True + load_instance = True diff --git a/migrations/versions/1230ff234df9_add_cookie_user_and_cookie_site_tables.py b/migrations/versions/1230ff234df9_add_cookie_user_and_cookie_site_tables.py new file mode 100644 index 0000000..2a97892 --- /dev/null +++ b/migrations/versions/1230ff234df9_add_cookie_user_and_cookie_site_tables.py @@ -0,0 +1,78 @@ +"""add cookie_user and cookie_site tables + +Revision ID: 1230ff234df9 +Revises: 9ae98ba6025b +Create Date: 2026-09-08 16:51:22.296613 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '1230ff234df9' +down_revision = '9ae98ba6025b' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('admin_cookie_site', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(length=100), nullable=False, comment='网站名称'), + sa.Column('url', sa.String(length=255), nullable=False, comment='网站URL'), + sa.Column('cookie_value', sa.Text(), nullable=False, comment='Cookie值'), + sa.Column('domain', sa.String(length=255), nullable=True, comment='Cookie域名'), + sa.Column('path', sa.String(length=255), nullable=True, comment='Cookie路径'), + sa.Column('expiry', sa.DateTime(), nullable=True, comment='过期时间'), + sa.Column('secure', sa.Integer(), nullable=True, comment='是否安全'), + sa.Column('http_only', sa.Integer(), nullable=True, comment='是否HTTPOnly'), + sa.Column('enable', sa.Integer(), nullable=True, comment='状态(1启用,0禁用)'), + sa.Column('create_by', sa.String(length=50), nullable=True, comment='创建者'), + sa.Column('create_at', sa.DateTime(), nullable=True, comment='创建时间'), + sa.Column('update_at', sa.DateTime(), nullable=True, comment='更新时间'), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('admin_cookie_user', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('username', sa.String(length=100), nullable=False, comment='用户名'), + sa.Column('nickname', sa.String(length=100), nullable=True, comment='昵称'), + sa.Column('website_url', sa.String(length=255), nullable=False, comment='网站URL'), + sa.Column('website_name', sa.String(length=100), nullable=True, comment='网站名称'), + sa.Column('cookie_value', sa.Text(), nullable=False, comment='Cookie值'), + sa.Column('domain', sa.String(length=255), nullable=True, comment='Cookie域名'), + sa.Column('expiry', sa.DateTime(), nullable=True, comment='过期时间'), + sa.Column('enable', sa.Integer(), nullable=True, comment='状态(1启用,0禁用)'), + sa.Column('create_by', sa.String(length=50), nullable=True, comment='创建者'), + sa.Column('create_at', sa.DateTime(), nullable=True, comment='创建时间'), + sa.Column('update_at', sa.DateTime(), nullable=True, comment='更新时间'), + sa.PrimaryKeyConstraint('id') + ) + op.drop_table('admin_cookie_manager') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('admin_cookie_manager', + sa.Column('id', sa.INTEGER(), nullable=False), + sa.Column('website_id', sa.INTEGER(), nullable=False), + sa.Column('website_name', sa.VARCHAR(length=100), nullable=True), + sa.Column('website_url', sa.VARCHAR(length=255), nullable=True), + sa.Column('name', sa.VARCHAR(length=100), nullable=False), + sa.Column('value', sa.TEXT(), nullable=False), + sa.Column('domain', sa.VARCHAR(length=255), nullable=True), + sa.Column('path', sa.VARCHAR(length=255), nullable=True), + sa.Column('expiry', sa.DATETIME(), nullable=True), + sa.Column('secure', sa.INTEGER(), nullable=True), + sa.Column('http_only', sa.INTEGER(), nullable=True), + sa.Column('enable', sa.INTEGER(), nullable=True), + sa.Column('create_by', sa.VARCHAR(length=50), nullable=True), + sa.Column('create_at', sa.DATETIME(), nullable=True), + sa.Column('update_at', sa.DATETIME(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.drop_table('admin_cookie_user') + op.drop_table('admin_cookie_site') + # ### end Alembic commands ### diff --git a/migrations/versions/9ae98ba6025b_add_cookie_manager_table.py b/migrations/versions/9ae98ba6025b_add_cookie_manager_table.py new file mode 100644 index 0000000..7487af2 --- /dev/null +++ b/migrations/versions/9ae98ba6025b_add_cookie_manager_table.py @@ -0,0 +1,45 @@ +"""add cookie_manager table + +Revision ID: 9ae98ba6025b +Revises: a47a5d2a3f1b +Create Date: 2026-09-08 15:23:56.125419 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '9ae98ba6025b' +down_revision = 'a47a5d2a3f1b' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('admin_cookie_manager', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='主键ID'), + sa.Column('website_id', sa.Integer(), nullable=False, comment='网站ID'), + sa.Column('website_name', sa.String(length=100), nullable=True, comment='网站名称'), + sa.Column('website_url', sa.String(length=255), nullable=True, comment='网站URL'), + sa.Column('name', sa.String(length=100), nullable=False, comment='Cookie名称'), + sa.Column('value', sa.Text(), nullable=False, comment='Cookie值'), + sa.Column('domain', sa.String(length=255), nullable=True, comment='Cookie域名'), + sa.Column('path', sa.String(length=255), nullable=True, comment='Cookie路径'), + sa.Column('expiry', sa.DateTime(), nullable=True, comment='过期时间'), + sa.Column('secure', sa.Integer(), nullable=True, comment='是否安全'), + sa.Column('http_only', sa.Integer(), nullable=True, comment='是否HTTPOnly'), + sa.Column('enable', sa.Integer(), nullable=True, comment='状态(1启用,0禁用)'), + sa.Column('create_by', sa.String(length=50), nullable=True, comment='创建者'), + sa.Column('create_at', sa.DateTime(), nullable=True, comment='创建时间'), + sa.Column('update_at', sa.DateTime(), nullable=True, comment='更新时间'), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('admin_cookie_manager') + # ### end Alembic commands ### diff --git a/plugins/cookieManager/__init__.json b/plugins/cookieManager/__init__.json new file mode 100644 index 0000000..61c8595 --- /dev/null +++ b/plugins/cookieManager/__init__.json @@ -0,0 +1,5 @@ +{ + "plugin_name": "Cookie管理", + "plugin_version": "1.0.0", + "plugin_description": "后台Cookie管理模块。管理网站的Cookie信息,支持增删改查、启用/禁用、按网站分组查看。" +} diff --git a/plugins/cookieManager/__init__.py b/plugins/cookieManager/__init__.py new file mode 100644 index 0000000..0b8474e --- /dev/null +++ b/plugins/cookieManager/__init__.py @@ -0,0 +1,17 @@ +""" +Cookie管理插件入口 + +- event_init:在 app 上注册以下蓝图 + - /system/cookie-user/* 登录用户管理 + - /system/cookie-site/* 登录网站管理 +""" +from flask import Flask + +from .view.cookie_user import bp as cookie_user_bp +from .view.cookie_site import bp as cookie_site_bp + + +def event_init(app: Flask): + app.register_blueprint(cookie_user_bp) + app.register_blueprint(cookie_site_bp) + print(" * cookieManager: registered /system/cookie-user/* and /system/cookie-site/* blueprints") diff --git a/plugins/cookieManager/models/__init__.py b/plugins/cookieManager/models/__init__.py new file mode 100644 index 0000000..41ea5be --- /dev/null +++ b/plugins/cookieManager/models/__init__.py @@ -0,0 +1,43 @@ +"""Cookie管理数据模型""" +import datetime +from applications.extensions import db + + +class CookieManager(db.Model): + """Cookie管理表""" + __tablename__ = 'admin_cookie_manager' + + id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='主键ID') + website_id = db.Column(db.Integer, nullable=False, comment='网站ID') + website_name = db.Column(db.String(100), default='', comment='网站名称') + website_url = db.Column(db.String(255), default='', comment='网站URL') + name = db.Column(db.String(100), nullable=False, comment='Cookie名称') + value = db.Column(db.Text, nullable=False, comment='Cookie值') + domain = db.Column(db.String(255), default='', comment='Cookie域名') + path = db.Column(db.String(255), default='/', comment='Cookie路径') + expiry = db.Column(db.DateTime, comment='过期时间') + secure = db.Column(db.Integer, default=0, comment='是否安全') + http_only = db.Column(db.Integer, default=0, comment='是否HTTPOnly') + enable = db.Column(db.Integer, default=1, comment='状态(1启用,0禁用)') + create_by = db.Column(db.String(50), default='admin', comment='创建者') + create_at = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间') + update_at = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='更新时间') + + def to_dict(self): + return { + 'id': self.id, + 'website_id': self.website_id, + 'website_name': self.website_name, + 'website_url': self.website_url, + 'name': self.name, + 'value': self.value, + 'domain': self.domain, + 'path': self.path, + 'expiry': self.expiry.strftime('%Y-%m-%d %H:%M:%S') if self.expiry else '', + 'secure': self.secure, + 'http_only': self.http_only, + 'enable': self.enable, + 'create_by': self.create_by, + 'create_at': self.create_at.strftime('%Y-%m-%d %H:%M:%S') if self.create_at else '', + 'update_at': self.update_at.strftime('%Y-%m-%d %H:%M:%S') if self.update_at else '', + } diff --git a/plugins/cookieManager/schemas/__init__.py b/plugins/cookieManager/schemas/__init__.py new file mode 100644 index 0000000..08829ce --- /dev/null +++ b/plugins/cookieManager/schemas/__init__.py @@ -0,0 +1,13 @@ +"""Cookie管理Schema""" +from marshmallow_sqlalchemy import SQLAlchemyAutoSchema + +from applications.extensions import db +from plugins.cookieManager.models import CookieManager + + +class CookieManageSchema(SQLAlchemyAutoSchema): + """后台管理用:序列化为表格数据 / 表单回填""" + class Meta: + model = CookieManager + include_fk = True + load_instance = True diff --git a/plugins/cookieManager/templates/system/cookie_site/add.html b/plugins/cookieManager/templates/system/cookie_site/add.html new file mode 100644 index 0000000..720e781 --- /dev/null +++ b/plugins/cookieManager/templates/system/cookie_site/add.html @@ -0,0 +1,125 @@ + + + + + 新增登录网站 + {% include 'system/common/header.html' %} + + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+ + + + diff --git a/plugins/cookieManager/templates/system/cookie_site/edit.html b/plugins/cookieManager/templates/system/cookie_site/edit.html new file mode 100644 index 0000000..a2137b8 --- /dev/null +++ b/plugins/cookieManager/templates/system/cookie_site/edit.html @@ -0,0 +1,128 @@ + + + + + 编辑登录网站 + {% include 'system/common/header.html' %} + + +
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+ + + + diff --git a/plugins/cookieManager/templates/system/cookie_site/main.html b/plugins/cookieManager/templates/system/cookie_site/main.html new file mode 100644 index 0000000..aa1e01b --- /dev/null +++ b/plugins/cookieManager/templates/system/cookie_site/main.html @@ -0,0 +1,163 @@ + + + + + 登录网站 + {% include 'system/common/header.html' %} + + +
+
+
+
+ +
+ +
+ + + +
+
+
+
+ +
+
+ +
+
+ +{% include 'system/common/footer.html' %} +{% raw %} + + + + + +{% endraw %} + + + + diff --git a/plugins/cookieManager/templates/system/cookie_user/add.html b/plugins/cookieManager/templates/system/cookie_user/add.html new file mode 100644 index 0000000..479b6ce --- /dev/null +++ b/plugins/cookieManager/templates/system/cookie_user/add.html @@ -0,0 +1,118 @@ + + + + + 新增登录用户 + {% include 'system/common/header.html' %} + + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+ + + + diff --git a/plugins/cookieManager/templates/system/cookie_user/edit.html b/plugins/cookieManager/templates/system/cookie_user/edit.html new file mode 100644 index 0000000..6378684 --- /dev/null +++ b/plugins/cookieManager/templates/system/cookie_user/edit.html @@ -0,0 +1,120 @@ + + + + + 编辑登录用户 + {% include 'system/common/header.html' %} + + +
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+ + + + diff --git a/plugins/cookieManager/templates/system/cookie_user/main.html b/plugins/cookieManager/templates/system/cookie_user/main.html new file mode 100644 index 0000000..4503b37 --- /dev/null +++ b/plugins/cookieManager/templates/system/cookie_user/main.html @@ -0,0 +1,158 @@ + + + + + 登录用户 + {% include 'system/common/header.html' %} + + +
+
+
+
+ +
+ +
+ + + +
+
+
+
+ +
+
+ +
+
+ +{% include 'system/common/footer.html' %} +{% raw %} + + + + + +{% endraw %} + + + + diff --git a/plugins/cookieManager/view/cookie.py b/plugins/cookieManager/view/cookie.py new file mode 100644 index 0000000..0f13684 --- /dev/null +++ b/plugins/cookieManager/view/cookie.py @@ -0,0 +1,220 @@ +""" +Cookie管理视图 — 插件版 + +URL 前缀:/system/cookie +模型和Schema从插件内部导入,避免循环依赖。 +""" +import os +import datetime + +from flask import Blueprint, render_template, request +from flask_login import current_user + +from applications.common import curd +from applications.common.utils.http import table_api, fail_api, success_api +from applications.common.utils.rights import authorize +from applications.common.utils.validate import str_escape +from applications.extensions import db +from applications.extensions.init_limit import limiter + +# 从插件内部导入模型和Schema(避免在applications.models中导入导致循环依赖) +from plugins.cookieManager.models import CookieManager +from plugins.cookieManager.schemas import CookieManageSchema + +dir_path = os.path.dirname(os.path.abspath(__file__)) +bp = Blueprint( + 'cookie_manager', __name__, + url_prefix='/system/cookie', + template_folder=os.path.join(dir_path, '..', 'templates'), +) + + +@bp.get('/') +@authorize("system:cookie:main") +def main(): + return render_template('system/cookie/main.html') + + +@bp.get('/data') +@limiter.limit("60 per minute") +@authorize("system:cookie:main") +def data(): + keyword = str_escape(request.args.get('keyword', type=str)) + website_id = request.args.get('website_id', type=int) + + query = CookieManager.query.filter() + if keyword: + query = query.filter( + db.or_( + CookieManager.name.contains(keyword), + CookieManager.website_name.contains(keyword), + CookieManager.website_url.contains(keyword), + ) + ) + if website_id: + query = query.filter(CookieManager.website_id == website_id) + + items = query.order_by(CookieManager.id.desc()).layui_paginate() + return table_api( + msg="请求成功", + data=curd.model_to_dicts(schema=CookieManageSchema, data=items.items), + count=items.total, + ) + + +@bp.get('/add') +@authorize("system:cookie:add", log=True) +def add(): + return render_template('system/cookie/add.html') + + +@bp.post('/save') +@authorize("system:cookie:add", log=True) +def save(): + req_json = request.get_json(force=True, silent=True) or {} + website_id = int(req_json.get('website_id') or 0) + website_name = str_escape(req_json.get('website_name') or '') + website_url = str_escape(req_json.get('website_url') or '') + name = str_escape(req_json.get('name') or '') + value = req_json.get('value') or '' + domain = str_escape(req_json.get('domain') or '') + path = str_escape(req_json.get('path') or '/') + expiry_str = req_json.get('expiry') or '' + secure = int(req_json.get('secure') or 0) + http_only = int(req_json.get('http_only') or 0) + enable = int(req_json.get('enable') or 1) + + if not all([website_id, name, value]): + return fail_api(msg="网站ID/Cookie名称/值不得为空") + + # 解析过期时间 + expiry = None + if expiry_str: + try: + expiry = datetime.datetime.strptime(expiry_str, '%Y-%m-%d %H:%M:%S') + except ValueError: + try: + expiry = datetime.datetime.fromisoformat(expiry_str) + except ValueError: + pass + + try: + cookie = CookieManager( + website_id=website_id, + website_name=website_name, + website_url=website_url, + name=name, + value=value, + domain=domain, + path=path, + expiry=expiry, + secure=secure, + http_only=http_only, + enable=enable, + create_by=current_user.username if current_user.is_authenticated else 'admin', + ) + db.session.add(cookie) + db.session.commit() + except Exception as e: + db.session.rollback() + return fail_api(msg=f"新增失败:{e}") + return success_api(msg="新增成功") + + +@bp.get('/edit') +@authorize("system:cookie:edit", log=True) +def edit(): + cookie_id = request.args.get('cookieId', type=int) + cookie = curd.get_one_by_id(CookieManager, cookie_id) + if not cookie: + return fail_api(msg="Cookie不存在") + return render_template('system/cookie/edit.html', cookie=cookie) + + +@bp.put('/update') +@authorize("system:cookie:edit", log=True) +def update(): + req_json = request.get_json(force=True, silent=True) or {} + cookie_id = req_json.get('cookieId') + cookie = curd.get_one_by_id(CookieManager, cookie_id) + if not cookie: + return fail_api(msg="Cookie不存在") + + website_id = int(req_json.get('website_id') or cookie.website_id) + website_name = str_escape(req_json.get('website_name') or cookie.website_name) + website_url = str_escape(req_json.get('website_url') or cookie.website_url) + name = str_escape(req_json.get('name') or '') + value = req_json.get('value') or '' + domain = str_escape(req_json.get('domain') or cookie.domain) + path = str_escape(req_json.get('path') or cookie.path) + secure = int(req_json.get('secure') or cookie.secure) + http_only = int(req_json.get('http_only') or cookie.http_only) + enable = int(req_json.get('enable') or cookie.enable) + + if not all([website_id, name, value]): + return fail_api(msg="网站ID/Cookie名称/值不得为空") + + # 解析过期时间 + expiry_str = req_json.get('expiry') or '' + expiry = None + if expiry_str: + try: + expiry = datetime.datetime.strptime(expiry_str, '%Y-%m-%d %H:%M:%S') + except ValueError: + try: + expiry = datetime.datetime.fromisoformat(expiry_str) + except ValueError: + pass + + try: + cookie.website_id = website_id + cookie.website_name = website_name + cookie.website_url = website_url + cookie.name = name + cookie.value = value + cookie.domain = domain + cookie.path = path + cookie.expiry = expiry + cookie.secure = secure + cookie.http_only = http_only + cookie.enable = enable + db.session.commit() + except Exception as e: + db.session.rollback() + return fail_api(msg=f"更新失败:{e}") + return success_api(msg="更新成功") + + +@bp.delete('/remove/') +@authorize("system:cookie:remove", log=True) +def remove(cookie_id): + res = curd.delete_one_by_id(CookieManager, cookie_id) + if not res: + return fail_api(msg="删除失败") + return success_api(msg="删除成功") + + +@bp.put('/enable') +@authorize("system:cookie:edit", log=True) +def enable(): + req_json = request.get_json(force=True, silent=True) or {} + cookie_id = req_json.get('cookieId') + if not cookie_id: + return fail_api(msg="数据错误") + res = curd.enable_status(CookieManager, cookie_id) + if not res: + return fail_api(msg="操作失败") + return success_api(msg="已启用") + + +@bp.put('/disable') +@authorize("system:cookie:edit", log=True) +def dis_enable(): + req_json = request.get_json(force=True, silent=True) or {} + cookie_id = req_json.get('cookieId') + if not cookie_id: + return fail_api(msg="数据错误") + res = curd.disable_status(CookieManager, cookie_id) + if not res: + return fail_api(msg="操作失败") + return success_api(msg="已禁用") diff --git a/plugins/cookieManager/view/cookie_site.py b/plugins/cookieManager/view/cookie_site.py new file mode 100644 index 0000000..923238a --- /dev/null +++ b/plugins/cookieManager/view/cookie_site.py @@ -0,0 +1,160 @@ +""" +Cookie管理 - 登录网站视图 + +URL: /system/cookie-site +""" +import os +from flask import Blueprint, render_template, request +from flask_login import current_user + +from applications.common import curd +from applications.common.utils.http import table_api, fail_api, success_api +from applications.common.utils.rights import authorize +from applications.common.utils.validate import str_escape +from applications.extensions import db +from applications.extensions.init_limit import limiter +from applications.models import CookieSite +from applications.schemas import CookieSiteManageSchema + +dir_path = os.path.dirname(os.path.abspath(__file__)) +bp = Blueprint('cookie_site', __name__, + url_prefix='/system/cookie-site', + template_folder=os.path.join(dir_path, '..', 'templates')) + + +@bp.get('/') +@authorize("system:cookie-site:main") +def main(): + return render_template('system/cookie_site/main.html') + + +@bp.get('/data') +@limiter.limit("60 per minute") +@authorize("system:cookie-site:main") +def data(): + keyword = str_escape(request.args.get('keyword', type=str)) + query = CookieSite.query.filter() + if keyword: + query = query.filter( + db.or_( + CookieSite.name.contains(keyword), + CookieSite.url.contains(keyword), + ) + ) + items = query.order_by(CookieSite.id.desc()).layui_paginate() + return table_api( + msg="请求成功", + data=curd.model_to_dicts(schema=CookieSiteManageSchema, data=items.items), + count=items.total, + ) + + +@bp.get('/add') +@authorize("system:cookie-site:add", log=True) +def add(): + return render_template('system/cookie_site/add.html') + + +@bp.post('/save') +@authorize("system:cookie-site:add", log=True) +def save(): + req_json = request.get_json(force=True, silent=True) or {} + name = str_escape(req_json.get('name')) + url = str_escape(req_json.get('url')) + cookie_value = str_escape(req_json.get('cookie_value')) + if not all([name, url, cookie_value]): + return fail_api(msg="名称/网址/Cookie值不得为空") + try: + obj = CookieSite( + name=name, + url=url, + cookie_value=cookie_value, + domain=str_escape(req_json.get('domain')), + path=str_escape(req_json.get('path')) or '/', + expiry=req_json.get('expiry'), + secure=int(req_json.get('secure') or 0), + http_only=int(req_json.get('http_only') or 0), + enable=int(req_json.get('enable') or 1), + create_by=current_user.username if current_user.is_authenticated else 'admin', + ) + db.session.add(obj) + db.session.commit() + except Exception as e: + db.session.rollback() + return fail_api(msg=f"新增失败:{e}") + return success_api(msg="新增成功") + + +@bp.get('/edit') +@authorize("system:cookie-site:edit", log=True) +def edit(): + sid = request.args.get('cookieSiteId', type=int) + obj = curd.get_one_by_id(CookieSite, sid) + if not obj: + return fail_api(msg="记录不存在") + return render_template('system/cookie_site/edit.html', obj=obj) + + +@bp.put('/update') +@authorize("system:cookie-site:edit", log=True) +def update(): + req_json = request.get_json(force=True, silent=True) or {} + sid = req_json.get('cookieSiteId') + obj = curd.get_one_by_id(CookieSite, sid) + if not obj: + return fail_api(msg="记录不存在") + name = str_escape(req_json.get('name')) + url = str_escape(req_json.get('url')) + cookie_value = str_escape(req_json.get('cookie_value')) + if not all([name, url, cookie_value]): + return fail_api(msg="名称/网址/Cookie值不得为空") + try: + obj.name = name + obj.url = url + obj.cookie_value = cookie_value + obj.domain = str_escape(req_json.get('domain')) + obj.path = str_escape(req_json.get('path')) or '/' + obj.expiry = req_json.get('expiry') + obj.secure = int(req_json.get('secure') or 0) + obj.http_only = int(req_json.get('http_only') or 0) + obj.enable = int(req_json.get('enable') or 1) + db.session.commit() + except Exception as e: + db.session.rollback() + return fail_api(msg=f"更新失败:{e}") + return success_api(msg="更新成功") + + +@bp.delete('/remove/') +@authorize("system:cookie-site:remove", log=True) +def remove(sid): + res = curd.delete_one_by_id(CookieSite, sid) + if not res: + return fail_api(msg="删除失败") + return success_api(msg="删除成功") + + +@bp.put('/enable') +@authorize("system:cookie-site:edit", log=True) +def enable(): + req_json = request.get_json(force=True, silent=True) or {} + sid = req_json.get('cookieSiteId') + if not sid: + return fail_api(msg="数据错误") + res = curd.enable_status(CookieSite, sid) + if not res: + return fail_api(msg="操作失败") + return success_api(msg="已启用") + + +@bp.put('/disable') +@authorize("system:cookie-site:edit", log=True) +def disable(): + req_json = request.get_json(force=True, silent=True) or {} + sid = req_json.get('cookieSiteId') + if not sid: + return fail_api(msg="数据错误") + res = curd.disable_status(CookieSite, sid) + if not res: + return fail_api(msg="操作失败") + return success_api(msg="已禁用") diff --git a/plugins/cookieManager/view/cookie_user.py b/plugins/cookieManager/view/cookie_user.py new file mode 100644 index 0000000..e611b42 --- /dev/null +++ b/plugins/cookieManager/view/cookie_user.py @@ -0,0 +1,159 @@ +""" +Cookie管理 - 登录用户视图 + +URL: /system/cookie-user +""" +import os +from flask import Blueprint, render_template, request +from flask_login import current_user + +from applications.common import curd +from applications.common.utils.http import table_api, fail_api, success_api +from applications.common.utils.rights import authorize +from applications.common.utils.validate import str_escape +from applications.extensions import db +from applications.extensions.init_limit import limiter +from applications.models import CookieUser +from applications.schemas import CookieUserManageSchema + +dir_path = os.path.dirname(os.path.abspath(__file__)) +bp = Blueprint('cookie_user', __name__, + url_prefix='/system/cookie-user', + template_folder=os.path.join(dir_path, '..', 'templates')) + + +@bp.get('/') +@authorize("system:cookie-user:main") +def main(): + return render_template('system/cookie_user/main.html') + + +@bp.get('/data') +@limiter.limit("60 per minute") +@authorize("system:cookie-user:main") +def data(): + keyword = str_escape(request.args.get('keyword', type=str)) + query = CookieUser.query.filter() + if keyword: + query = query.filter( + db.or_( + CookieUser.username.contains(keyword), + CookieUser.website_name.contains(keyword), + CookieUser.website_url.contains(keyword), + ) + ) + items = query.order_by(CookieUser.id.desc()).layui_paginate() + return table_api( + msg="请求成功", + data=curd.model_to_dicts(schema=CookieUserManageSchema, data=items.items), + count=items.total, + ) + + +@bp.get('/add') +@authorize("system:cookie-user:add", log=True) +def add(): + return render_template('system/cookie_user/add.html') + + +@bp.post('/save') +@authorize("system:cookie-user:add", log=True) +def save(): + req_json = request.get_json(force=True, silent=True) or {} + username = str_escape(req_json.get('username')) + website_url = str_escape(req_json.get('website_url')) + cookie_value = str_escape(req_json.get('cookie_value')) + if not all([username, website_url, cookie_value]): + return fail_api(msg="用户名/网站URL/Cookie值不得为空") + try: + obj = CookieUser( + username=username, + nickname=str_escape(req_json.get('nickname')), + website_url=website_url, + website_name=str_escape(req_json.get('website_name')), + cookie_value=cookie_value, + domain=str_escape(req_json.get('domain')), + expiry=req_json.get('expiry'), + enable=int(req_json.get('enable') or 1), + create_by=current_user.username if current_user.is_authenticated else 'admin', + ) + db.session.add(obj) + db.session.commit() + except Exception as e: + db.session.rollback() + return fail_api(msg=f"新增失败:{e}") + return success_api(msg="新增成功") + + +@bp.get('/edit') +@authorize("system:cookie-user:edit", log=True) +def edit(): + cid = request.args.get('cookieUserId', type=int) + obj = curd.get_one_by_id(CookieUser, cid) + if not obj: + return fail_api(msg="记录不存在") + return render_template('system/cookie_user/edit.html', obj=obj) + + +@bp.put('/update') +@authorize("system:cookie-user:edit", log=True) +def update(): + req_json = request.get_json(force=True, silent=True) or {} + cid = req_json.get('cookieUserId') + obj = curd.get_one_by_id(CookieUser, cid) + if not obj: + return fail_api(msg="记录不存在") + username = str_escape(req_json.get('username')) + website_url = str_escape(req_json.get('website_url')) + cookie_value = str_escape(req_json.get('cookie_value')) + if not all([username, website_url, cookie_value]): + return fail_api(msg="用户名/网站URL/Cookie值不得为空") + try: + obj.username = username + obj.nickname = str_escape(req_json.get('nickname')) + obj.website_url = website_url + obj.website_name = str_escape(req_json.get('website_name')) + obj.cookie_value = cookie_value + obj.domain = str_escape(req_json.get('domain')) + obj.expiry = req_json.get('expiry') + obj.enable = int(req_json.get('enable') or 1) + db.session.commit() + except Exception as e: + db.session.rollback() + return fail_api(msg=f"更新失败:{e}") + return success_api(msg="更新成功") + + +@bp.delete('/remove/') +@authorize("system:cookie-user:remove", log=True) +def remove(cid): + res = curd.delete_one_by_id(CookieUser, cid) + if not res: + return fail_api(msg="删除失败") + return success_api(msg="删除成功") + + +@bp.put('/enable') +@authorize("system:cookie-user:edit", log=True) +def enable(): + req_json = request.get_json(force=True, silent=True) or {} + cid = req_json.get('cookieUserId') + if not cid: + return fail_api(msg="数据错误") + res = curd.enable_status(CookieUser, cid) + if not res: + return fail_api(msg="操作失败") + return success_api(msg="已启用") + + +@bp.put('/disable') +@authorize("system:cookie-user:edit", log=True) +def disable(): + req_json = request.get_json(force=True, silent=True) or {} + cid = req_json.get('cookieUserId') + if not cid: + return fail_api(msg="数据错误") + res = curd.disable_status(CookieUser, cid) + if not res: + return fail_api(msg="操作失败") + return success_api(msg="已禁用")