feat(plugins): Cookie 管理插件(账号/站点 + 刷新记录)

以插件方式新增 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/*
This commit is contained in:
bwstudio
2026-09-09 19:17:41 +08:00
parent 4f3f26e0ed
commit 3e8c490851
19 changed files with 1648 additions and 0 deletions
+1
View File
@@ -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
+73
View File
@@ -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 '',
}
+1
View File
@@ -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
+21
View File
@@ -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
@@ -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 ###
@@ -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 ###
+5
View File
@@ -0,0 +1,5 @@
{
"plugin_name": "Cookie管理",
"plugin_version": "1.0.0",
"plugin_description": "后台Cookie管理模块。管理网站的Cookie信息,支持增删改查、启用/禁用、按网站分组查看。"
}
+17
View File
@@ -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")
+43
View File
@@ -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 '',
}
+13
View File
@@ -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
@@ -0,0 +1,125 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>新增登录网站</title>
{% include 'system/common/header.html' %}
</head>
<body>
<div class="layui-form" lay-filter="cookie-site-form" style="padding: 20px 30px 0 0;">
<div class="layui-form-item">
<label class="layui-form-label">网站名称</label>
<div class="layui-input-block">
<input type="text" name="name" required lay-verify="required" placeholder="网站显示名称"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站URL</label>
<div class="layui-input-block">
<input type="text" name="url" required lay-verify="required|url" placeholder="https://example.com"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Cookie值</label>
<div class="layui-input-block">
<textarea name="cookie_value" required lay-verify="required"
style="width:100%;height:100px;resize:none;" class="layui-textarea" placeholder="Cookie内容"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">域名</label>
<div class="layui-input-block">
<input type="text" name="domain" placeholder="例如:.example.com(可留空)"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">路径</label>
<div class="layui-input-block">
<input type="text" name="path" value="/" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">过期时间</label>
<div class="layui-input-block">
<input type="text" name="expiry" placeholder="YYYY-MM-DD HH:MM:SS(可留空)"
autocomplete="off" class="layui-input" id="expiry-picker">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Secure</label>
<div class="layui-input-block">
<input type="radio" name="secure" value="1" title="是">
<input type="radio" name="secure" value="0" title="否" checked>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">HTTPOnly</label>
<div class="layui-input-block">
<input type="radio" name="http_only" value="1" title="是" checked>
<input type="radio" name="http_only" value="0" title="否">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="enable" value="1" title="启用" checked>
<input type="radio" name="enable" value="0" title="禁用">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="button" class="layui-btn" lay-submit lay-filter="cookie-site-form-submit">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</div>
<script>
layui.use(['form', 'layer', 'laydate'], function(){
var form = layui.form;
var layer = layui.layer;
var laydate = layui.laydate;
var $ = layui.$;
laydate.render({ elem: '#expiry-picker', trigger: 'click' });
form.render();
form.on('submit(cookie-site-form-submit)', function(){
var data = form.val('cookie-site-form');
var submitBtn = $('button[lay-filter="cookie-site-form-submit"]');
submitBtn.prop('disabled', true).addClass('layui-btn-disabled');
$.ajax({
url: '/system/cookie-site/save',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
name: data.name,
url: data.url,
cookie_value: data.cookie_value,
domain: data.domain,
path: data.path,
expiry: data.expiry,
secure: data.secure,
http_only: data.http_only,
enable: data.enable
}),
success: function(res){
layer.msg(res.msg || (res.code === 0 ? '保存成功' : '保存失败'));
if (res.code === 0 || res.success) {
setTimeout(function(){ parent.layer.close(parent.layer.getFrameIndex(window.name)); }, 600);
}
},
error: function(){ layer.msg('请求失败'); },
complete: function(){
submitBtn.prop('disabled', false).removeClass('layui-btn-disabled');
}
});
return false;
});
});
</script>
</body>
</html>
@@ -0,0 +1,128 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>编辑登录网站</title>
{% include 'system/common/header.html' %}
</head>
<body>
<div class="layui-form" lay-filter="cookie-site-form" style="padding: 20px 30px 0 0;">
<input type="hidden" name="cookieSiteId" value="{{ obj.id }}">
<div class="layui-form-item">
<label class="layui-form-label">网站名称</label>
<div class="layui-input-block">
<input type="text" name="name" value="{{ obj.name }}" lay-verify="required"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站URL</label>
<div class="layui-input-block">
<input type="text" name="url" value="{{ obj.url }}" lay-verify="required|url"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Cookie值</label>
<div class="layui-input-block">
<textarea name="cookie_value" lay-verify="required"
style="width:100%;height:100px;resize:none;" class="layui-textarea">{{ obj.cookie_value }}</textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">域名</label>
<div class="layui-input-block">
<input type="text" name="domain" value="{{ obj.domain }}"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">路径</label>
<div class="layui-input-block">
<input type="text" name="path" value="{{ obj.path }}"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">过期时间</label>
<div class="layui-input-block">
<input type="text" name="expiry" value="{{ obj.expiry }}"
autocomplete="off" class="layui-input" id="expiry-picker">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Secure</label>
<div class="layui-input-block">
<input type="radio" name="secure" value="1" title="是" {{ 'checked' if obj.secure == 1 }}>
<input type="radio" name="secure" value="0" title="否" {{ 'checked' if obj.secure == 0 }}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">HTTPOnly</label>
<div class="layui-input-block">
<input type="radio" name="http_only" value="1" title="是" {{ 'checked' if obj.http_only == 1 }}>
<input type="radio" name="http_only" value="0" title="否" {{ 'checked' if obj.http_only == 0 }}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="enable" value="1" title="启用" {{ 'checked' if obj.enable == 1 }}>
<input type="radio" name="enable" value="0" title="禁用" {{ 'checked' if obj.enable == 0 }}>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="button" class="layui-btn" lay-submit lay-filter="cookie-site-form-submit">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</div>
<script>
layui.use(['form', 'layer', 'laydate'], function(){
var form = layui.form;
var layer = layui.layer;
var laydate = layui.laydate;
var $ = layui.$;
laydate.render({ elem: '#expiry-picker', trigger: 'click' });
form.render();
form.on('submit(cookie-site-form-submit)', function(){
var data = form.val('cookie-site-form');
var submitBtn = $('button[lay-filter="cookie-site-form-submit"]');
submitBtn.prop('disabled', true).addClass('layui-btn-disabled');
$.ajax({
url: '/system/cookie-site/update',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({
cookieSiteId: data.cookieSiteId,
name: data.name,
url: data.url,
cookie_value: data.cookie_value,
domain: data.domain,
path: data.path,
expiry: data.expiry,
secure: data.secure,
http_only: data.http_only,
enable: data.enable
}),
success: function(res){
layer.msg(res.msg || (res.code === 0 ? '保存成功' : '保存失败'));
if (res.code === 0 || res.success) {
setTimeout(function(){ parent.layer.close(parent.layer.getFrameIndex(window.name)); }, 600);
}
},
error: function(){ layer.msg('请求失败'); },
complete: function(){
submitBtn.prop('disabled', false).removeClass('layui-btn-disabled');
}
});
return false;
});
});
</script>
</body>
</html>
@@ -0,0 +1,163 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>登录网站</title>
{% include 'system/common/header.html' %}
</head>
<body class="pear-container">
<div class="layui-card">
<div class="layui-card-body">
<form class="layui-form" action="" lay-filter="cookie-site-query-form">
<div class="layui-form-item" style="margin-bottom: unset;">
<label class="layui-form-label">关键词</label>
<div class="layui-input-inline">
<input type="text" name="keyword" placeholder="网站名称/链接" class="layui-input">
</div>
<button class="layui-btn layui-btn-md" lay-submit lay-filter="cookie-site-query">
<i class="layui-icon layui-icon-search"></i> 查询
</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-md">
<i class="layui-icon layui-icon-refresh"></i> 重置
</button>
<button type="button" class="layui-btn layui-btn-normal layui-btn-md" id="btn-add">
<i class="layui-icon layui-icon-add-1"></i> 新增登录网站
</button>
</div>
</form>
</div>
</div>
<div class="layui-card">
<div class="layui-card-body">
<table id="cookie-site-table" lay-filter="cookie-site-table"></table>
</div>
</div>
{% include 'system/common/footer.html' %}
{% raw %}
<script type="text/html" id="col-cookie-site-status">
{{# if(d.enable === 1){ }}
<span class="layui-badge layui-bg-green">启用</span>
{{# } else { }}
<span class="layui-badge layui-bg-gray">禁用</span>
{{# } }}
</script>
<script type="text/html" id="col-cookie-site-value">
{{# var v = d.cookie_value || ''; }}
{{# if(v.length > 30){ }}
<span title="{{ v }}">{{ v.slice(0, 30) }}...</span>
{{# } else { }}
<span>{{ v }}</span>
{{# } }}
</script>
<script type="text/html" id="col-cookie-site-op">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
{{# if(d.enable === 1){ }}
<a class="layui-btn layui-btn-xs layui-btn-warm" lay-event="disable">禁用</a>
{{# } else { }}
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="enable">启用</a>
{{# } }}
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="remove">删除</a>
</script>
{% endraw %}
<script>
layui.use(['table', 'form', 'layer'], function(){
var table = layui.table;
var form = layui.form;
var layer = layui.layer;
var $ = layui.$;
var renderTable = function(){
var keyword = $('input[name="keyword"]').val() || '';
table.render({
elem: '#cookie-site-table',
url: '/system/cookie-site/data',
where: { keyword: keyword },
page: true,
limit: 20,
cols: [[
{field: 'id', title: 'ID', width: 60},
{field: 'name', title: '网站名称', width: 150},
{field: 'url', title: '网站URL', minWidth: 200},
{field: 'cookie_value', title: 'Cookie值', minWidth: 200, templet: '#col-cookie-site-value'},
{field: 'domain', title: '域名', width: 150},
{field: 'path', title: '路径', width: 100},
{field: 'expiry', title: '过期时间', width: 160},
{field: 'secure', title: 'Secure', width: 80, templet: function(d){
return d.secure === 1 ? '<span class="layui-badge">是</span>' : '<span class="layui-badge layui-bg-gray">否</span>';
}},
{field: 'http_only', title: 'HTTPOnly', width: 90, templet: function(d){
return d.http_only === 1 ? '<span class="layui-badge">是</span>' : '<span class="layui-badge layui-bg-gray">否</span>';
}},
{field: 'enable', title: '状态', width: 80, templet: '#col-cookie-site-status'},
{field: 'create_at', title: '创建时间', width: 160},
{fixed: 'right', title: '操作', toolbar: '#col-cookie-site-op', width: 200}
]],
skin: 'line',
text: {none: '暂无登录网站'},
});
};
renderTable();
form.on('submit(cookie-site-query)', function(){
renderTable();
return false;
});
$('#btn-add').on('click', function(){
layer.open({
type: 2,
title: '新增登录网站',
area: ['700px', '680px'],
content: '/system/cookie-site/add'
});
});
table.on('tool(cookie-site-table)', function(obj){
var data = obj.data;
if (obj.event === 'edit'){
layer.open({
type: 2,
title: '编辑登录网站',
area: ['700px', '680px'],
content: '/system/cookie-site/edit?cookieSiteId=' + data.id
});
} else if (obj.event === 'remove'){
layer.confirm('确定删除该登录网站吗?', function(idx){
$.ajax({
url: '/system/cookie-site/remove/' + data.id,
type: 'DELETE',
success: function(res){
if (res.code === 0 || res.success) { layer.msg(res.msg); obj.del(); }
else layer.msg(res.msg);
}
});
layer.close(idx);
});
} else if (obj.event === 'enable'){
$.ajax({
url: '/system/cookie-site/enable',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({cookieSiteId: data.id}),
success: function(res){ layer.msg(res.msg); renderTable(); }
});
} else if (obj.event === 'disable'){
$.ajax({
url: '/system/cookie-site/disable',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({cookieSiteId: data.id}),
success: function(res){ layer.msg(res.msg); renderTable(); }
});
}
});
});
</script>
</body>
</html>
@@ -0,0 +1,118 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>新增登录用户</title>
{% include 'system/common/header.html' %}
</head>
<body>
<div class="layui-form" lay-filter="cookie-user-form" style="padding: 20px 30px 0 0;">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" name="username" required lay-verify="required" placeholder="用户名"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">昵称</label>
<div class="layui-input-block">
<input type="text" name="nickname" placeholder="昵称(可留空)"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站名称</label>
<div class="layui-input-block">
<input type="text" name="website_name" required lay-verify="required" placeholder="网站显示名称"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站URL</label>
<div class="layui-input-block">
<input type="text" name="website_url" required lay-verify="required|url" placeholder="https://example.com"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Cookie值</label>
<div class="layui-input-block">
<textarea name="cookie_value" required lay-verify="required"
style="width:100%;height:100px;resize:none;" class="layui-textarea" placeholder="Cookie内容"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">域名</label>
<div class="layui-input-block">
<input type="text" name="domain" placeholder="例如:.example.com(可留空)"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">过期时间</label>
<div class="layui-input-block">
<input type="text" name="expiry" placeholder="YYYY-MM-DD HH:MM:SS(可留空)"
autocomplete="off" class="layui-input" id="expiry-picker">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="enable" value="1" title="启用" checked>
<input type="radio" name="enable" value="0" title="禁用">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="button" class="layui-btn" lay-submit lay-filter="cookie-user-form-submit">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</div>
<script>
layui.use(['form', 'layer', 'laydate'], function(){
var form = layui.form;
var layer = layui.layer;
var laydate = layui.laydate;
var $ = layui.$;
laydate.render({ elem: '#expiry-picker', trigger: 'click' });
form.render();
form.on('submit(cookie-user-form-submit)', function(){
var data = form.val('cookie-user-form');
var submitBtn = $('button[lay-filter="cookie-user-form-submit"]');
submitBtn.prop('disabled', true).addClass('layui-btn-disabled');
$.ajax({
url: '/system/cookie-user/save',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
username: data.username,
nickname: data.nickname,
website_name: data.website_name,
website_url: data.website_url,
cookie_value: data.cookie_value,
domain: data.domain,
expiry: data.expiry,
enable: data.enable
}),
success: function(res){
layer.msg(res.msg || (res.code === 0 ? '保存成功' : '保存失败'));
if (res.code === 0 || res.success) {
setTimeout(function(){ parent.layer.close(parent.layer.getFrameIndex(window.name)); }, 600);
}
},
error: function(){ layer.msg('请求失败'); },
complete: function(){
submitBtn.prop('disabled', false).removeClass('layui-btn-disabled');
}
});
return false;
});
});
</script>
</body>
</html>
@@ -0,0 +1,120 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>编辑登录用户</title>
{% include 'system/common/header.html' %}
</head>
<body>
<div class="layui-form" lay-filter="cookie-user-form" style="padding: 20px 30px 0 0;">
<input type="hidden" name="cookieUserId" value="{{ obj.id }}">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" name="username" value="{{ obj.username }}" lay-verify="required"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">昵称</label>
<div class="layui-input-block">
<input type="text" name="nickname" value="{{ obj.nickname }}"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站名称</label>
<div class="layui-input-block">
<input type="text" name="website_name" value="{{ obj.website_name }}" lay-verify="required"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站URL</label>
<div class="layui-input-block">
<input type="text" name="website_url" value="{{ obj.website_url }}" lay-verify="required|url"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">Cookie值</label>
<div class="layui-input-block">
<textarea name="cookie_value" lay-verify="required"
style="width:100%;height:100px;resize:none;" class="layui-textarea">{{ obj.cookie_value }}</textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">域名</label>
<div class="layui-input-block">
<input type="text" name="domain" value="{{ obj.domain }}"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">过期时间</label>
<div class="layui-input-block">
<input type="text" name="expiry" value="{{ obj.expiry }}"
autocomplete="off" class="layui-input" id="expiry-picker">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="enable" value="1" title="启用" {{ 'checked' if obj.enable == 1 }}>
<input type="radio" name="enable" value="0" title="禁用" {{ 'checked' if obj.enable == 0 }}>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="button" class="layui-btn" lay-submit lay-filter="cookie-user-form-submit">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</div>
<script>
layui.use(['form', 'layer', 'laydate'], function(){
var form = layui.form;
var layer = layui.layer;
var laydate = layui.laydate;
var $ = layui.$;
laydate.render({ elem: '#expiry-picker', trigger: 'click' });
form.render();
form.on('submit(cookie-user-form-submit)', function(){
var data = form.val('cookie-user-form');
var submitBtn = $('button[lay-filter="cookie-user-form-submit"]');
submitBtn.prop('disabled', true).addClass('layui-btn-disabled');
$.ajax({
url: '/system/cookie-user/update',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({
cookieUserId: data.cookieUserId,
username: data.username,
nickname: data.nickname,
website_name: data.website_name,
website_url: data.website_url,
cookie_value: data.cookie_value,
domain: data.domain,
expiry: data.expiry,
enable: data.enable
}),
success: function(res){
layer.msg(res.msg || (res.code === 0 ? '保存成功' : '保存失败'));
if (res.code === 0 || res.success) {
setTimeout(function(){ parent.layer.close(parent.layer.getFrameIndex(window.name)); }, 600);
}
},
error: function(){ layer.msg('请求失败'); },
complete: function(){
submitBtn.prop('disabled', false).removeClass('layui-btn-disabled');
}
});
return false;
});
});
</script>
</body>
</html>
@@ -0,0 +1,158 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>登录用户</title>
{% include 'system/common/header.html' %}
</head>
<body class="pear-container">
<div class="layui-card">
<div class="layui-card-body">
<form class="layui-form" action="" lay-filter="cookie-user-query-form">
<div class="layui-form-item" style="margin-bottom: unset;">
<label class="layui-form-label">关键词</label>
<div class="layui-input-inline">
<input type="text" name="keyword" placeholder="用户名/网站名/链接" class="layui-input">
</div>
<button class="layui-btn layui-btn-md" lay-submit lay-filter="cookie-user-query">
<i class="layui-icon layui-icon-search"></i> 查询
</button>
<button type="reset" class="layui-btn layui-btn-primary layui-btn-md">
<i class="layui-icon layui-icon-refresh"></i> 重置
</button>
<button type="button" class="layui-btn layui-btn-normal layui-btn-md" id="btn-add">
<i class="layui-icon layui-icon-add-1"></i> 新增登录用户
</button>
</div>
</form>
</div>
</div>
<div class="layui-card">
<div class="layui-card-body">
<table id="cookie-user-table" lay-filter="cookie-user-table"></table>
</div>
</div>
{% include 'system/common/footer.html' %}
{% raw %}
<script type="text/html" id="col-cookie-user-status">
{{# if(d.enable === 1){ }}
<span class="layui-badge layui-bg-green">启用</span>
{{# } else { }}
<span class="layui-badge layui-bg-gray">禁用</span>
{{# } }}
</script>
<script type="text/html" id="col-cookie-user-value">
{{# var v = d.cookie_value || ''; }}
{{# if(v.length > 30){ }}
<span title="{{ v }}">{{ v.slice(0, 30) }}...</span>
{{# } else { }}
<span>{{ v }}</span>
{{# } }}
</script>
<script type="text/html" id="col-cookie-user-op">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
{{# if(d.enable === 1){ }}
<a class="layui-btn layui-btn-xs layui-btn-warm" lay-event="disable">禁用</a>
{{# } else { }}
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="enable">启用</a>
{{# } }}
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="remove">删除</a>
</script>
{% endraw %}
<script>
layui.use(['table', 'form', 'layer'], function(){
var table = layui.table;
var form = layui.form;
var layer = layui.layer;
var $ = layui.$;
var renderTable = function(){
var keyword = $('input[name="keyword"]').val() || '';
table.render({
elem: '#cookie-user-table',
url: '/system/cookie-user/data',
where: { keyword: keyword },
page: true,
limit: 20,
cols: [[
{field: 'id', title: 'ID', width: 60},
{field: 'username', title: '用户名', width: 150},
{field: 'nickname', title: '昵称', width: 120},
{field: 'website_name', title: '网站名称', width: 150},
{field: 'website_url', title: '网站链接', minWidth: 200},
{field: 'cookie_value', title: 'Cookie值', minWidth: 200, templet: '#col-cookie-user-value'},
{field: 'domain', title: '域名', width: 150},
{field: 'expiry', title: '过期时间', width: 160},
{field: 'enable', title: '状态', width: 80, templet: '#col-cookie-user-status'},
{field: 'create_at', title: '创建时间', width: 160},
{fixed: 'right', title: '操作', toolbar: '#col-cookie-user-op', width: 200}
]],
skin: 'line',
text: {none: '暂无登录用户'},
});
};
renderTable();
form.on('submit(cookie-user-query)', function(){
renderTable();
return false;
});
$('#btn-add').on('click', function(){
layer.open({
type: 2,
title: '新增登录用户',
area: ['700px', '680px'],
content: '/system/cookie-user/add'
});
});
table.on('tool(cookie-user-table)', function(obj){
var data = obj.data;
if (obj.event === 'edit'){
layer.open({
type: 2,
title: '编辑登录用户',
area: ['700px', '680px'],
content: '/system/cookie-user/edit?cookieUserId=' + data.id
});
} else if (obj.event === 'remove'){
layer.confirm('确定删除该登录用户吗?', function(idx){
$.ajax({
url: '/system/cookie-user/remove/' + data.id,
type: 'DELETE',
success: function(res){
if (res.code === 0 || res.success) { layer.msg(res.msg); obj.del(); }
else layer.msg(res.msg);
}
});
layer.close(idx);
});
} else if (obj.event === 'enable'){
$.ajax({
url: '/system/cookie-user/enable',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({cookieUserId: data.id}),
success: function(res){ layer.msg(res.msg); renderTable(); }
});
} else if (obj.event === 'disable'){
$.ajax({
url: '/system/cookie-user/disable',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({cookieUserId: data.id}),
success: function(res){ layer.msg(res.msg); renderTable(); }
});
}
});
});
</script>
</body>
</html>
+220
View File
@@ -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/<int:cookie_id>')
@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="已禁用")
+160
View File
@@ -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/<int:sid>')
@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="已禁用")
+159
View File
@@ -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/<int:cid>')
@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="已禁用")