53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/router/SwiperRouter.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, request
2 |
3 | from src.model import db
4 | from src.model.SwiperModel import SwiperModel
5 | from src import siwa
6 | from src.siwadoc.SwiperSiwa import SwiperQuery, SwiperBody, SwiperBodyId
7 | from src.utils.jwt import TokenRequired
8 | from src.utils.response import Result
9 |
10 | swiper = Blueprint("swiper", __name__)
11 |
12 |
13 | # 新增轮播图
14 | @swiper.route("/swiper", methods=["POST"])
15 | @siwa.doc(tags=["轮播图管理"], summary="新增轮播图", description="新增轮播图记得把id去掉,否则可能会导致重复id异常",
16 | body=SwiperBody)
17 | @TokenRequired
18 | def add():
19 | swiper = request.json
20 |
21 | data = SwiperModel(**swiper)
22 |
23 | db.session.add(data)
24 | db.session.commit()
25 |
26 | return Result(200, "新增成功")
27 |
28 |
29 | # 删除轮播图
30 | @swiper.route("/swiper/", methods=["DELETE"])
31 | @siwa.doc(tags=["轮播图管理"], summary="删除轮播图", description="通过ID删除指定轮播图")
32 | @TokenRequired
33 | def drop(id):
34 | data = SwiperModel.query.filter_by(id=id).first()
35 |
36 | if not data:
37 | return Result(400, "删除失败:没有此轮播图")
38 |
39 | db.session.delete(data)
40 | db.session.commit()
41 |
42 | return Result(200, "删除轮播图成功")
43 |
44 |
45 | # 批量删除
46 | @swiper.route("/swiper", methods=["DELETE"])
47 | @siwa.doc(tags=["轮播图管理"], summary="批量删除轮播图", description="[1,2,3] 删除ID为1、2、3的数据", body=SwiperBodyId)
48 | @TokenRequired
49 | def dropBatch():
50 | ids = request.json["ids"]
51 |
52 | for id in ids:
53 | data = SwiperModel.query.filter_by(id=id).first()
54 |
55 | if not data:
56 | return Result(400, f"批量删除失败:没有ID:{id}的轮播图")
57 |
58 | db.session.delete(data)
59 |
60 | db.session.commit()
61 |
62 | return Result(200, "批量删除轮播图成功")
63 |
64 |
65 | # 编辑轮播图
66 | @swiper.route("/swiper", methods=["PATCH"])
67 | @siwa.doc(tags=["轮播图管理"], summary="编辑轮播图", body=SwiperBody)
68 | @TokenRequired
69 | def edit():
70 | swiper = request.json
71 |
72 | data = SwiperModel.query.filter_by(id=swiper["id"]).update(swiper)
73 |
74 | if not data:
75 | return Result(400, "编辑失败:没有此轮播图")
76 |
77 | db.session.commit()
78 |
79 | return Result(200, "编辑成功")
80 |
81 |
82 | # 获取轮播图详情
83 | @swiper.route("/swiper/")
84 | @siwa.doc(tags=["轮播图管理"], summary="获取轮播图详情", resp=SwiperBody)
85 | def get(id):
86 | data = SwiperModel.query.filter_by(id=id).first()
87 |
88 | if not data:
89 | return Result(400, "获取失败:没有此轮播图")
90 |
91 | return Result(200, "获取轮播图详情成功", data.to())
92 |
93 |
94 | # 获取轮播图列表
95 | @swiper.route("/swiper")
96 | @siwa.doc(tags=["轮播图管理"], summary="获取轮播图列表", description="不传参数表示从第1页开始 每页查询5条数据",
97 | query=SwiperQuery)
98 | def list():
99 | page = request.args.get("page", 1, type=int)
100 | size = request.args.get("size", 5, type=int)
101 |
102 | # 最新发布的轮播图在最前面排序
103 | paginate = SwiperModel.query.paginate(page=page, per_page=size,
104 | error_out=False)
105 |
106 | data = {
107 | "result": [k.to() for k in paginate],
108 | "page": paginate.page,
109 | "size": paginate.per_page,
110 | "pages": paginate.pages,
111 | "total": paginate.total,
112 | "prev": paginate.has_prev,
113 | "next": paginate.has_next
114 | }
115 |
116 | return Result(200, "获取轮播图列表成功", data)
117 |
--------------------------------------------------------------------------------
/src/router/LinkRouter.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, request
2 |
3 | from src.model import db
4 | from src.model.LinkModel import LinkModel
5 | from src import siwa
6 | from src.model.TypeModel import TypeModel
7 | from src.siwadoc.LinkSiwa import LinkQuery, LinkBody, LinkBodyId
8 | from src.utils.jwt import TokenRequired
9 | from src.utils.response import Result
10 |
11 | link = Blueprint("link", __name__)
12 |
13 |
14 | # 新增网站
15 | @link.route("/link", methods=["POST"])
16 | @siwa.doc(tags=["网站管理"], summary="新增网站", description="新增网站记得把id去掉,否则可能会导致重复id异常",
17 | body=LinkBody)
18 | @TokenRequired
19 | def add():
20 | link = request.json
21 |
22 | data = LinkModel(**link)
23 |
24 | db.session.add(data)
25 | db.session.commit()
26 |
27 | return Result(200, "新增成功")
28 |
29 |
30 | # 删除网站
31 | @link.route("/link/", methods=["DELETE"])
32 | @siwa.doc(tags=["网站管理"], summary="删除网站", description="通过ID删除指定网站")
33 | @TokenRequired
34 | def drop(id):
35 | data = LinkModel.query.filter_by(id=id).first()
36 |
37 | if not data:
38 | return Result(400, "删除失败:没有此网站")
39 |
40 | db.session.delete(data)
41 | db.session.commit()
42 |
43 | return Result(200, "删除网站成功")
44 |
45 |
46 | # 批量删除
47 | @link.route("/link", methods=["DELETE"])
48 | @siwa.doc(tags=["网站管理"], summary="批量删除网站", description="[1,2,3] 删除ID为1、2、3的数据", body=LinkBodyId)
49 | @TokenRequired
50 | def dropBatch():
51 | ids = request.json["ids"]
52 |
53 | for id in ids:
54 | data = LinkModel.query.filter_by(id=id).first()
55 |
56 | if not data:
57 | return Result(400, f"批量删除失败:没有ID:{id}的网站")
58 |
59 | db.session.delete(data)
60 |
61 | db.session.commit()
62 |
63 | return Result(200, "批量删除网站成功")
64 |
65 |
66 | # 编辑网站
67 | @link.route("/link", methods=["PATCH"])
68 | @siwa.doc(tags=["网站管理"], summary="编辑网站", body=LinkBody)
69 | @TokenRequired
70 | def edit():
71 | link = request.json
72 |
73 | data = LinkModel.query.filter_by(id=link["id"]).update(link)
74 |
75 | if not data:
76 | return Result(400, "编辑失败:没有此网站")
77 |
78 | db.session.commit()
79 |
80 | return Result(200, "编辑成功")
81 |
82 |
83 | # 获取网站详情
84 | @link.route("/link/")
85 | @siwa.doc(tags=["网站管理"], summary="获取网站详情", resp=LinkBody)
86 | def get(id):
87 | data = LinkModel.query.filter_by(id=id).first()
88 |
89 | if not data:
90 | return Result(400, "获取失败:没有此网站")
91 |
92 | data = data.to()
93 | data["type"] = TypeModel.query.filter_by(id=data["type"]).first().to()["name"]
94 |
95 | return Result(200, "获取网站详情成功", data)
96 |
97 |
98 | # 获取网站列表
99 | @link.route("/link")
100 | @siwa.doc(tags=["网站管理"], summary="获取网站列表", description="不传参数表示从第1页开始 每页查询5条数据",
101 | query=LinkQuery)
102 | def list():
103 | page = request.args.get("page", 1, type=int)
104 | size = request.args.get("size", 5, type=int)
105 |
106 | # 最新发布的网站在最前面排序
107 | paginate = LinkModel.query.order_by(LinkModel.createtime.desc()).paginate(page=page, per_page=size, error_out=False)
108 |
109 | result = [k.to() for k in paginate]
110 |
111 | for k in result:
112 | k["type"] = TypeModel.query.filter_by(id=k["type"]).first().to()["name"]
113 |
114 | data = {
115 | "result": result,
116 | "page": paginate.page,
117 | "size": paginate.per_page,
118 | "pages": paginate.pages,
119 | "total": paginate.total,
120 | "prev": paginate.has_prev,
121 | "next": paginate.has_next
122 | }
123 |
124 | return Result(200, "获取网站列表成功", data)
125 |
--------------------------------------------------------------------------------
/src/router/ResRouter.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from flask import Blueprint, request
4 |
5 | from src import app
6 | from src.utils.file import randomName
7 | from src.utils.jwt import TokenRequired
8 | from src.utils.response import Result
9 |
10 | from src import siwa
11 |
12 | # 创建蓝图
13 | res = Blueprint("res", __name__)
14 |
15 | from src.siwadoc.ResSiwa import ResBody, FileBody
16 |
17 |
18 | # 文件上传
19 | @res.route("/file", methods=["POST"])
20 | @siwa.doc(tags=["文件管理"], summary="批量上传文件",
21 | description="默认上传到default目录,可以通过target指定文件上传的位置",
22 | files={'file': {"required": True, "single": False}},
23 | form=ResBody)
24 | @TokenRequired
25 | def upload():
26 | from datetime import datetime
27 | from werkzeug.utils import secure_filename
28 |
29 | # 获取上传的文件列表
30 | files = request.files.getlist('file')
31 |
32 | # 目标存放文件:默认为image
33 | tagger = request.form.get("target", "default", type=str)
34 |
35 | # 获取年、月份
36 | date = datetime.now()
37 | year, month = str(date.year), str(date.month)
38 |
39 | # 项目根目录
40 | path = app.root_path
41 | # 获取项目资源存放位置
42 | upload = app.config["UPLOAD_PATH"]
43 | uploadPath = path + os.path.join(upload, tagger)
44 |
45 | # 根据年、月份来命名,创建文件目录
46 | # 判断该目录是否存在, 如果不存在则自动创建
47 | os.makedirs(uploadPath, exist_ok=True)
48 | os.makedirs(os.path.join(uploadPath, year), exist_ok=True)
49 | os.makedirs(os.path.join(uploadPath, year, month), exist_ok=True)
50 | dirPath = f"{tagger}/{year}/{month}/"
51 |
52 | # 保存所有文件的 URL
53 | urls = []
54 |
55 | for file in files:
56 | # 生成唯一文件名
57 | fileName = secure_filename(randomName(file.filename))
58 |
59 | # 将文件上传到指定的目录
60 | file.save(os.path.join(uploadPath, year, month, fileName))
61 |
62 | # 拼接文件路径
63 | url = f"{request.host_url}{dirPath}{fileName}"
64 | urls.append(url)
65 |
66 | return Result(200, "文件上传成功", urls)
67 |
68 |
69 | # 删除文件
70 | @res.route("/file", methods=["DELETE"])
71 | @siwa.doc(tags=["文件管理"], summary="删除文件", body=FileBody,
72 | description="根据文件的路径来删除")
73 | @TokenRequired
74 | def delete():
75 | files = request.json["files"]
76 |
77 | try:
78 | for file in files:
79 | os.remove(app.root_path + app.config["UPLOAD_PATH"] + file)
80 | except FileNotFoundError as e:
81 | return Result(500, str(e))
82 |
83 | return Result(200, "删除文件成功")
84 |
85 |
86 | # 获取文件列表
87 | @res.route("/file", methods=["GET"])
88 | @siwa.doc(tags=["文件管理"], summary="获取文件列表")
89 | @TokenRequired
90 | def list():
91 | upload = app.config["UPLOAD_PATH"][1:]
92 | dirs = get_directory_structure(os.path.join(app.root_path, upload))
93 | return Result(200, "获取文件列表成功", dirs)
94 |
95 |
96 | def get_directory_structure(path):
97 | structure = []
98 | if os.path.isdir(path):
99 | items = os.listdir(path)
100 |
101 | for item in items:
102 | item_path = os.path.join(path, item)
103 | # 如果是文件
104 | if os.path.isdir(item_path):
105 | # 如果没有子目录
106 | if hasDirFile("dir", item_path):
107 | children = get_directory_structure(item_path)
108 | directory = {
109 | "children": children,
110 | "list": [],
111 | "name": item
112 | }
113 | else:
114 | list = get_directory_structure(item_path)
115 | directory = {
116 | "children": [],
117 | "list": list,
118 | "name": item
119 | }
120 |
121 | structure.append(directory)
122 | else:
123 | structure.append(item)
124 | return structure
125 |
126 |
127 | # 判断指定目录中有没有目录或文件
128 | def hasDirFile(mark, directory):
129 | if mark == "dir":
130 | # 判断当前目录中是否有子目录
131 | for item in os.listdir(directory):
132 | if os.path.isdir(os.path.join(directory, item)):
133 | return True
134 | return False
135 | elif mark == "file":
136 | # 判断当前目录中是否有文件
137 | for item in os.listdir(directory):
138 | if os.path.isfile(os.path.join(directory, item)):
139 | return True
140 | return False
141 |
--------------------------------------------------------------------------------
/src/router/CateRouter.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, request
2 |
3 | from src.model import db
4 | from src.model.CateModel import CateModel
5 | from src import siwa
6 | from src.siwadoc.CateSiwa import CateQuery, CateBody, CateBodyId
7 | from src.utils.jwt import TokenRequired
8 | from src.utils.response import Result
9 |
10 | cate = Blueprint("cate", __name__)
11 |
12 |
13 | # 新增分类
14 | @cate.route("/cate", methods=["POST"])
15 | @siwa.doc(tags=["分类管理"], summary="新增分类",
16 | description="level的值为0表示新增一级分类,值为其他分类的id表示这个分类为二级。比如分类A的id为3,如果将分类B的level设置为分类A的ID(3),那么分类B就是分类A的子分类",
17 | body=CateBody)
18 | @TokenRequired
19 | def add():
20 | cate = request.json
21 |
22 | data = CateModel(**cate)
23 |
24 | db.session.add(data)
25 | db.session.commit()
26 |
27 | return Result(200, "新增成功")
28 |
29 |
30 | # 删除分类
31 | @cate.route("/cate/", methods=["DELETE"])
32 | @siwa.doc(tags=["分类管理"], summary="删除分类", description="通过ID删除指定分类")
33 | @TokenRequired
34 | def drop(id):
35 | data = CateModel.query.filter_by(id=id).first()
36 |
37 | if not data:
38 | return Result(400, "删除失败:没有此分类")
39 |
40 | # 判断需要删除的分类有没有子分类
41 | size = CateModel.query.filter_by(level=id).count()
42 | if size != 0: return Result(400, "请先删除该分类中的所有子分类")
43 |
44 | db.session.delete(data)
45 | db.session.commit()
46 |
47 | return Result(200, "删除分类成功")
48 |
49 |
50 | # 批量删除
51 | @cate.route("/cate", methods=["DELETE"])
52 | @siwa.doc(tags=["分类管理"], summary="批量删除分类", description="[1,2,3] 删除ID为1、2、3的数据", body=CateBodyId)
53 | @TokenRequired
54 | def dropBatch():
55 | ids = request.json["ids"]
56 |
57 | for id in ids:
58 | data = CateModel.query.filter_by(id=id).first()
59 |
60 | if not data:
61 | return Result(400, f"批量删除失败:没有ID:{id}的分类")
62 |
63 | db.session.delete(data)
64 |
65 | db.session.commit()
66 |
67 | return Result(200, "批量删除分类成功")
68 |
69 |
70 | # 编辑分类
71 | @cate.route("/cate", methods=["PATCH"])
72 | @siwa.doc(tags=["分类管理"], summary="编辑分类", body=CateBody)
73 | @TokenRequired
74 | def edit():
75 | cate = request.json
76 |
77 | data = CateModel.query.filter_by(id=cate["id"])
78 |
79 | if not data:
80 | return Result(400, "编辑失败:没有此分类")
81 |
82 | data.update({
83 | "name": cate["name"],
84 | "icon": cate["icon"],
85 | "url": cate["url"],
86 | "mark": cate["mark"],
87 | "level": cate["level"]
88 | })
89 |
90 | db.session.commit()
91 |
92 | return Result(200, "编辑成功")
93 |
94 |
95 | # 获取分类详情
96 | @cate.route("/cate/")
97 | @siwa.doc(tags=["分类管理"], summary="获取分类详情", resp=CateBody)
98 | def get(id):
99 | data = CateModel.query.filter_by(id=id).first()
100 |
101 | if not data:
102 | return Result(400, "获取失败:没有此分类")
103 |
104 | data = data.to()
105 | data['children'] = []
106 |
107 | list = [k.to() for k in CateModel.query.all()]
108 |
109 | # 查询该分类下的所有子分类
110 | for cate in list:
111 | if cate['level'] == id:
112 | data['children'].append(cate)
113 |
114 | # 如果为空, 就不让他显示children
115 | if len(data['children']) == 0:
116 | del data['children']
117 |
118 | return Result(200, "获取分类详情成功", data)
119 |
120 |
121 | # 获取分类列表
122 | @cate.route("/cate")
123 | @siwa.doc(tags=["分类管理"], summary="获取分类列表", description="不传参数表示从第1页开始 每页查询5条数据",
124 | query=CateQuery)
125 | def list():
126 | page = request.args.get("page", 1, type=int)
127 | size = request.args.get("size", 5, type=int)
128 |
129 | # 最新发布的分类在最前面排序
130 | paginate = CateModel.query.filter_by(level=0).paginate(page=page, per_page=size, error_out=False)
131 | list = CateModel.query.all()
132 |
133 | def tree(pid, data):
134 | children = []
135 |
136 | for cate in data:
137 | if cate['level'] == pid:
138 | cate['children'] = tree(cate['id'], data)
139 |
140 | # 如果为空, 就不让他显示children
141 | if len(cate['children']) == 0:
142 | del cate['children']
143 |
144 | children.append(cate)
145 |
146 | return children
147 |
148 | data = {
149 | "result": tree(0, [k.to() for k in list]),
150 | "page": paginate.page,
151 | "size": paginate.per_page,
152 | "pages": paginate.pages,
153 | "total": paginate.total,
154 | "prev": paginate.has_prev,
155 | "next": paginate.has_next
156 | }
157 |
158 | return Result(200, "获取分类列表成功", data)
159 |
--------------------------------------------------------------------------------
/src/router/CommentRouter.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, request
2 | from sqlalchemy import desc
3 |
4 | from src.model import db
5 | from src.model.ArticleModel import ArticleModel
6 | from src.model.CommentModel import CommentModel
7 | from src import siwa
8 | from src.siwadoc.CommentSiwa import CommentQuery, CommentBody, CommentBodyId
9 | from src.utils.jwt import TokenRequired
10 | from src.utils.response import Result
11 |
12 | comment = Blueprint("comment", __name__)
13 |
14 |
15 | # 新增评论
16 | @comment.route("/comment", methods=["POST"])
17 | @siwa.doc(tags=["评论管理"], summary="新增评论", description="新增评论记得把id去掉,否则可能会导致重复id异常",
18 | body=CommentBody)
19 | def add():
20 | comment = request.json
21 |
22 | data = CommentModel(**comment)
23 |
24 | db.session.add(data)
25 | db.session.commit()
26 |
27 | return Result(200, "新增成功")
28 |
29 |
30 | # 删除评论
31 | @comment.route("/comment/", methods=["DELETE"])
32 | @siwa.doc(tags=["评论管理"], summary="删除评论", description="通过ID删除指定评论")
33 | @TokenRequired
34 | def drop(id):
35 | data = CommentModel.query.filter_by(id=id).first()
36 |
37 | if not data:
38 | return Result(400, "删除失败:没有此评论")
39 |
40 | db.session.delete(data)
41 | db.session.commit()
42 |
43 | return Result(200, "删除评论成功")
44 |
45 |
46 | # 批量删除
47 | @comment.route("/comment", methods=["DELETE"])
48 | @siwa.doc(tags=["评论管理"], summary="批量删除评论", description="[1,2,3] 删除ID为1、2、3的数据", body=CommentBodyId)
49 | @TokenRequired
50 | def dropBatch():
51 | ids = request.json["ids"]
52 |
53 | for id in ids:
54 | data = CommentModel.query.filter_by(id=id).first()
55 |
56 | if not data:
57 | return Result(400, f"批量删除失败:没有ID:{id}的评论")
58 |
59 | db.session.delete(data)
60 |
61 | db.session.commit()
62 |
63 | return Result(200, "批量删除评论成功")
64 |
65 |
66 | # 编辑评论
67 | @comment.route("/comment", methods=["PATCH"])
68 | @siwa.doc(tags=["评论管理"], summary="编辑评论", body=CommentBody)
69 | @TokenRequired
70 | def edit():
71 | comment = request.json
72 |
73 | data = CommentModel.query.filter_by(id=comment["id"]).update(comment)
74 |
75 | if not data:
76 | return Result(400, "编辑失败:没有此评论")
77 |
78 | db.session.commit()
79 |
80 | return Result(200, "编辑成功")
81 |
82 |
83 | # 审核评论
84 | @comment.route("/comment/audit/", methods=["PATCH"])
85 | @TokenRequired
86 | def audit(id):
87 | data = CommentModel.query.filter_by(id=id).update({'audit': 1})
88 |
89 | if not data:
90 | return Result(400, "审核失败:没有此评论")
91 |
92 | db.session.commit()
93 |
94 | return Result(200, "审核通过")
95 |
96 |
97 | # 获取评论详情
98 | @comment.route("/comment/")
99 | @siwa.doc(tags=["评论管理"], summary="获取评论详情", resp=CommentBody)
100 | def get(id):
101 | data = CommentModel.query.filter_by(id=id).first()
102 |
103 | if not data:
104 | return Result(400, "获取失败:没有此评论")
105 |
106 | return Result(200, "获取评论详情成功", data.to())
107 |
108 |
109 | # 获取评论列表
110 | @comment.route("/comment")
111 | @siwa.doc(tags=["评论管理"], summary="获取评论列表", description="不传参数表示从第1页开始 每页查询5条数据",
112 | query=CommentQuery)
113 | def list():
114 | page = request.args.get("page", 1, type=int)
115 | size = request.args.get("size", 5, type=int)
116 |
117 | # 最新发布的评论在最前面排序
118 | paginate = CommentModel.query.order_by(desc(CommentModel.createtime)).paginate(page=page, per_page=size,
119 | error_out=False)
120 |
121 | result = []
122 |
123 | # 给每个评论绑定对应的文章标题
124 | for data in paginate:
125 | comment = data.to()
126 |
127 | art = ArticleModel.query.filter_by(id=comment["aid"]).first()
128 | if art is not None:
129 | comment["article"] = art.title
130 | else:
131 | comment["article"] = "子级"
132 | result.append(comment)
133 |
134 | data = {
135 | "result": result,
136 | "page": paginate.page,
137 | "size": paginate.per_page,
138 | "pages": paginate.pages,
139 | "total": paginate.total,
140 | "prev": paginate.has_prev,
141 | "next": paginate.has_next
142 | }
143 |
144 | return Result(200, "获取评论列表成功", data)
145 |
146 |
147 | # 获取指定文章中的所有评论
148 | @comment.route("/comment/article/")
149 | @siwa.doc(tags=["评论管理"], summary="获取指定文章中的评论", description="传入指定文章的ID")
150 | def articleComment(aid):
151 | # 最新发布的评论在最前面排序
152 | list = CommentModel.query.filter_by(aid=aid, audit=1).order_by(desc(CommentModel.createtime)).all()
153 |
154 | data = build_hierarchy([k.to() for k in list], 0)
155 |
156 | return Result(200, "获取指定文章评论成功", data)
157 |
158 |
159 | def build_hierarchy(data, rid):
160 | result = []
161 |
162 | for item in data:
163 | if item['audit'] == 1:
164 | if item['rid'] == rid:
165 | children = build_hierarchy(data, item['id'])
166 | if children:
167 | item['children'] = children
168 | result.append(item)
169 |
170 | return result
171 |
--------------------------------------------------------------------------------
/src/router/UserRouter.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, request
2 |
3 | import jwt
4 | from src import app
5 | from src.model import db
6 | from src.model.UserModel import UserModel
7 | from src import siwa
8 | from src.siwadoc.UserSiwa import UserQuery, LoginBody, UserBody, UserBodyId, UserAdminPass
9 | from src.utils.jwt import TokenRequired
10 | from src.utils.response import Result
11 | from datetime import datetime, timedelta
12 | from hashlib import md5
13 |
14 | user = Blueprint("user", __name__)
15 |
16 |
17 | # 用户登录
18 | @user.route("/login", methods=["POST"])
19 | @siwa.doc(tags=["用户管理"], summary="用户登录", body=LoginBody)
20 | def login():
21 | user = request.json
22 |
23 | data = UserModel.query.filter_by(username=user["username"]).first().to()
24 | if not data: return Result(400, "登录失败:没有此用户")
25 |
26 | # 给密码加密后与数据库中的做对比
27 | user["password"] = md5(user["password"].encode()).hexdigest()
28 |
29 | if user["password"] != data["password"]: return Result(400, "登录失败:用户密码错误")
30 |
31 | # 加载配置信息
32 | expire = app.config["EXPIRE"]
33 | secretkey = app.config["SECRET_KEY"]
34 | algorithm = app.config["ALGORITHM"]
35 |
36 | payload = {
37 | "exp": datetime.utcnow() + timedelta(seconds=expire)
38 | }
39 |
40 | # 生成token
41 | token = jwt.encode(payload, secretkey, algorithm)
42 |
43 | # 不返回密码字段
44 | del data["password"]
45 |
46 | return Result(200, "登录成功", {"token": token, "user": data})
47 |
48 |
49 | # 新增用户
50 | @user.route("/user", methods=["POST"])
51 | @siwa.doc(tags=["用户管理"], summary="新增用户", description="新增用户记得把id去掉,否则可能会导致重复id异常",
52 | body=UserBody)
53 | @TokenRequired
54 | def add():
55 | user = request.json
56 |
57 | # 密码加密处理
58 | user["password"] = md5(user["password"].encode()).hexdigest()
59 |
60 | data = UserModel(**user)
61 |
62 | db.session.add(data)
63 | db.session.commit()
64 |
65 | return Result(200, "新增成功")
66 |
67 |
68 | # 删除用户
69 | @user.route("/user/", methods=["DELETE"])
70 | @siwa.doc(tags=["用户管理"], summary="删除用户", description="通过ID删除指定用户")
71 | @TokenRequired
72 | def drop(id):
73 | data = UserModel.query.filter_by(id=id).first()
74 |
75 | if not data:
76 | return Result(400, "删除失败:没有此用户")
77 |
78 | db.session.delete(data)
79 | db.session.commit()
80 |
81 | return Result(200, "删除用户成功")
82 |
83 |
84 | # 批量删除
85 | @user.route("/user", methods=["DELETE"])
86 | @siwa.doc(tags=["用户管理"], summary="批量删除用户", description="[5,2,3] 删除ID为1、2、3的数据", body=UserBodyId)
87 | @TokenRequired
88 | def dropBatch():
89 | ids = request.json["ids"]
90 |
91 | for id in ids:
92 | data = UserModel.query.filter_by(id=id).first()
93 |
94 | if not data:
95 | return Result(400, f"批量删除失败:没有ID:{id}的用户")
96 |
97 | db.session.delete(data)
98 |
99 | db.session.commit()
100 |
101 | return Result(200, "批量删除用户成功")
102 |
103 |
104 | # 编辑用户
105 | @user.route("/user", methods=["PATCH"])
106 | @siwa.doc(tags=["用户管理"], summary="编辑用户", body=UserBody)
107 | @TokenRequired
108 | def edit():
109 | user = request.json
110 |
111 | data = UserModel.query.filter_by(id=user["id"]).update(user)
112 |
113 | if not data:
114 | return Result(400, "编辑失败:没有此用户")
115 |
116 | db.session.commit()
117 |
118 | return Result(200, "编辑成功")
119 |
120 |
121 | # 获取用户详情
122 | @user.route("/user/")
123 | @siwa.doc(tags=["用户管理"], summary="获取用户详情", resp=UserBody)
124 | def get(id):
125 | data = UserModel.query.filter_by(id=id).first().to()
126 |
127 | if not data:
128 | return Result(400, "获取失败:没有此用户")
129 |
130 | # 不返回密码字段
131 | del data["password"]
132 |
133 | return Result(200, "获取用户详情成功", data)
134 |
135 |
136 | # 获取用户列表
137 | @user.route("/user")
138 | @siwa.doc(tags=["用户管理"], summary="获取用户列表", description="不传参数表示从第1页开始 每页查询5条数据",
139 | query=UserQuery)
140 | def list():
141 | page = request.args.get("page", 1, type=int)
142 | size = request.args.get("size", 5, type=int)
143 |
144 | # 最新发布的用户在最前面排序
145 | paginate = UserModel.query.order_by(UserModel.createtime.desc()).paginate(page=page, per_page=size,
146 | error_out=False)
147 |
148 | result = [k.to() for k in paginate]
149 |
150 | # 删除所有的密码字段
151 | for data in result:
152 | del data["password"]
153 |
154 | data = {
155 | "result": result,
156 | "page": paginate.page,
157 | "size": paginate.per_page,
158 | "pages": paginate.pages,
159 | "total": paginate.total,
160 | "prev": paginate.has_prev,
161 | "next": paginate.has_next
162 | }
163 |
164 | return Result(200, "获取用户列表成功", data)
165 |
166 |
167 | # 修改管理员密码
168 | @user.route("/user/admin", methods=["PATCH"])
169 | @siwa.doc(tags=["用户管理"], summary="修改管理员密码", body=UserAdminPass)
170 | @TokenRequired
171 | def editAdminPass():
172 | user = request.json
173 |
174 | # 查找管理员账号是否存在
175 | data = UserModel.query.filter_by(username=user["username"]).first()
176 |
177 | if not data:
178 | return Result(400, "编辑失败:没有此用户")
179 |
180 | # 密码加密处理
181 | user["oldPassword"] = md5(user["oldPassword"].encode()).hexdigest()
182 |
183 | # 判断旧密码是否正确
184 | if user["oldPassword"] == data.password:
185 | data.password = md5(user["newPassword"].encode()).hexdigest()
186 | db.session.commit()
187 |
188 | return Result(200, "编辑成功")
189 | else:
190 | return Result(400, "编辑失败:旧密码不正确,请重新输入")
191 |
--------------------------------------------------------------------------------
/src/router/ProjectRouter.py:
--------------------------------------------------------------------------------
1 | import psutil
2 | import platform
3 | from datetime import datetime, date
4 |
5 | from flask import Blueprint, request
6 |
7 | from src.model.system.ProjectModel import ProjectModel
8 | from src.model.system.LayoutModel import LayoutModel
9 | from src.utils.jwt import TokenRequired
10 | from src.utils.response import Result
11 |
12 | from src import siwa
13 |
14 | # 创建蓝图
15 | project = Blueprint("project", __name__)
16 |
17 | from src.siwadoc.ProjectSiwa import ProjectBody
18 |
19 |
20 | # 获取系统配置
21 | @project.route("/project/system", methods=["GET"])
22 | @siwa.doc(tags=["全局配置"], summary="获取系统配置", description="获取系统配置:CPU、磁盘、IP、系统等等")
23 | @TokenRequired
24 | def getSystem():
25 | # 获取CPU信息
26 | cpu = psutil.cpu_percent(interval=1, percpu=True)
27 | cpu = round(sum(cpu) / len(cpu), 2)
28 |
29 | # 获取磁盘信息
30 | disk = psutil.disk_usage('/')
31 | diskTotal = round(disk.total / 1_073_741_824) # 总容量
32 | diskUsed = round(disk.used / 1_073_741_824) # 已使用容量
33 | diskFree = round(disk.free / 1073741824) # 可用容量
34 | diskPercent = disk.percent # 已用容量百分比
35 |
36 | # 获取内存信息
37 | memory = psutil.virtual_memory()
38 | memoryTotal = round(memory.total / 1_073_741_824, 2) # 获取内存总量
39 | memoryAvailable = round(memory.available / 1_073_741_824, 2) # 获取可用内存
40 | memoryPercent = memory.percent # 获取内存已使用百分比
41 | memoryUsed = round(memory.used / 1_073_741_824, 2) # 获取已使用内存
42 |
43 | # 系统开机时间
44 | boot_time = psutil.boot_time()
45 | boot_time_datetime = datetime.fromtimestamp(boot_time)
46 |
47 | # 获取系统不间断运行天数
48 | date1 = date(boot_time_datetime.year, boot_time_datetime.month, boot_time_datetime.day) # 系统开机时间
49 | date2 = date(datetime.now().year, datetime.now().month, datetime.now().day)
50 | # 计算日期差
51 | delta = date2 - date1
52 | # 获取天数差
53 | days = delta.days
54 |
55 | # 操作系统信息
56 | name = platform.system() # 名称
57 | version = platform.release() # 版本
58 |
59 | # 获取系统IP地址
60 | ip = request.environ.get('HTTP_X_REAL_IP', request.remote_addr)
61 |
62 | data = {
63 | "cpu": cpu,
64 | "disk": {"diskTotal": diskTotal, "diskUsed": diskUsed, "diskFree": diskFree, "diskPercent": diskPercent},
65 | "memory": {"memoryTotal": memoryTotal, "memoryAvailable": memoryAvailable, "memoryPercent": memoryPercent,
66 | "memoryUsed": memoryUsed},
67 | "boot_time_datetime": boot_time_datetime,
68 | "name": name,
69 | "run": days,
70 | "ip": ip
71 | }
72 |
73 | return Result(200, "获取系统配置成功", data)
74 |
75 |
76 | # 获取网站配置
77 | @project.route('/project/web', methods=['GET'])
78 | @siwa.doc(tags=["全局配置"], summary="获取网站配置", description="获取网站配置:标题、描述、LOGO、关键词等等")
79 | def getSite():
80 | p = ProjectModel()
81 |
82 | p.keyword = (",").join(p.keyword)
83 |
84 | data = {
85 | 'url': p.url,
86 | 'favicon': p.favicon,
87 | 'title': p.title,
88 | 'subhead': p.subhead,
89 | 'light_logo': p.light_logo,
90 | 'dark_logo': p.dark_logo,
91 | 'description': p.description,
92 | 'keyword': p.keyword,
93 | 'footer': p.footer,
94 | 'font': p.font,
95 | 'social': p.social,
96 | 'covers': p.covers
97 | }
98 |
99 | return Result(200, "获取网站配置成功", data)
100 |
101 |
102 | # 修改网站配置
103 | @project.route('/project/web', methods=['PATCH'])
104 | @siwa.doc(tags=["全局配置"], summary="修改网站配置", description="修改网站配置:标题、描述、LOGO、关键词等等",
105 | body=ProjectBody)
106 | @TokenRequired
107 | def editSite():
108 | web = request.json
109 |
110 | web["keyword"] = web["keyword"].split(",")
111 |
112 | data = f"""class ProjectModel(object):
113 | url = "{web['url']}" # 网站链接
114 | favicon = "{web['favicon']}" # 网站图标
115 | title = "{web['title']}" # 网站标题
116 | subhead = "{web['subhead']}" # 网站副标题
117 | light_logo = "{web['light_logo']}" # 白天主题logo
118 | dark_logo = "{web['dark_logo']}" # 暗黑主题logo
119 | description = "{web['description']}" # 网站描述
120 | keyword = {web['keyword']} # 网站SEO关键词
121 | footer = "{web['footer']}" # 底部描述
122 | font = "{web['font']}" # 字体链接
123 | social = {web['social']} # 社交账号
124 | covers = {web['covers']} # 随机文章封面
125 | """
126 |
127 | with open("src/model/system/ProjectModel.py", "w", encoding="utf8") as f:
128 | f.write(data)
129 |
130 | return Result(200, "修改网站配置成功")
131 |
132 |
133 | # 获取布局配置
134 | @project.route('/project/layout', methods=['GET'])
135 | @siwa.doc(tags=["全局配置"], summary="获取布局配置", description="获取布局配置:主题、文章列表、侧边栏、打字机等等")
136 | def getLayout():
137 | l = LayoutModel()
138 |
139 | data = {
140 | 'isArticleLayout': l.isArticleLayout,
141 | 'rightSidebar': l.rightSidebar,
142 | 'swiperImage': l.swiperImage,
143 | 'swiperText': l.swiperText,
144 | }
145 |
146 | return Result(200, "获取布局配置成功", data)
147 |
148 |
149 | # 修改布局配置
150 | @project.route('/project/layout', methods=['PATCH'])
151 | @siwa.doc(tags=["全局配置"], summary="修改布局配置", description="修改布局配置:主题、文章列表、侧边栏、打字机等等",
152 | body=ProjectBody)
153 | @TokenRequired
154 | def editLayout():
155 | layout = request.json
156 |
157 | data = f"""class LayoutModel(object):
158 | isArticleLayout = "{layout['isArticleLayout']}"
159 | rightSidebar = {layout['rightSidebar']}
160 | swiperImage = "{layout['swiperImage']}"
161 | swiperText = {layout['swiperText']}
162 | """
163 |
164 | with open("src/model/system/LayoutModel.py", "w", encoding="utf8") as f:
165 | f.write(data)
166 |
167 | return Result(200, "修改布局配置成功")
168 |
--------------------------------------------------------------------------------
/src/router/ArticleRouter.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, request
2 | from sqlalchemy import text
3 |
4 | from src.model import db
5 | from src.model.ArticleModel import ArticleModel
6 | from src.model.CateModel import CateModel
7 | from src import siwa
8 | from src.model.CommentModel import CommentModel
9 | from src.siwadoc.ArticleSiwa import ArticleQuery, ArticleBody, ArticleBodyId
10 | from src.utils.jwt import TokenRequired
11 | from src.utils.response import Result
12 |
13 | article = Blueprint("article", __name__)
14 |
15 |
16 | # 新增文章
17 | @article.route("/article", methods=["POST"])
18 | @siwa.doc(tags=["文章管理"], summary="新增文章", description="新增文章记得把id去掉,否则可能会导致重复id异常",
19 | body=ArticleBody)
20 | @TokenRequired
21 | def add():
22 | article = request.json
23 |
24 | # 将分类数组转换为字符串
25 | article["cids"] = ",".join([str(k) for k in article["cids"]])
26 |
27 | data = ArticleModel(**article)
28 |
29 | db.session.add(data)
30 | db.session.commit()
31 |
32 | return Result(200, "新增成功")
33 |
34 |
35 | # 删除文章
36 | @article.route("/article/", methods=["DELETE"])
37 | @siwa.doc(tags=["文章管理"], summary="删除文章", description="通过ID删除指定文章")
38 | @TokenRequired
39 | def drop(id):
40 | data = ArticleModel.query.filter_by(id=id).first()
41 |
42 | if not data:
43 | return Result(400, "删除失败:没有此文章")
44 |
45 | db.session.delete(data)
46 | db.session.commit()
47 |
48 | return Result(200, "删除文章成功")
49 |
50 |
51 | # 批量删除
52 | @article.route("/article", methods=["DELETE"])
53 | @siwa.doc(tags=["文章管理"], summary="批量删除文章", description="[1,2,3] 删除ID为1、2、3的数据", body=ArticleBodyId)
54 | @TokenRequired
55 | def dropBatch():
56 | ids = request.json["ids"]
57 |
58 | for id in ids:
59 | data = ArticleModel.query.filter_by(id=id).first()
60 |
61 | if not data:
62 | return Result(400, f"批量删除失败:没有ID:{id}的文章")
63 |
64 | db.session.delete(data)
65 |
66 | db.session.commit()
67 |
68 | return Result(200, "批量删除文章成功")
69 |
70 |
71 | # 编辑文章
72 | @article.route("/article", methods=["PATCH"])
73 | @siwa.doc(tags=["文章管理"], summary="编辑文章", body=ArticleBody)
74 | @TokenRequired
75 | def edit():
76 | article = request.json
77 |
78 | # 将分类数组转换为字符串
79 | article["cids"] = ",".join([str(k) for k in article["cids"]])
80 |
81 | data = ArticleModel.query.filter_by(id=article["id"])
82 |
83 | if not data:
84 | return Result(400, "编辑失败:没有此文章")
85 |
86 | data.update({
87 | "cids": article["cids"],
88 | "content": article["content"],
89 | "cover": article["cover"],
90 | "description": article["description"],
91 | "tag": article["tag"],
92 | "title": article["title"],
93 | "view": article["view"]
94 | })
95 |
96 | db.session.commit()
97 |
98 | return Result(200, "编辑成功")
99 |
100 |
101 | # 获取文章详情
102 | @article.route("/article/")
103 | @siwa.doc(tags=["文章管理"], summary="获取文章详情", resp=ArticleBody)
104 | def get(id):
105 | data = ArticleModel.query.filter_by(id=id).first()
106 |
107 | # 获取评论数量
108 | comment = CommentModel.query.filter_by(aid=id).all()
109 |
110 | if not data:
111 | return Result(400, "获取失败:没有此文章")
112 |
113 | article = data.to()
114 | article["cate"] = []
115 | # 将cid字符串转换为列表,并将字符串列表转换为数值列表
116 | article["cids"] = [int(k) for k in article["cids"].split(",")]
117 |
118 | # 循环每一项的分类id,找出文章所对应的那一个
119 | for cid in article["cids"]:
120 | cate = CateModel.query.filter_by(id=cid).first().to()
121 | article["cate"].append(cate)
122 |
123 | # 设置评论数量
124 | article["comment"] = len(comment)
125 |
126 | # 查询上一个文章
127 | prev = ArticleModel.query.filter(ArticleModel.createtime < article["createtime"]).order_by(
128 | ArticleModel.createtime.desc()).first()
129 | # 查询下一个文章
130 | next = ArticleModel.query.filter(ArticleModel.createtime > article["createtime"]).order_by(
131 | ArticleModel.createtime.asc()).first()
132 |
133 | if prev is None:
134 | result = {**article, "prev": prev, "next": next.to()}
135 | elif next is None:
136 | result = {**article, "prev": prev.to(), "next": next}
137 | else:
138 | result = {**article, "prev": prev.to(), "next": next.to()}
139 |
140 | return Result(200, "获取文章详情成功", result)
141 |
142 |
143 | # 获取文章列表
144 | @article.route("/article")
145 | @siwa.doc(tags=["文章管理"], summary="获取文章列表", description="不传参数表示从第1页开始 每页查询5条数据",
146 | query=ArticleQuery)
147 | def list():
148 | page = request.args.get("page", 1, type=int)
149 | size = request.args.get("size", 5, type=int)
150 |
151 | # 最新发布的文章在最前面排序
152 | paginate = ArticleModel.query.order_by(ArticleModel.createtime.desc()).paginate(page=page, per_page=size,
153 | error_out=False)
154 |
155 | result = []
156 |
157 | # 关联分类表
158 | for article in paginate:
159 | article = article.to()
160 |
161 | # 获取评论数量
162 | comment = CommentModel.query.filter_by(aid=article["id"]).all()
163 | article["comment"] = len(comment)
164 |
165 | article["cate"] = []
166 | # 将cid字符串转换为列表,并将字符串列表转换为数值列表
167 | article["cids"] = [int(k) for k in article["cids"].split(",")]
168 |
169 | # 循环每一项的分类id,找出文章所对应的那一个
170 | for id in article["cids"]:
171 | cate = CateModel.query.filter_by(id=id).first().to()
172 | article["cate"].append(cate)
173 |
174 | result.append(article)
175 |
176 | data = {
177 | "result": result,
178 | "page": paginate.page,
179 | "size": paginate.per_page,
180 | "pages": paginate.pages,
181 | "total": paginate.total,
182 | "prev": paginate.has_prev,
183 | "next": paginate.has_next
184 | }
185 |
186 | return Result(200, "获取文章列表成功", data)
187 |
188 |
189 | # 随机五篇文章
190 | @article.route("/article/random")
191 | @siwa.doc(tags=["文章管理"], summary="获取随机五篇文章")
192 | def randomArticle():
193 | query = text(
194 | "select * from article order by rand() limit 5")
195 | sql = db.session.execute(query)
196 |
197 | result = []
198 | for row in sql:
199 | result.append({"id": row.id, "title": row.title, "description": row.description, "content": row.content,
200 | "cover": row.cover,
201 | "view": row.view, "cids": row.cids, "tag": row.tag,
202 | "createtime": row.create_time})
203 |
204 | return Result(200, "获取随机文章成功", result)
205 |
206 |
207 | # 递增文章浏览量
208 | @article.route("/article/view/", methods=["PATCH"])
209 | @siwa.doc(tags=["文章管理"], summary="递增文章浏览量")
210 | def editView(id):
211 | query = text("update article set view = view + 1 where id = :id")
212 | sql = db.session.execute(query, {"id": id})
213 |
214 | db.session.commit()
215 |
216 | if sql.rowcount == 0:
217 | return Result(400, "递增失败")
218 |
219 | return Result(200, "递增成功")
220 |
221 |
222 | # 获取指定分类中的所有文章
223 | @article.route("/article/")
224 | @siwa.doc(tags=["文章管理"], summary="获取指定分类中的所有文章", description="根据分类的标识查询",
225 | query=ArticleQuery)
226 | def articleCate(mark):
227 | page = request.args.get("page", 1, type=int)
228 | size = request.args.get("size", 5, type=int)
229 |
230 | # 自定义sql查询
231 | query = text(
232 | "select a.* from article a, cate c where find_in_set(c.id,a.cids) and c.mark = :mark limit :size offset :offset")
233 | sql = db.session.execute(query, {'mark': mark, 'size': size, 'offset': (page - 1) * size})
234 |
235 | result = []
236 | for row in sql:
237 | cate = []
238 |
239 | # 循环每一项的分类id,找出文章所对应的那一个
240 | for id in [int(k) for k in row.cids.split(",")]:
241 | cate.append(CateModel.query.filter_by(id=id).first().to())
242 |
243 | result.append({"id": row.id, "title": row.title, "description": row.description, "content": row.content,
244 | "cover": row.cover,
245 | "view": row.view, "cids": row.cids, "cate": cate, "tag": row.tag,
246 | "createtime": row.create_time})
247 |
248 | data = {
249 | "result": result,
250 | "page": page,
251 | "size": size,
252 | "pages": 0,
253 | "total": len(result),
254 | "prev": False,
255 | "next": False
256 | }
257 |
258 | return Result(200, "获取文章列表成功", data)
259 |
--------------------------------------------------------------------------------
/thirive.sql:
--------------------------------------------------------------------------------
1 | -- MySQL dump 10.13 Distrib 8.0.35, for Win64 (x86_64)
2 | --
3 | -- Host: 82.157.186.125 Database: thrive
4 | -- ------------------------------------------------------
5 | -- Server version 8.3.0
6 |
7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
10 | /*!50503 SET NAMES utf8mb4 */;
11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
12 | /*!40103 SET TIME_ZONE='+00:00' */;
13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
17 |
18 | --
19 | -- Table structure for table `article`
20 | --
21 |
22 | DROP TABLE IF EXISTS `article`;
23 | /*!40101 SET @saved_cs_client = @@character_set_client */;
24 | /*!50503 SET character_set_client = utf8mb4 */;
25 | CREATE TABLE `article` (
26 | `id` int NOT NULL AUTO_INCREMENT COMMENT '文章ID',
27 | `title` varchar(100) NOT NULL COMMENT '文章标题',
28 | `description` varchar(200) DEFAULT NULL COMMENT '文章介绍',
29 | `content` text NOT NULL COMMENT '文章主要内容',
30 | `cover` varchar(300) DEFAULT NULL COMMENT '文章封面',
31 | `view` int DEFAULT NULL COMMENT '文章浏览量',
32 | `cids` varchar(255) DEFAULT NULL COMMENT '该文章所绑定的分类ID',
33 | `tag` varchar(100) DEFAULT NULL COMMENT '文章标签',
34 | `create_time` datetime DEFAULT NULL COMMENT '文章创建时间',
35 | PRIMARY KEY (`id`) USING BTREE
36 | ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
37 | /*!40101 SET character_set_client = @saved_cs_client */;
38 |
39 | --
40 | -- Dumping data for table `article`
41 | --
42 |
43 | LOCK TABLES `article` WRITE;
44 | /*!40000 ALTER TABLE `article` DISABLE KEYS */;
45 | INSERT INTO `article` VALUES (1,'Vue.js 3.0新特性介绍','本文介绍了Vue.js 3.0的新特性,包括Composition API、Teleport、Suspense等','# Vue.js 3.0新特性介绍\r\n\r\nVue.js是一款流行的JavaScript框架,用于构建用户界面。它在3.0版本中引入了一些令人兴奋的新特性,使得开发者能够更加高效地构建现代化的Web应用程序。本文将介绍Vue.js 3.0的一些重要特性。\r\n\r\n## Composition API\r\n\r\nVue.js 3.0引入了Composition API,这是一个全新的API风格,旨在提供更灵活、更可组合的代码复用方式。相比于以往的Options API,Composition API允许开发者通过函数的形式组织代码逻辑,使得代码更易于理解和维护。开发者可以根据需要将相关的逻辑组合在一起,而不需要按照生命周期钩子将它们分散在不同的选项中。\r\n\r\n下面是一个使用Composition API的示例:\r\n\r\n```javascript\r\nimport { ref, reactive, computed } from \'vue\';\r\n\r\nexport default {\r\n setup() {\r\n const count = ref(0);\r\n const state = reactive({\r\n message: \'Hello, Vue.js 3.0!\',\r\n });\r\n\r\n const doubleCount = computed(() => count.value * 2);\r\n\r\n function increment() {\r\n count.value++;\r\n }\r\n\r\n return {\r\n count,\r\n state,\r\n doubleCount,\r\n increment,\r\n };\r\n },\r\n};\r\n```\r\n\r\n## 更好的性能\r\n\r\nVue.js 3.0在性能方面进行了一系列的优化,使得应用程序的渲染速度更快、内存占用更少。其中最显著的改进是使用了Proxy对象来替代Object.defineProperty,这使得Vue.js能够更高效地追踪数据的变化。此外,Vue.js 3.0还引入了静态树提升(Static Tree Hoisting)和基于模板的优化(Template-based Optimization)等技术,进一步提升了应用程序的性能。\r\n\r\n## 更好的TypeScript支持\r\n\r\nVue.js 3.0对TypeScript的支持也得到了改进。新版本中的TypeScript声明文件提供了更准确的类型推断和类型检查,使得开发者能够更轻松地编写类型安全的Vue.js应用程序。此外,Vue.js 3.0还引入了一些新的TypeScript API,如`defineComponent`和`defineProps`,以提供更好的类型支持。\r\n\r\n下面是一个使用TypeScript的示例:\r\n\r\n```typescript\r\nimport { defineComponent, defineProps } from \'vue\';\r\n\r\ninterface Props {\r\n name: string;\r\n}\r\n\r\nexport default defineComponent({\r\n props: defineProps(),\r\n setup(props) {\r\n return {\r\n greet: `Hello, ${props.name}!`,\r\n };\r\n },\r\n});\r\n```\r\n\r\n## 更小的包体积\r\n\r\nVue.js 3.0还对包体积进行了优化。由于使用了Tree-shaking技术,新版本中的Vue.js只包含了实际使用到的代码,减少了不必要的代码体积。此外,Vue.js 3.0还支持按需加载,使得开发者可以只引入需要的功能模块,进一步减小了包体积。\r\n\r\n下面是一个按需加载的示例:\r\n\r\n```javascript\r\nimport { createApp } from \'vue\';\r\nimport { Button, Input } from \'ant-design-vue\';\r\n\r\nconst app = createApp();\r\n\r\napp.use(Button);\r\napp.use(Input);\r\n\r\napp.mount(\'#app\');\r\n```\r\n\r\n## 更好的开发者工具\r\n\r\nVue.js 3.0提供了一系列新的开发者工具,使得开发者能够更轻松地调试和优化应用程序。新版本中的Devtools提供了更多的功能,如组件树的可视化、性能分析、事件追踪等。此外,Vue.js 3.0还引入了新的警告系统,使得开发者能够更容易地发现和修复潜在的问题。\r\n\r\n总结\r\n\r\nVue.js 3.0引入了许多令人兴奋的新特性,包括Composition API、更好的性能、更好的TypeScript支持、更小的包体积和更好的开发者工具。这些特性使得开发者能够更加高效地构建现代化的Web应用程序。如果你还没有尝试Vue.js 3.0,现在是时候开始了!','https://bu.dusays.com/2024/04/25/662a127c8df63.png',44,'2','Nodejs','2023-10-25 04:00:00'),(2,'Java 15新特性详解','本文介绍了Java 15的新特性,包括ZGC、Records、Text Blocks等','# Java 15新特性详解\nJava 15是Java语言的最新版本,它带来了一些非常实用的新特性。其中最重要的特性是ZGC,它是一种高效的垃圾回收器,可以大大提高Java应用程序的性能和可靠性。此外,Records和Text Blocks也是非常有用的新特性,它们可以帮助我们更好地处理数据和字符串。','https://bu.dusays.com/2024/04/25/662a127cacf86.jpg',17,'4,5,7,9','Java','2023-10-23 10:00:00'),(3,'Python爬虫实战教程','本文介绍了Python爬虫的基本原理和实战技巧','Python是一种非常流行的编程语言,它在数据处理和网络爬虫方面有着广泛的应用。本文将介绍Python爬虫的基本原理和实战技巧,包括如何使用Python的requests和beautifulsoup库来爬取网页数据,如何处理JSON和XML格式的数据,以及如何使用selenium库模拟用户行为。','https://bu.dusays.com/2024/04/25/662a127c9ac4b.jpeg',1,'4','Python','2023-10-22 08:00:00'),(4,'前端性能优化的10个技巧','本文介绍了前端性能优化的10个实用技巧,包括减少HTTP请求、使用CDN、优化图片等','前端性能优化是Web开发中非常重要的一环,它可以提高网站的加载速度和用户体验。本文将介绍10个实用的前端性能优化技巧,包括减少HTTP请求、使用CDN、优化图片、使用缓存、压缩代码等。这些技巧可以帮助开发者更好地优化自己的网站,提高用户满意度。','',0,'4','性能优化','2023-10-21 14:00:00'),(5,'使用Docker部署Java应用程序','本文介绍了如何使用Docker来部署Java应用程序','Docker是一种非常流行的容器化技术,它可以帮助开发者更好地管理和部署应用程序。本文将介绍如何使用Docker来部署Java应用程序,包括如何编写Dockerfile、如何构建和运行Docker镜像、如何使用Docker Compose来管理多个容器等。这些技巧可以帮助开发者更好地管理自己的Java应用程序,提高开发效率。','',0,'4','Java','2023-10-20 16:00:00'),(6,'前端开发入门指南','本文介绍了前端开发的基本概念和技术栈,适合初学者入门。','前端开发是指利用HTML、CSS和JavaScript等技术,开发网站的用户界面部分。它负责将网站的设计和用户交互变成可视化的界面,为用户提供优秀的用户体验。','',0,'4','入门','2023-01-01 10:00:00'),(7,'Vue.js实战教程','本文通过实例演示了如何使用Vue.js构建现代化的Web应用程序。','Vue.js是一个用于构建用户界面的渐进式JavaScript框架。它易于学习、灵活且高效,被广泛应用于前端开发领域。本文从基础概念到高级特性,详细介绍了Vue.js的使用方法。','https://bu.dusays.com/2024/04/25/662a127c8df63.png',0,'4,5,7,9','Vue.js','2023-02-01 14:00:00'),(8,'Java入门指南','本文介绍了Java编程语言的基本概念和语法,适合初学者入门。','Java是一种通用的高级编程语言,具有跨平台、面向对象和安全性等特点。它被广泛应用于企业级应用开发、移动应用开发和大数据处理等领域。本文从安装到编写简单程序,全面讲解了Java的入门知识。','https://bu.dusays.com/2024/04/25/662a127cacf86.jpg',0,'4,5,7,9','入门','2023-03-01 12:00:00'),(9,'Python数据分析实战','本文介绍了使用Python进行数据分析的基本方法和常用工具,适合数据分析初学者。','Python是一种简单易学且功能强大的编程语言,被广泛应用于数据科学和机器学习领域。本文通过实例演示了如何使用Python进行数据清洗、数据可视化和机器学习建模等任务。','https://bu.dusays.com/2024/04/25/662a127c9ac4b.jpeg',0,'4','数据分析','2023-04-01 16:00:00'),(10,'深入理解MySQL数据库','本文深入介绍了MySQL数据库的架构、优化和高级特性,适合有一定数据库基础的开发人员。','MySQL是一种常用的关系型数据库管理系统,被广泛应用于Web应用程序和企业级系统。本文从数据库设计到性能优化,详细讲解了MySQL的各个方面,帮助读者更好地理解和使用MySQL。','',7,'4','MySQL','2023-05-01 18:00:00');
46 | /*!40000 ALTER TABLE `article` ENABLE KEYS */;
47 | UNLOCK TABLES;
48 |
49 | --
50 | -- Table structure for table `cate`
51 | --
52 |
53 | DROP TABLE IF EXISTS `cate`;
54 | /*!40101 SET @saved_cs_client = @@character_set_client */;
55 | /*!50503 SET character_set_client = utf8mb4 */;
56 | CREATE TABLE `cate` (
57 | `id` int NOT NULL AUTO_INCREMENT,
58 | `name` varchar(255) NOT NULL COMMENT '分类名称',
59 | `icon` varchar(100) DEFAULT NULL COMMENT '分类图标',
60 | `url` varchar(255) DEFAULT NULL COMMENT '分类链接',
61 | `mark` varchar(100) NOT NULL COMMENT '分类标识',
62 | `level` int DEFAULT NULL COMMENT '分类级别',
63 | PRIMARY KEY (`id`) USING BTREE,
64 | UNIQUE KEY `name` (`name`) USING BTREE,
65 | UNIQUE KEY `cate_pk` (`mark`)
66 | ) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
67 | /*!40101 SET character_set_client = @saved_cs_client */;
68 |
69 | --
70 | -- Dumping data for table `cate`
71 | --
72 |
73 | LOCK TABLES `cate` WRITE;
74 | /*!40000 ALTER TABLE `cate` DISABLE KEYS */;
75 | INSERT INTO `cate` VALUES (1,'开发笔记','🎉','/','kfbj',0),(2,'生活随笔','✍️','/','shsb',0),(4,'大前端','🎉','http://127.0.0.1:5000','dqd',0),(5,'前端','?','/','qd',4),(7,'Java','?','/','java',4),(9,'Python','?','/','python',4);
76 | /*!40000 ALTER TABLE `cate` ENABLE KEYS */;
77 | UNLOCK TABLES;
78 |
79 | --
80 | -- Table structure for table `chat`
81 | --
82 |
83 | DROP TABLE IF EXISTS `chat`;
84 | /*!40101 SET @saved_cs_client = @@character_set_client */;
85 | /*!50503 SET character_set_client = utf8mb4 */;
86 | CREATE TABLE `chat` (
87 | `id` int NOT NULL AUTO_INCREMENT,
88 | `room` int NOT NULL,
89 | `data` json NOT NULL,
90 | PRIMARY KEY (`id`),
91 | UNIQUE KEY `chat_pk_2` (`id`)
92 | ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
93 | /*!40101 SET character_set_client = @saved_cs_client */;
94 |
95 | --
96 | -- Dumping data for table `chat`
97 | --
98 |
99 | LOCK TABLES `chat` WRITE;
100 | /*!40000 ALTER TABLE `chat` DISABLE KEYS */;
101 | INSERT INTO `chat` VALUES (18,10001,'{\"date\": \"2023-05-25\", \"name\": \"宇阳\", \"avatar\": \"https://api.dicebear.com/7.x/fun-emoji/svg?seed=Lilly\", \"content\": \"Hello! 有什么要对我说的吗?\"}'),(19,10003,'{\"date\": \"2023-05-25\", \"name\": \"神秘人\", \"avatar\": \"https://api.dicebear.com/7.x/fun-emoji/svg?seed=Lilly\", \"content\": \"大家可以在这里提交你的需求以及宝贵的建议\"}'),(20,10004,'{\"date\": \"2023-05-25\", \"name\": \"神秘人\", \"avatar\": \"https://api.dicebear.com/7.x/fun-emoji/svg?seed=Lilly\", \"content\": \"抢沙发\"}'),(21,10002,'{\"date\": \"2023-05-25\", \"name\": \"神秘人\", \"avatar\": \"https://api.dicebear.com/7.x/fun-emoji/svg?seed=Lilly\", \"content\": \"占楼\"}');
102 | /*!40000 ALTER TABLE `chat` ENABLE KEYS */;
103 | UNLOCK TABLES;
104 |
105 | --
106 | -- Table structure for table `comment`
107 | --
108 |
109 | DROP TABLE IF EXISTS `comment`;
110 | /*!40101 SET @saved_cs_client = @@character_set_client */;
111 | /*!50503 SET character_set_client = utf8mb4 */;
112 | CREATE TABLE `comment` (
113 | `id` int NOT NULL AUTO_INCREMENT,
114 | `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
115 | `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
116 | `content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
117 | `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
118 | `url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
119 | `aid` int NOT NULL,
120 | `rid` int NOT NULL,
121 | `create_time` datetime DEFAULT NULL,
122 | `audit` int DEFAULT '0' COMMENT '是否审核',
123 | PRIMARY KEY (`id`) USING BTREE
124 | ) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
125 | /*!40101 SET character_set_client = @saved_cs_client */;
126 |
127 | --
128 | -- Dumping data for table `comment`
129 | --
130 |
131 | LOCK TABLES `comment` WRITE;
132 | /*!40000 ALTER TABLE `comment` DISABLE KEYS */;
133 | INSERT INTO `comment` VALUES (36,'神秘人','https://q1.qlogo.cn/g?b=qq&nk=3311118881&s=640','测试评论','3311118881@qq.com','http://127.0.0.1:5173/',1,0,'2023-11-24 08:13:59',1),(37,'神秘人2号','https://q1.qlogo.cn/g?b=qq&nk=2518848232&s=640','测试回复评论','2518848232@qq.com','http://127.0.0.1:5173/',0,36,'2023-11-24 08:14:22',1),(38,'神秘人2号','https://q1.qlogo.cn/g?b=qq&nk=2518848232&s=640','第二条评论','2518848232@qq.com','http://127.0.0.1:5173/',1,0,'2023-11-24 08:14:32',1),(50,'神秘人3号','https://q1.qlogo.cn/g?b=qq&nk=754443568&s=640','三级','754443568@qq.com','http://127.0.0.1:5173/',0,37,'2023-11-24 09:27:37',0),(55,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,0,'2024-03-26 02:31:18',1),(56,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,55,'2024-03-26 02:31:18',1),(57,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,56,'2024-03-26 02:31:18',1),(58,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,55,'2024-03-26 02:31:18',1),(59,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,56,'2024-03-26 02:31:18',1),(60,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,56,'2024-03-26 02:31:18',1),(61,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,56,'2024-03-26 02:31:18',1),(62,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,0,'2024-03-26 02:31:18',1),(63,'刘宇阳','https://liuyuyang.net/avatar.jpg','123','liuyuyang1024@163.com','',1,0,'2024-03-26 02:31:18',1),(64,'神秘人','','写的不错','liuyuyang1024@163.com','',1,0,'2024-03-26 09:47:03',1),(65,'神秘人','https://q1.qlogo.cn/g?b=qq&nk=liuyuyang1024&s=640','123','liuyuyang1024@163.com','',1,0,'2024-03-26 09:51:58',0);
134 | /*!40000 ALTER TABLE `comment` ENABLE KEYS */;
135 | UNLOCK TABLES;
136 |
137 | --
138 | -- Table structure for table `link`
139 | --
140 |
141 | DROP TABLE IF EXISTS `link`;
142 | /*!40101 SET @saved_cs_client = @@character_set_client */;
143 | /*!50503 SET character_set_client = utf8mb4 */;
144 | CREATE TABLE `link` (
145 | `id` int NOT NULL AUTO_INCREMENT,
146 | `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
147 | `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
148 | `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
149 | `image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
150 | `url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
151 | `type` int NOT NULL,
152 | `create_time` datetime DEFAULT NULL,
153 | PRIMARY KEY (`id`) USING BTREE
154 | ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
155 | /*!40101 SET character_set_client = @saved_cs_client */;
156 |
157 | --
158 | -- Dumping data for table `link`
159 | --
160 |
161 | LOCK TABLES `link` WRITE;
162 | /*!40000 ALTER TABLE `link` DISABLE KEYS */;
163 | INSERT INTO `link` VALUES (6,'Thrive','记录一个架构师的崛起','3311118881@qq.com','https://q1.qlogo.cn/g?b=qq&nk=3311118881&s=640','/',2,'2023-10-02 18:54:44'),(7,'张洪Heo','分享设计与科技生活','3311118881@qq.com','https://bu.dusays.com/2022/12/28/63ac2812183aa.png','https://blog.zhheo.com/',1,'2023-10-02 18:54:44'),(8,'友人C','友人C的个人空间','3311118881@qq.com','https://s1.ax1x.com/2023/06/02/p9zTn0O.png','http://space.eyescode.top',2,'2023-10-02 18:54:44'),(9,'秦枫鸢梦','花有重开日,人无再少年','3311118881@qq.com','https://blog.zwying.com/avatar.jpg','https://blog.zwying.com',1,'2023-10-02 18:54:44'),(10,'生活倒影','这是一个 Vue2 Vue3 与 SpringBoot 结合的产物','3311118881@qq.com','https://s1.ax1x.com/2022/11/10/z9E7X4.jpg','https://poetize.cn/',1,'2023-10-02 18:54:44'),(11,'心月云','须知少时凌云志,曾许人间第一流','3311118881@qq.com','https://wch666.com/head.png','https://wch666.com',1,'2023-10-02 18:54:44'),(12,'一克猫','一只微不足道的猫','3311118881@qq.com','https://cravatar.cn/avatar/7adbfaef92d9d082be5dec39f3fe3d02?s=200','https://www.1gcat.com',2,'2023-10-02 18:54:44'),(13,'频率','风卷过的起点','3311118881@qq.com','https://cravatar.cn/avatar/cc763511474fe24ffcc80257fb7cb970?s=256','https://pinlyu.com/',1,'2023-10-02 18:54:44'),(14,'青灯暮雨','再渺小的星光,也有属于它的光芒','3311118881@qq.com','https://www.blatr.cn/images/adminAvatar.jpg','https://www.blatr.cn',1,'2023-10-02 18:54:44'),(15,'相左','心有山海,静而不争','3311118881@qq.com','https://qiniu.ztyang.com/img/wechatavatar.jpg','https://www.ztyang.com',1,'2023-10-02 18:54:44'),(16,'Echo’s blog','韶华不为少年留 恨悠悠 几时休','3311118881@qq.com','https://yy.liveout.cn/photo/photo2.jpg','https://www.liveout.cn/index/',1,'2023-10-02 18:54:44'),(17,'奇异纬度','不曾与你分享的时间,我在进步','3311118881@qq.com','https://blog.isww.cn/logo.head.jpg','https://blog.isww.cn/',1,'2023-10-02 18:54:44'),(18,'正物博客','一场凡梦,一份追求','3311118881@qq.com','https://www.zwbo.com/tx.png','https://www.zwbo.com/',2,'2023-10-02 18:54:44'),(19,'HONG的小站','或许是个二次元','3311118881@qq.com','https://blog.zwying.com/usr/uploads/sina/63adb58e798d4.jpg','https://hongweblog.com/',1,'2023-10-02 18:54:44'),(26,'11','22','3311118881@qq.com','44','66',2,'2024-02-07 13:21:55');
164 | /*!40000 ALTER TABLE `link` ENABLE KEYS */;
165 | UNLOCK TABLES;
166 |
167 | --
168 | -- Table structure for table `swiper`
169 | --
170 |
171 | DROP TABLE IF EXISTS `swiper`;
172 | /*!40101 SET @saved_cs_client = @@character_set_client */;
173 | /*!50503 SET character_set_client = utf8mb4 */;
174 | CREATE TABLE `swiper` (
175 | `id` int NOT NULL AUTO_INCREMENT,
176 | `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
177 | `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
178 | `image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
179 | `url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
180 | PRIMARY KEY (`id`) USING BTREE
181 | ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
182 | /*!40101 SET character_set_client = @saved_cs_client */;
183 |
184 | --
185 | -- Dumping data for table `swiper`
186 | --
187 |
188 | LOCK TABLES `swiper` WRITE;
189 | /*!40000 ALTER TABLE `swiper` DISABLE KEYS */;
190 | INSERT INTO `swiper` VALUES (1,'半山腰的风景很美,然而我还是更想到山顶看看','The scenery halfway up the mountain is beautiful, but I still prefer to see the mountaintop','https://bu.dusays.com/2023/11/10/654e2cf6055b0.jpg','/'),(14,'ces','ces','https://bu.dusays.com/2023/11/05/65473822495c8.jpg','/');
191 | /*!40000 ALTER TABLE `swiper` ENABLE KEYS */;
192 | UNLOCK TABLES;
193 |
194 | --
195 | -- Table structure for table `tag`
196 | --
197 |
198 | DROP TABLE IF EXISTS `tag`;
199 | /*!40101 SET @saved_cs_client = @@character_set_client */;
200 | /*!50503 SET character_set_client = utf8mb4 */;
201 | CREATE TABLE `tag` (
202 | `id` int NOT NULL AUTO_INCREMENT,
203 | `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
204 | PRIMARY KEY (`id`) USING BTREE
205 | ) ENGINE=InnoDB AUTO_INCREMENT=68 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
206 | /*!40101 SET character_set_client = @saved_cs_client */;
207 |
208 | --
209 | -- Dumping data for table `tag`
210 | --
211 |
212 | LOCK TABLES `tag` WRITE;
213 | /*!40000 ALTER TABLE `tag` DISABLE KEYS */;
214 | INSERT INTO `tag` VALUES (3,'Nodejs'),(4,'Python'),(5,'Java'),(6,'Element ui'),(7,'Vue3'),(8,'React'),(10,'Django'),(11,'Flask'),(12,'JavaScript'),(13,'HTML'),(14,'CSS'),(15,'Ajax'),(16,'axios'),(17,'全栈开发'),(54,'大前端'),(63,'123'),(65,'88'),(66,'生活随笔'),(67,'Mybatis');
215 | /*!40000 ALTER TABLE `tag` ENABLE KEYS */;
216 | UNLOCK TABLES;
217 |
218 | --
219 | -- Table structure for table `type`
220 | --
221 |
222 | DROP TABLE IF EXISTS `type`;
223 | /*!40101 SET @saved_cs_client = @@character_set_client */;
224 | /*!50503 SET character_set_client = utf8mb4 */;
225 | CREATE TABLE `type` (
226 | `id` int NOT NULL AUTO_INCREMENT,
227 | `name` varchar(100) NOT NULL COMMENT '类型名称',
228 | PRIMARY KEY (`id`),
229 | UNIQUE KEY `type_pk_2` (`id`)
230 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='网站类型';
231 | /*!40101 SET character_set_client = @saved_cs_client */;
232 |
233 | --
234 | -- Dumping data for table `type`
235 | --
236 |
237 | LOCK TABLES `type` WRITE;
238 | /*!40000 ALTER TABLE `type` DISABLE KEYS */;
239 | INSERT INTO `type` VALUES (1,'生活类'),(2,'技术类');
240 | /*!40000 ALTER TABLE `type` ENABLE KEYS */;
241 | UNLOCK TABLES;
242 |
243 | --
244 | -- Table structure for table `user`
245 | --
246 |
247 | DROP TABLE IF EXISTS `user`;
248 | /*!40101 SET @saved_cs_client = @@character_set_client */;
249 | /*!50503 SET character_set_client = utf8mb4 */;
250 | CREATE TABLE `user` (
251 | `id` int NOT NULL AUTO_INCREMENT,
252 | `username` varchar(50) DEFAULT NULL COMMENT '用户名',
253 | `password` varchar(50) DEFAULT NULL COMMENT '密码',
254 | `name` varchar(50) NOT NULL COMMENT '用户名称',
255 | `email` varchar(100) NOT NULL COMMENT '用户邮箱',
256 | `avatar` varchar(255) NOT NULL COMMENT '用户头像',
257 | `info` varchar(255) NOT NULL COMMENT '用户介绍',
258 | `role` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
259 | `create_time` datetime DEFAULT NULL COMMENT '用户创建时间',
260 | PRIMARY KEY (`id`) USING BTREE,
261 | UNIQUE KEY `user_pk` (`username`)
262 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
263 | /*!40101 SET character_set_client = @saved_cs_client */;
264 |
265 | --
266 | -- Dumping data for table `user`
267 | --
268 |
269 | LOCK TABLES `user` WRITE;
270 | /*!40000 ALTER TABLE `user` DISABLE KEYS */;
271 | INSERT INTO `user` VALUES (1,'liuyuyang','4297f44b13955235245b2497399d7a93','宇阳','3311118881@qq.com','https://blog.liuyuyang.net/avatar.jpg','再渺小的星光,也有属于他的光芒!','admin','2024-01-22 18:32:30');
272 | /*!40000 ALTER TABLE `user` ENABLE KEYS */;
273 | UNLOCK TABLES;
274 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
275 |
276 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
277 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
278 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
279 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
280 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
281 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
282 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
283 |
284 | -- Dump completed on 2024-06-01 21:02:26
285 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------