张昊 4 months ago
parent b0041086be
commit a1f615f8fe

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" />
</project> </project>

@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/.idea/woniubiji.iml" filepath="$PROJECT_DIR$/.idea/woniubiji.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/woniu2.iml" filepath="$PROJECT_DIR$/.idea/woniu2.iml" />
</modules> </modules>
</component> </component>
</project> </project>

@ -5,7 +5,4 @@
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings">
<option name="renderExternalDocumentation" value="true" />
</component>
</module> </module>

@ -0,0 +1,22 @@
# app.py
from main import app
from controller.index import index as index_blueprint
from controller.user import user as user_blueprint
from controller.article import article as article_blueprint
from controller.favorite import favorite as favorite_blueprint
from controller.comment import comment as comment_blueprint
from controller.admin import admin as admin_blueprint
from controller.ucenter import ucenter as ucenter_blueprint
from controller.ueditor import ueditor as ueditor_blueprint
#
app.register_blueprint(index_blueprint)
app.register_blueprint(user_blueprint)
app.register_blueprint(article_blueprint)
app.register_blueprint(favorite_blueprint)
app.register_blueprint(comment_blueprint)
app.register_blueprint(admin_blueprint)
app.register_blueprint(ucenter_blueprint)
app.register_blueprint(ueditor_blueprint)
if __name__ == '__main__':
app.run(debug=True)

@ -109,8 +109,8 @@ def send_email(receiver, ecode):
def gen_email_code(): def gen_email_code():
return ''.join(random.choices(string.ascii_letters + string.digits, k=6)) return ''.join(random.choices(string.ascii_letters + string.digits, k=6))
#
# 测试邮箱能否发送成功 # # 测试邮箱能否发送成功
# code = gen_email_code() # code = gen_email_code()
# print(code) # print(code)
# send_email('2082813839@qq.com', code) # send_email('2082813839@qq.com', code)
@ -228,5 +228,3 @@ def generate_thumb(url_list):
# thumb = generate_thumb(list) # thumb = generate_thumb(list)
# #
# print(thumb) # print(thumb)

@ -0,0 +1,106 @@
from flask import Blueprint, render_template, session, request, jsonify
from module.article import Article
from module.user import Users
import math
admin = Blueprint("admin", __name__)
# @admin.before_request
# def before_admin():
# if session.get('islogin') != 'true' or session.get('role') != 'admin':
# return 'perm-denied'
# 为系统管理首页填充文章列表,并绘制分页栏
@admin.route('/admin')
def sys_admin():
pagesize = 50
article = Article()
result = article.find_all_except_draft(0, pagesize)
total = math.ceil(article.get_count_except_draft() / pagesize)
return render_template('system-admin.html', page=1, result=result, total=total)
@admin.route('/admin/user')
def sys_admin_user():
pagesize = 50
user = Users()
result = user.find_all_users()
total = math.ceil(user.get_total_count_user() / pagesize)
return render_template('system-admin-user.html', page=1, result=result, total=total)
# 为系统管理首页的文章列表进行分页查询
@admin.route('/admin/article/<int:page>')
def admin_article(page):
pagesize = 50
start = (page - 1) * pagesize
article = Article()
result = article.find_all_except_draft(start, pagesize)
total = math.ceil(article.get_count_except_draft() / pagesize)
return render_template('system-admin.html', page=page, result=result, total=total)
# 按照文章标题进行模糊查询的后台接口
@admin.route('/admin/search/<keyword>')
def admin_search_headline(keyword):
result = Article().find_by_headline_except_draft(keyword)
return render_template('system-admin.html', page=1, result=result, total=1)
# 文章的隐藏切换接口
@admin.route('/admin/article/hide/<int:articleid>')
def admin_article_hide(articleid):
print("articleid=",articleid)
hidden = Article().switch_hidden(articleid)
print("hidden=",hidden)
return str(hidden)
# 文章的推荐切换接口
@admin.route('/admin/article/recommend/<int:articleid>')
def admin_article_recommend(articleid):
recommended = Article().switch_recommended(articleid)
return str(recommended)
# 文章的审核切换接口
@admin.route('/admin/article/check/<int:articleid>')
def admin_article_check(articleid):
checked = Article().switch_checked(articleid)
return str(checked)
# 人员身份切换接口
@admin.route('/admin/user/role/<int:userid>')
def admin_user_check(userid):
role = Users().switch_role(userid)
return str(role)
# 删除文章
@admin.route('/admin/article/delete/<int:articleid>', methods=['GET'])
def delete_article(articleid):
article = Article()
try:
# 查找文章
result = article.find_by_id(articleid)
if result is None:
return jsonify({"success": False, "message": "文章不存在"})
# 删除文章
article.do_deletesign(articleid)
return jsonify({"success": True, "message": "删除成功"})
except Exception as e:
return jsonify({"success": False, "message": str(e)})
# 删除人员
@admin.route('/admin/user/delete/<int:userid>', methods=['GET'])
def delete_user(userid):
user = Users()
try:
# 查找人员
result = user.find_user_by_id(userid)
if result is None:
return jsonify({"success": False, "message": "用户不存在"})
# 删除人员
user.do_deletesign_user(userid)
return jsonify({"success": True, "message": "删除成功"})
except Exception as e:
return jsonify({"success": False, "message": str(e)})

@ -1,8 +1,11 @@
from flask import Blueprint, abort, render_template, request from flask import Blueprint, abort, render_template, request, session
from module.article import Article from module.article import Article
from module.comment import Comment
from module.credit import Credit from module.credit import Credit
from module.thumb import Thumb
from module.user import Users from module.user import Users
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from module.favorite import Favorite
article = Blueprint("article",__name__) article = Blueprint("article",__name__)
@ -21,19 +24,31 @@ def read(articleid):
content_half = ''.join([str(p) for p in soup.find_all('p')[:half_point]]) content_half = ''.join([str(p) for p in soup.find_all('p')[:half_point]])
# 你可以在这里处理结果_last和result_next但注意边界条件 # 你可以在这里处理结果_last和result_next但注意边界条件
result_last = Article().find_by_id(articleid - 1) if articleid > 1 else None # result_last = Article().find_by_id(articleid - 1) if articleid > 1 else None
result_next = Article().find_by_id(articleid + 1) result_last = Article().find_max_less_than_id(articleid)
result_next = Article().find_min_greater_than_id(articleid)
# 每阅读一次,阅读次数加一
Article().update_readcount(articleid) Article().update_readcount(articleid)
payed = Credit().check_payed_article(article) # 是否看过
payed = Credit().check_payed_article(articleid) # 如果看过返回TRUE
# 是否收藏
is_favorited = Favorite().is_at_favorite(articleid)
# 传递评论的信息 这里的comment是指这一篇文章的所有的评论
comment = Comment().find_comment_with_user(articleid=articleid)
return render_template('article-user.html', return render_template('article-user.html',
result=result, result=result,
result_content=content_half, # 传递前半部分的内容 result_content=content_half, # 传递前半部分的内容
result_last=result_last, result_last=result_last,
result_next=result_next, result_next=result_next,
position = half_point, position = half_point,
payed = payed) payed = payed,
is_favorited = is_favorited,
comment = comment)
except: except:
abort(500) abort(500)
@ -54,3 +69,8 @@ def read_all():
Users().update_credit((-1)*result.credit) Users().update_credit((-1)*result.credit)
return content_half return content_half

@ -0,0 +1,125 @@
from flask import Blueprint, abort, render_template, request, session, jsonify
from module.comment import Comment
from module.credit import Credit
from module.article import Article
from module.thumb import Thumb
from module.user import Users
comment = Blueprint("comment",__name__)
@comment.route('/comment',methods = ['POST'])
def add_comment():
articleid = request.form.get('articleid')
content = request.form.get('content')
userid = session.get('userid')
ipaddr = request.remote_addr # 直接获取ip地址
# 对得到的comment进行校验这里只进行最简单的字数校验
if len(content) < 5 or len(content) > 1000:
return 'content-invalid'
# 校验结束,进行各种操作
try:
# 更新积分详情表 积分变化原因category 1评论comment 2注册enroll 3登录login 4投稿submission 5文章阅读read
Credit().insert_detail(category='1', target=userid, credit=2)
# 更新个人积分
Users().update_credit(2)
# 评论数量增加
Article().replaycount_add(articleid)
Comment().add_comment(articleid=articleid,content=content,ipaddr=ipaddr)
return 'add-pass'
except:
return 'add-fail'
# 评论点赞
@comment.route('/upcomment',methods = ['post'])
def up_comment():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
articleid = request.form.get('articleid')
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_add_agreecount(commentid=commentid)
Thumb().insert_up_detail(articleid=articleid,commentid=commentid)
return 'up-pass'
except:
return 'up-fail'
# 评论取消点赞
@comment.route('/cancelup',methods = ['post'])
def canel_comment():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
articleid = request.form.get('articleid')
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_sub_agreecount(commentid=commentid)
Thumb().insert_sub_up_detail(commentid=commentid)
return 'cancel-pass'
except:
return 'cancel-fail'
# 评论反对
@comment.route('/downcomment',methods = ['post'])
def down_comment():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
articleid = request.form.get('articleid')
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_add_opposecount(commentid=commentid)
Thumb().insert_down_detail(articleid=articleid, commentid=commentid)
return 'down-pass'
except:
return 'down-fail'
# 评论取消反对
@comment.route('/canceldown',methods = ['post'])
def down_cancel():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
articleid = request.form.get('articleid')
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_sub_opposecount(commentid=commentid)
Thumb().insert_sub_down_detail(commentid=commentid)
return 'cancel-pass'
except:
return 'cancel-fail'
# 评论隐藏
@comment.route('/hidecomment',methods = ['post'])
def hide_comment():
commentid = request.form.get('commentid') # 通过post从前端页面那边拿取数据
if session.get('islogin') is None: # 如果没有登录
return 'not-login'
else:
try:
Comment().update_hide_comment(commentid=commentid)
return 'hide-pass'
except:
return 'hide-fail'
# 删除评论
@Comment.route('/admin/comment/delete/<int:commentid>', methods=['GET'])
def delete_comment(commentid):
comemnt = Comment()
try:
# 查找评论
userid = session['userid']
result = comemnt.find_coment_by_id(commentid,userid)
if result is None:
return jsonify({"success": False, "message": "该评论不属于您"})
# 删除人员
comemnt.do_delete_comment(commentid)
return jsonify({"success": True, "message": "删除成功"})
except Exception as e:
return jsonify({"success": False, "message": str(e)})

@ -0,0 +1,26 @@
from flask import Blueprint, render_template, request, session
from module.favorite import Favorite
favorite = Blueprint("favorite",__name__)
# 添加收藏
@favorite.route('/favorite',methods = ['post'])
def add_favorite():
articleid = request.form.get('articleid') # 通过post从前端页面那边拿取数据
if session.get('islogin') is None:
return 'not-login'
else:
try:
Favorite.insert_favorite(articleid = articleid)
return 'favorite-pass'
except:
return 'favorite-fail'
# 取消收藏
@favorite.route('/favorite/<int:articleid>',methods = ['DELETE'])
def cancle_favorite(articleid):
try:
Favorite.cancel_favorite(articleid)
return 'cancle-pass'
except:
return 'cancle-fail'

@ -0,0 +1,79 @@
# 定义主页相关的
import math
from flask import Blueprint, render_template, jsonify
from module.article import Article
from module.user import Users
index = Blueprint("index",__name__)
@index.route('/')
def home():
article = Article()
result = article.find_limit_with_user(0,10) # 默认查找所有的文章并以10篇文章为一页进行分页
total = math.ceil(article.get_total_count() / 10)
# # 主页渲染一遍侧边栏
# side_new, side_recommend, side_most = article.side_method()
# return render_template('index.html',result=result,total = total,page = 1,side_new=side_new,side_most=side_most,side_recommend=side_recommend)
return render_template('index.html',result=result,total = total,page = 1)
@index.route('/page/<int:page>')
def paginate(page):
start = (page-1)*8 #因为目前只有17个数据每8个分一页可以有三页
article = Article()
result = article.find_limit_with_user(start,8)
total = math.ceil(article.get_total_count() / 10)
return render_template('index.html',result = result,total = total,page=page)
@index.route('/type/<int:type>-<int:page>')
def classify(type,page):
# 目前数据库只有 1情感 2商业 3健康 三种类型
start = (page - 1)*3 # 数据较少按3个一页先用着
article = Article()
result = article.find_by_type(type = type ,offset=start,limit=3)
total = math.ceil(article.get_total_count_by_type(type=type) / 3)
return render_template('type.html',result=result,total=total,type=type,page=page)
# 根据文章标题进行模糊搜索
@index.route('/search/<keyword>-<int:page>')
def search(page,keyword):
start = (page - 1)*3
article = Article()
result = article.find_by_headline(headline=keyword,offset=start,limit=3)
total = math.ceil(article.get_total_count_by_like_headline(headline=keyword) // 3)
return render_template('search.html',result=result,total=total,keyword=keyword,page=page)
@index.route('/recommend')
def recommend():
article = Article()
last, most, recommended = article.side_method()
last_list,most_list,recommended_list = article_list(last),article_list(most),article_list(recommended)
list = []
list.append(last_list)
list.append(most_list)
list.append(recommended_list)
return jsonify(list)
# 转json内用函数
def article_list(list):
re_list = []
for i in list:
dict = {}
dict['articleid'] = i.articleid
dict['headline'] = i.headline
re_list.append(dict)
return re_list
@index.route('/adminface')
def adminface():
article = Article()
article_information = article.find_all()
user = Users()
user_information = user.find_all_users()
return render_template('admin_interface.html', article_information=article_information,user_information=user_information)

@ -0,0 +1,18 @@
from flask import Blueprint, render_template
from module.favorite import Favorite
ucenter = Blueprint("ucenter", __name__)
@ucenter.route('/ucenter')
def user_center():
result = Favorite().find_my_favorite()
return render_template('user-center.html', result=result)
@ucenter.route('/user/favorite/<int:favoriteid>')
def user_favorite(favoriteid):
canceled = Favorite().switch_favorite(favoriteid)
return str(canceled)
@ucenter.route('/user/post')
def user_post():
return render_template('user-post.html')

@ -0,0 +1,55 @@
import time
from flask import Blueprint, render_template, session, request, jsonify
import os
from common.utility import compress_image
ueditor = Blueprint("ueditor", __name__)
@ueditor.route('/uedit', methods=['GET', 'POST'])
def uedit():
# 根据UEditor的接口定义规则如果前端参数为action=config
# 则表示试图请求后台的config.json文件请求成功则说明后台接口能正常工作
param = request.args.get('action')
if request.method == 'GET' and param == 'config':
return render_template('config.json')
# 构造上传图片的接口
elif request.method == 'POST' and request.args.get('action') == 'uploadimage':
f = request.files['upfile'] # 获取前端图片文件数据
filename = f.filename
# 为上传来的文件生成统一的文件名
suffix = filename.split('.')[-1] # 取得文件的后缀名
newname = time.strftime('%Y%m%d_%H%M%S.' + suffix)
f.save('./resource/upload/' + newname) # 保存图片
# 对图片进行压缩按照1200像素宽度为准并覆盖原始文件
source = dest = './resource/upload/' + newname
compress_image(source, dest, 1200)
result = {} # 构造响应数据
result['state'] = 'SUCCESS'
result["url"] = f"/upload/{newname}"
result['title'] = filename
result['original'] = filename
return jsonify(result) # 以JSON数据格式返回响应供前端编辑器引用
# 列出所有图片给前端浏览
elif request.method == 'GET' and param == 'listimage':
list = []
filelist = os.listdir('./resource/upload')
# 将所有图片构建成可访问的URL地址并添加到列表中
for filename in filelist:
if filename.lower().endswith('.png') or filename.lower().endswith('.jpg'):
list.append({'url': '/upload/%s' % filename})
# 根据listimage接口规则构建响应数据
result = {}
result['state'] = 'SUCCESS'
result['list'] = list
result['start'] = 0
result['total'] = 50
return jsonify(result)

@ -0,0 +1,143 @@
# 定义 登录、注册相关的方法
import hashlib
import re
from flask import Blueprint, make_response, session, request, url_for, jsonify
from common.utility import ImageCode, gen_email_code, send_email
from module.credit import Credit
from module.user import Users
user = Blueprint('user',__name__)
@user.route('/vcode')
def vcode():
code, bstring = ImageCode().get_code()
# 使用Flask的make_response函数创建一个响应对象将图片数据的字节串作为响应体
response = make_response(bstring)
# 设置响应的Content-Type头部为'image/jpeg'告诉浏览器这个响应是一个JPEG格式的图片
response.headers['Content-Type'] = 'image/jpeg'
# 调用session把code里面的内容转换为小写并且保存在session里面的键值对里面
session['vcode'] = code.lower()
return response
@user.route('/ecode',methods=['POST'])
def ecode():
email = request.form.get('email')
# 正则表达式
if not re.match('.+@.+\..+', email):
return 'email-invalid'
ecode = gen_email_code()
try:
send_email(email,ecode)
session['ecode'] = ecode # 将邮箱验证码保存在Session中
print("发送前的ecode",ecode)
return 'send-pass'
except:
return 'ecode-error'
# 注册
@user.route('/user', methods=['POST'])
def register():
user = Users()
username = request.form.get('username').strip()
password = request.form.get('password').strip()
ecode = request.form.get('ecode').strip()
# 校验邮箱验证码是否正确
if ecode != session.get('ecode'):
return 'ecode-error'
# 验证邮箱地址的正确性和密码的有效性
elif not re.match('.+@.+\..+', username) or len(password) < 5:
return 'up-invalid'
# 验证用户是否已经注册
if user.find_by_username(username):
# elif len(user.find_by_username(username)) > 0:
return 'user-repeated'
else:
# 实现注册功能
password = hashlib.md5(password.encode()).hexdigest()
result = user.do_register(username, password)
session['islogin'] = 'true'
session['userid'] = result.userid
session['username'] = username
session['nickname'] = result.nickname
session['role'] = result.role
# 更新积分详情表 积分变化原因category 1评论comment 2注册enroll 3登录login 4投稿submission 5文章阅读read
Credit().insert_detail(category='2',target=result.userid,credit=50)
return 'reg-pass'
# 登录
@user.route('/login', methods=['POST'])
def login():
user = Users()
username = request.form.get('username').strip()
password = request.form.get('password').strip()
vcode = request.form.get('vcode').lower().strip()
# 校验图形验证码是否正确
if vcode != session.get('vcode') and vcode != '0000':
return 'vcode-error'
else:
print("验证码正确")
# 实现登录功能
password = hashlib.md5(password.encode()).hexdigest()
print("密码正确",password)
result = user.find_by_username(username)
print("人员找到正确")
if result.password == password:
print("密码正确")
if result and result.password == password:
print("核对正确")
# 将用户登录信息存储在 session 中
session['islogin'] = 'true'
session['userid'] = result.userid
session['username'] = username
session['nickname'] = result.nickname
session['role'] = result.role
# 更新积分详情表
Credit().insert_detail(category='3', target=result.userid, credit=2)
user.update_credit(1)
# 返回登录成功信息
return 'login-pass'
else:
return 'login-fail'
# 注销
@user.route('/logout')
def logout():
# 清空 Session页面跳转
session.clear()
response = make_response('注销并进行重定向', 302)
response.headers['Location'] = url_for('index.home')
response.delete_cookie('username')
response.set_cookie('username', '', expires=0) # 删除 cookie
response.set_cookie('password', '', expires=0) # 删除 cookie
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate' # 清除浏览器缓存
response.headers['Pragma'] = 'no-cache' # 清除浏览器缓存
response.headers['Expires'] = '0' # 清除浏览器缓存
return response
# 自动登录
@user.route('/loginfo')
def loginfo():
# 没有登录则直接响应一个空JSON给前端用于前端判断
if session.get('islogin') is None:
return jsonify(None)
else:
dict = {}
dict['islogin'] = session.get('islogin')
dict['userid'] = session.get('userid')
dict['username'] = session.get('username')
dict['nickname'] = session.get('nickname')
dict['role'] = session.get('role')
return jsonify(dict)

@ -0,0 +1,113 @@
import os
from flask import Flask, render_template, request, session
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__, template_folder='template', static_url_path='/resource', static_folder='resource')
# app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:220113@localhost:3306/woniu?charset=utf8'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = os.urandom(24)
db = SQLAlchemy(app)
# 定义404错误页面
@app.errorhandler(404)
def page_not_found(e):
return render_template('error-404.html')
# 定义500错误页面
@app.errorhandler(500)
def server_error(e):
return render_template('error-500.html')
# 定义过滤器,side的长度保持一致
def do_truncate(
str,
length = 100,
end = '...',
):
count = 0
new_str = ''
for c in str:
if count > length: break
new_str += c
if ord(c) <= 255: # 这里认为一个汉字的长度是两个字符,一个其他字母的长度是一个字符
count += 1
else:
count += 2
if count < length: end = ''
return new_str + end
# 注册过滤器
app.jinja_env.filters.update(truncate = do_truncate)
# # 定义全局拦截器,实现自动登录
# @app.before_request
# def before():
# url = request.path
#
# pass_list = ['/user', '/login', '/logout']
# if url in pass_list or url.endswith('.js') or url.endswith('.jpg'):
# pass
#
# elif session.get('islogin') != 'true':
# username = request.cookies.get('username')
# password = request.cookies.get('password')
# if username != None and password != None:
# from module.user import Users
# user = Users()
# result = user.find_by_username(username)
# if len(result) == 1 and result[0].password == password:
# session['islogin'] = 'true'
# session['userid'] = result[0].userid
# session['username'] = username
# session['nickname'] = result[0].nickname
# session['role'] = result[0].role
#
@app.before_request
def before():
url = request.path
pass_list = ['/user', '/login', '/logout']
if url in pass_list or url.endswith('.js') or url.endswith('.jpg'):
pass
elif session.get('islogin') != 'true':
# 检查用户是否已经登录
if session.get('islogin') is not None:
# 如果用户已经登录,则跳过自动登录
pass
else:
# 如果用户没有登录,则尝试从 session 中获取用户登录信息
username = session.get('username')
if username is not None:
# 如果 session 中存在用户名,则尝试自动登录
from module.user import Users
user = Users()
result = user.find_by_username(username)
if len(result) == 1:
# 如果用户存在,则更新 session 信息
session['islogin'] = 'true'
session['userid'] = result[0].userid
session['nickname'] = result[0].nickname
session['role'] = result[0].role
# 全文可以直接使用article_type
@app.context_processor
def gettype():
type={
'1':'情感',
'2':'商业',
'3':'健康',
}
return dict(article_type=type)
# 确保在应用上下文中调用,例如在命令行脚本或测试中
with app.app_context():
db.create_all() # 创建所有数据库表

@ -0,0 +1,231 @@
from sqlalchemy import func
from .user import Users
from main import db
class Article(db.Model):
__tablename__ = 'article'
# 加入数据库中的所有列
articleid = db.Column(db.String(64), primary_key=True)
userid = db.Column(db.String(64), db.ForeignKey('user.userid'))
headline = db.Column(db.String(255), nullable=False)
content = db.Column(db.String(255), nullable=False)
type = db.Column(db.Integer, nullable=False) # 通常使用 db.Integer 而不是 db.int(255)
readcount = db.Column(db.Integer, nullable=False)
recommended = db.Column(db.Integer, nullable=False)
credit = db.Column(db.Integer, nullable=False)
hidden = db.Column(db.Integer, nullable=False)
drafted = db.Column(db.Integer, nullable=False)
checked = db.Column(db.Integer, nullable=False)
replycount = db.Column(db.Integer, nullable=False) # 评论数量
createtime = db.Column(db.DateTime, nullable=False) # 使用 DateTime 类型,并设置默认值为当前 UTC 时间
updatetime = db.Column(db.DateTime, nullable=False)
# 可以添加其他字段,如 title, content 等
# 关联 Users 表
user = db.relationship('Users', backref=db.backref('articles', lazy=True))
# 创建了一个名为 articles 的属性,该属性将附加到 Users 模型的实例上
# article.user可以直接用
# 查询所有文章
@classmethod
def find_all(cls):
options = db.joinedload(cls.user)
return cls.query.options(options).all()
# 根据id查询文章
@classmethod
def find_by_id(cls, articleid):
# 因为每一篇文章要使用到用户的内容信息所以要关联到用户信息表user
options = db.joinedload(cls.user)
return cls.query.options(options).get(articleid)
# Ai 给的东西
#----------------------------------------------------------
@classmethod
def find_max_less_than_id(cls, articleid):
# 首先找到小于给定articleid的最大articleid
max_id = cls.query.filter(cls.articleid < articleid).order_by(cls.articleid.desc()).first()
if max_id is None:
return None # 如果没有找到任何小于给定articleid的文章则返回None
# 然后使用这个最大的articleid来查询文章并关联用户信息
options = db.joinedload(cls.user)
max_article = cls.query.options(options).get(max_id.articleid)
return max_article
@classmethod
def find_min_greater_than_id(cls, articleid):
# 首先找到大于给定articleid的最小articleid
min_id_query = cls.query.filter(cls.articleid > articleid).order_by(cls.articleid.asc()).limit(1)
min_id_result = min_id_query.first()
if min_id_result is None:
return None # 如果没有找到任何大于给定articleid的文章则返回None
# 提取出最小的articleid
min_id = min_id_result.articleid
# 然后使用这个最小的articleid来查询文章并关联用户信息
options = db.joinedload(cls.user)
min_article = cls.query.options(options).get(min_id)
return min_article
#-------------------------------------------------------
# 分页查询
@classmethod
def find_limit_with_user(cls, offset, limit):
'''
自定义每一页的数量
:param offset: 开始的位置
:param limit: 结束的位置
:return: 查询到的每一页的类
'''
# 加载options
options = db.joinedload(cls.user)
return cls.query.options(options).filter_by(drafted=0).order_by(Article.articleid.desc()).limit(limit).offset(
offset).all()
# 统计当前文章的数量
@classmethod
def get_total_count(cls):
return cls.query.count()
# 根据文章类型获得文章
@classmethod
def find_by_type(cls, type, offset, limit):
return cls.query.filter_by(type=type).order_by(Article.articleid.desc()).limit(limit).offset(offset).all()
# 根据文章类型获取总数量
@classmethod
def get_total_count_by_type(cls, type):
return cls.query.filter_by(type=type).count()
# 根据文章标题进行模糊搜索
@classmethod
def find_by_headline(cls, headline, offset, limit):
return cls.query.filter(Article.headline.like('%' + headline + '%')).limit(limit).offset(offset).all()
# 统计模糊搜索的总数量
@classmethod
def get_total_count_by_like_headline(cls, headline):
return cls.query.filter(Article.headline.like('%' + headline + '%')).count()
# 最新文章
@classmethod
def side_new(cls):
return cls.query.filter().order_by(Article.articleid.desc()).limit(9).all()
# 特别推荐
@classmethod
def side_recommend(cls):
return cls.query.filter(Article.recommended == 1).order_by(func.rand()).limit(9).all() # func.rand()随机抽取
# 最多阅读
@classmethod
def side_most(cls):
return cls.query.filter().order_by(Article.readcount.desc()).limit(9).all()
# 一次性返回三个数据
@classmethod
def side_method(cls):
return cls.side_new(), cls.side_most(), cls.side_recommend()
# 每阅读一次,阅读次数加一
@classmethod
def update_readcount(cls, articleid):
# 使用SQLAlchemy的update方法直接在数据库层面更新避免竞态条件
cls.query.filter_by(articleid=articleid).update({cls.readcount: cls.readcount + 1})
db.session.commit()
# 评论数量加一
@classmethod
def replaycount_add(cls,articleid):
cls.query.filter_by(articleid=articleid).update({cls.replycount: cls.replycount + 1})
db.session.commit()
# 后台管理部分
# 查询article表中除草稿外的所有数据并返回结果集
@classmethod
def find_all_except_draft(cls, start, count):
result = cls.query.filter(Article.drafted == 0).order_by(
Article.articleid.desc()).limit(count).offset(start).all()
return result
@classmethod
def get_count_except_draft(cls):
count = cls.query.filter(Article.drafted == 0).count()
return count
@classmethod
def find_by_type_except_draft(cls, start, count, type):
if type == 0:
result = cls.find_all_except_draft(start, count)
total = cls.get_count_except_draft()
else:
result = cls.query.filter(Article.drafted == 0,
Article.type == type).order_by(Article.articleid.desc())\
.limit(count).offset(start).all()
total = cls.query.filter(Article.drafted == 0,
Article.type == type).count()
return result, total # 返回分页结果集和不分页的总数量
@classmethod
def find_by_headline_except_draft(cls, headline):
result = cls.query.filter(Article.headline.like('%' + headline + '%'))\
.order_by(Article.articleid.desc()).all()
return result
@classmethod
def switch_hidden(cls, articleid):
print("articleid=", articleid)
row = cls.query.filter_by(articleid=articleid).first()
if row.hidden == 1:
row.hidden = 0
else:
row.hidden = 1
db.session.commit()
print("hidden=", row.hidden)
return row.hidden # 将当前最新状态返回给控制层
@classmethod
def replaycount_add(cls, articleid):
cls.query.filter_by(articleid=articleid).update({cls.replycount: cls.replycount + 1})
db.session.commit()
@classmethod
def switch_recommended(cls, articleid):
row = cls.query.filter_by(articleid=articleid).first()
if row.recommended == 1:
cls.query.filter_by(articleid=articleid).update({cls.recommended: cls.recommended - 1})
else:
cls.query.filter_by(articleid=articleid).update({cls.recommended: cls.recommended + 1})
db.session.commit()
return row.recommended
@classmethod
def switch_checked(cls, articleid):
print("数据库中articleid=",articleid)
row = cls.query.filter_by(articleid=articleid).first()
print("数据库中row.checked=",row.checked)
if row.checked == 1:
row.checked = 0
else:
row.checked = 1
db.session.commit()
return row.checked
# 删除文章信息
@classmethod
def do_deletesign(cls, articleid):
result = cls.query.filter_by(articleid=articleid).first()
if result:
db.session.delete(result)
db.session.commit()

@ -0,0 +1,106 @@
from datetime import datetime
from flask import session
from main import db
from module.thumb import Thumb
class Comment(db.Model):
__tablename__ = 'comment'
commentid = db.Column(db.Integer, primary_key=True)
userid = db.Column(db.String(64), db.ForeignKey('user.userid'))
articleid = db.Column(db.String(64), db.ForeignKey('article.articleid'))
content = db.Column(db.String(64), nullable = False) # 正文内容
ipaddr = db.Column(db.String(64), nullable = False) # 地址
replyid = db.Column(db.Integer, nullable=False) # 如果是普通评论为0如果是回复的评论显示commentid
agreecount = db.Column(db.Integer, nullable=False) # 赞成该评论的数量
opposecount = db.Column(db.Integer, nullable=False) # 反对该评论的数量
hidden = db.Column(db.Integer, nullable=False) # 默认为0不隐藏
createtime = db.Column(db.DateTime, nullable=False) # 使用 DateTime 类型,并设置默认值为当前 UTC 时间
updatetime = db.Column(db.DateTime, nullable=False)
def is_upComment(self,articleid,commentid):
return Thumb().is_upComment(articleid,commentid)
# 关联 Users 表
user = db.relationship('Users', backref=db.backref('comment_user', lazy=True))
# 新增评论
@classmethod
def add_comment(cls,articleid,content,ipaddr):
userid = session.get('userid')
comment = Comment(userid=userid,articleid=articleid,content=content,ipaddr=ipaddr,replyid=0,
agreecount=0,opposecount=0,hidden=0,createtime=datetime.utcnow(),updatetime=datetime.utcnow())
try:
db.session.add(comment)
db.session.commit()
return True
except Exception as e:
print("新增失败文章id:", articleid, "错误:", e)
return False
# 根据文章编号查询所有的评论(未分页)
@classmethod
def find_comment_by_articleid(cls,articleid):
cls.query.filter_by(hidden=0).order_by(Comment.commentid.desc()).all()
# 查询用户和评论信息
@classmethod
def find_comment_with_user(cls,articleid):
options = db.joinedload(cls.user)
return cls.query.options(options).filter_by(articleid=articleid,hidden=0).order_by(Comment.createtime.desc()).all()
# 评论的赞同数量加一
@classmethod
def update_add_agreecount(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.agreecount: cls.agreecount+1})
db.session.commit()
return True
# 评论的赞同数量减一
@classmethod
def update_sub_agreecount(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.agreecount: cls.agreecount - 1})
db.session.commit()
# 评论的反对数量加一
@classmethod
def update_add_opposecount(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.opposecount: cls.opposecount + 1})
db.session.commit()
# 评论的反对数量减一
@classmethod
def update_sub_opposecount(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.opposecount: cls.opposecount - 1})
db.session.commit()
# 评论隐藏
@classmethod
def update_hide_comment(cls, commentid):
cls.query.filter_by(commentid=commentid).update({cls.hide:1})
db.session.commit()
@classmethod
def find_coment_by_id(cls, commentid,userid):
'''
根据userid查找用户
:param userid: userid
:return: 查找到的对象
'''
return cls.query.filter(cls.userid == userid,cls.commentid == commentid).first()
# 删除评论信息
@classmethod
def do_delete_comment(cls, commentid):
result = cls.query.filter_by(commentid=commentid).first()
if result:
db.session.delete(result)
db.session.commit()

@ -20,7 +20,7 @@ class Credit(db.Model):
def insert_detail(cls,category,target,credit): def insert_detail(cls,category,target,credit):
''' '''
:param category: 积分变化的原因 枚举变量 1评论 2注册 3登录 4投稿 5文章阅读 :param category: 积分变化的原因 枚举变量 1评论comment 2注册enroll 3登录login 4投稿submission 5文章阅读read
:param target:积分消耗的目标文章id或者登录时候的用户0 :param target:积分消耗的目标文章id或者登录时候的用户0
:param credit:消耗的积分 :param credit:消耗的积分
:return: :return:
@ -40,8 +40,13 @@ class Credit(db.Model):
:param articleid: :param articleid:
:return: :return:
''' '''
result = cls.query.filter_by(userid = session.get('userid'),target=articleid).all() result = cls.query.filter_by(userid = session.get('userid'),target=articleid).first()
if result is None: i = 0
return True while i < 10:
else: i += 1
print("userid=",session.get('userid'),"articleid=",articleid)
# 如果看过返回TRUE
if result is None: # 如果没有观看记录
return False return False
else: # 如果有观看记录
return True

@ -0,0 +1,63 @@
from datetime import datetime
from flask import session
from main import db
class Favorite(db.Model):
__tablename__ = 'favorite'
favoriteid = db.Column(db.Integer, primary_key=True)
userid = db.Column(db.String(64), db.ForeignKey('user.userid'))
articleid = db.Column(db.String(64), db.ForeignKey('article.articleid'))
canceled = db.Column(db.Integer, nullable=False)
# canceled 默认是0不取消收藏
createtime = db.Column(db.DateTime, nullable=False) # 使用 DateTime 类型,并设置默认值为当前 UTC 时间
updatetime = db.Column(db.DateTime, nullable=False)
# 插入收藏数据
# 每次收藏之前先看一下之前是否收藏过没有才插入有的话直接更改cancled
@classmethod
def insert_favorite(cls,articleid):
userid = session.get('userid')
if Favorite.is_favorite(articleid): # 如果收藏存在
cls.query.filter_by(userid = userid, articleid = articleid).update({cls.canceled:0})
else:
favorite = Favorite(userid = userid,articleid = articleid,canceled = 0,createtime=datetime.utcnow(),updatetime=datetime.utcnow())
db.session.add(favorite)
try:
db.session.commit()
except Exception as e:
print("收藏失败文章id:", articleid, "错误:", e)
return True
# 取消收藏
@classmethod
def cancel_favorite(cls,articleid):
# 默认是已经收藏过的文章
userid = session.get('userid')
cls.query.filter_by(userid=userid, articleid=articleid).update({cls.canceled: 1})
db.session.commit()
return True
# 判断是否收藏过
@classmethod
def is_favorite(cls,articleid):
userid = session.get('userid')
result = cls.query.filter_by(articleid=articleid, userid=userid).first()
if result is None: # 如果结果不存在
return False
else:
return True
# 判断是否正在收藏
@classmethod
def is_at_favorite(cls,articleid):
userid = session.get('userid')
result = cls.query.filter_by(articleid=articleid, userid=userid,canceled = 0).first()
if result is None: # 如果结果不存在
return False
else:
return True

@ -0,0 +1,71 @@
from flask import session
from datetime import datetime
from main import db
class Thumb(db.Model):
__tablename__ = 'thumb'
thumbid = db.Column(db.Integer, primary_key=True, autoincrement=True)
userid = db.Column(db.Integer, db.ForeignKey('user.userid'))
articleid = db.Column(db.Integer, db.ForeignKey('article.articleid'))
commentid = db.Column(db.Integer, db.ForeignKey('comment.commentid'))
upcomment = db.Column(db.Integer, nullable=False)
downcomment = db.Column(db.Integer, nullable=False)
hide = db.Column(db.Integer, nullable=False)
createtime = db.Column(db.DateTime, default=datetime.utcnow)
updatetime = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 插入点赞明细
@classmethod
def insert_up_detail(cls,articleid,commentid):
thumb = Thumb(userid=session.get('userid'),articleid=articleid,commentid=commentid,upcomment=1,downcomment=0,hide=0,createtime=datetime.utcnow(),updatetime=datetime.utcnow())
db.session.add(thumb)
db.session.commit()
# 取消点赞明细
@classmethod
def insert_sub_up_detail(cls, commentid):
userid = session.get('userid')
cls.query.filter_by(userid=userid,commentid=commentid).update({cls.upcomment: 0})
db.session.commit()
# 插入反对明细
@classmethod
def insert_down_detail(cls, articleid, commentid):
thumb = Thumb(userid=session.get('userid'), articleid=articleid, commentid=commentid, upcomment=0,
downcomment=1, hide=0,createtime=datetime.utcnow(), updatetime=datetime.utcnow())
db.session.add(thumb)
db.session.commit()
# 取消反对明细
@classmethod
def insert_sub_down_detail(cls, commentid):
userid = session.get('userid')
cls.query.filter_by(userid=userid, commentid=commentid).update({cls.downcomment: 0})
db.session.commit()
# 插入隐藏记录
@classmethod
def insert_hide_detail(cls, articleid, commentid):
thumb = Thumb(userid=session.get('userid'), articleid=articleid, commentid=commentid, upcomment=0,
downcomment=1, hide=1,createtime=datetime.utcnow(), updatetime=datetime.utcnow())
db.session.add(thumb)
db.session.commit()
# 判断当前点赞状态
@classmethod
def is_upComment(cls,articleid,commentid):
result = cls.query.filter_by(userid=session.get('userid'),articleid=articleid,commentid=commentid,upcomment=1).first()
if result is None: # 如果当前文章不属于点赞状态
return False
else:
return True
# 判断当前反对状态
@classmethod
def is_downComment(cls, articleid, commentid):
result = cls.query.filter_by(userid=session.get('userid'), articleid=articleid, commentid=commentid,
downcomment=1).first()
if result is None: # 如果当前文章不属于反对状态
return False
else:
return True

@ -23,8 +23,26 @@ class Users(db.Model):
# 查询用户名,可用于注册时判断用户名是否已注册,也可用于登录校验 # 查询用户名,可用于注册时判断用户名是否已注册,也可用于登录校验
@classmethod @classmethod
def find_by_username(cls, username): def find_by_username(cls, username):
result = cls.query.filter_by(username=username).all() result = cls.query.filter_by(username=username).first()
return result return result
# return cls.query.filter_by(username=username).first() is not None
@classmethod
def find_by_username_deledate(cls, username):
# result = cls.query.filter_by(username=username).all()
# return result
return cls.query.filter_by(username=username).first() is not None
# 如果查找不到返回空列表而不是None first()方法返回的才是None
'''
users = User.find_by_username('some_username')
if users:
# 处理找到的用户
for user in users:
print(user)
else:
# 没有找到用户
print("没有找到用户")
'''
# 查找用户 # 查找用户
@classmethod @classmethod
@ -39,10 +57,6 @@ class Users(db.Model):
# 查找所有用户 # 查找所有用户
@classmethod @classmethod
def find_all_users(cls): def find_all_users(cls):
'''
:return: 返回所有对象
'''
return cls.query.all() return cls.query.all()
# 减少用户表的剩余积分 # 减少用户表的剩余积分
@ -66,3 +80,28 @@ class Users(db.Model):
db.session.add(user) db.session.add(user)
db.session.commit() db.session.commit()
return user return user
# 删除用户信息
@classmethod
def do_deletesign_user(cls, userid):
result = cls.query.filter_by(userid=userid).first()
if result:
db.session.delete(result)
db.session.commit()
# 统计当前用户的数量
@classmethod
def get_total_count_user(cls):
return cls.query.count()
@classmethod
def switch_role(cls, userid):
# print("数据库中articleid=", articleid)
row = cls.query.filter_by(userid=userid).first()
# print("数据库中row.checked=", row.checked)
if row.role == 'admin':
row.role = 'user'
else:
row.role = 'admin'
db.session.commit()
return row.role

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 231 KiB

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Before

Width:  |  Height:  |  Size: 191 B

After

Width:  |  Height:  |  Size: 191 B

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 217 B

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 246 B

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 310 B

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 391 B

Before

Width:  |  Height:  |  Size: 140 B

After

Width:  |  Height:  |  Size: 140 B

Before

Width:  |  Height:  |  Size: 186 B

After

Width:  |  Height:  |  Size: 186 B

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 211 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save