diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 7003f78..a61ba5d 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,12 +2,24 @@ - - - + + + + + + + + + + + - + + + + + - @@ -224,6 +246,13 @@ + + + + + + + @@ -237,11 +266,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -262,6 +343,13 @@ + + + + + + + @@ -276,7 +364,7 @@ - + @@ -287,11 +375,11 @@ + + + - - - - + @@ -379,7 +467,14 @@ @@ -392,10 +487,9 @@ - - + - + @@ -410,7 +504,7 @@ - + @@ -434,47 +528,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -530,64 +583,21 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + + + @@ -674,36 +684,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -720,7 +700,7 @@ - + @@ -728,30 +708,121 @@ - + - - + + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + @@ -760,34 +831,61 @@ - + + - + - - - - - - - - - + + - + - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/com b/com new file mode 100644 index 0000000..8dcd609 --- /dev/null +++ b/com @@ -0,0 +1,22 @@ +# coding: utf-8 +from sqlalchemy import BigInteger, Column, DateTime, Integer, String, Text +from sqlalchemy.schema import FetchedValue +from sqlalchemy.ext.declarative import declarative_base + + +Base = declarative_base() +metadata = Base.metadata + + +class AppAccessLog(Base): + __tablename__ = 'app_access_log' + + id = Column(Integer, primary_key=True) + uid = Column(BigInteger, nullable=False, index=True, server_default=FetchedValue()) + referer_url = Column(String(255), nullable=False, server_default=FetchedValue()) + target_url = Column(String(255), nullable=False, server_default=FetchedValue()) + query_params = Column(Text, nullable=False) + ua = Column(String(255), nullable=False, server_default=FetchedValue()) + ip = Column(String(32), nullable=False, server_default=FetchedValue()) + note = Column(String(1000), nullable=False, server_default=FetchedValue()) + created_time = Column(DateTime, nullable=False, server_default=FetchedValue()) diff --git a/common/libs/Helper.py b/common/libs/Helper.py index acb2d5c..ef1a4ba 100644 --- a/common/libs/Helper.py +++ b/common/libs/Helper.py @@ -57,4 +57,11 @@ def iPagination( params ): def ops_render( template,context = {} ): if 'current_user' in g: context['current_user'] = g.current_user - return render_template( template,**context ) \ No newline at end of file + return render_template( template,**context ) + +''' +获取当前时间 +''' +def getCurrentDate( format = "%Y-%m-%d %H:%M:%S"): + #return datetime.datetime.now().strftime( format ) + return datetime.datetime.now() diff --git a/common/libs/LogService.py b/common/libs/LogService.py new file mode 100644 index 0000000..fb00299 --- /dev/null +++ b/common/libs/LogService.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +from flask import request,g +from application import app,db +import json +from common.libs.Helper import getCurrentDate +from common.models.log.AppAccessLog import AppAccessLog +from common.models.log.AppErrorLog import AppErrorLog + +class LogService(): + @staticmethod + def addAccessLog(): + target = AppAccessLog() + target.target_url = request.url + target.referer_url = request.referrer + target.ip = request.remote_addr + target.query_params = json.dumps( request.values.to_dict() ) + if 'current_user' in g and g.current_user is not None: + target.uid = g.current_user.uid + target.ua = request.headers.get( "User-Agent" ) + target.created_time = getCurrentDate() + db.session.add( target ) + db.session.commit( ) + return True + + @staticmethod + def addErrorLog( content ): + if 'favicon.ico' in request.url: + return + target = AppErrorLog() + target.target_url = request.url + target.referer_url = request.referrer + target.query_params = json.dumps(request.values.to_dict()) + target.content = content + target.created_time = getCurrentDate() + db.session.add(target) + db.session.commit() + return True \ No newline at end of file diff --git a/common/libs/UrlManager.py b/common/libs/UrlManager.py index 036c942..b165778 100644 --- a/common/libs/UrlManager.py +++ b/common/libs/UrlManager.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- - +import time +from application import app class UrlManager(object): def __init__(self): pass @@ -10,6 +11,7 @@ class UrlManager(object): @staticmethod def buildStaticUrl(path): - ver = "%s"%( 22222222 ) + release_version = app.config.get('RELEASE_VERSION') + ver = "%s" % (int(time.time())) if not release_version else release_version path = "/static" + path + "?ver=" + ver return UrlManager.buildUrl( path ) \ No newline at end of file diff --git a/common/models/log/AppAccessLog.py b/common/models/log/AppAccessLog.py index 68be444..bec6000 100644 --- a/common/models/log/AppAccessLog.py +++ b/common/models/log/AppAccessLog.py @@ -1,8 +1,7 @@ # coding: utf-8 from sqlalchemy import BigInteger, Column, DateTime, Integer, String, Text from sqlalchemy.schema import FetchedValue -from application import db - +from application import db class AppAccessLog(db.Model): diff --git a/common/models/log/AppErrorLog.py b/common/models/log/AppErrorLog.py index 84ef848..8d6b1e2 100644 --- a/common/models/log/AppErrorLog.py +++ b/common/models/log/AppErrorLog.py @@ -1,7 +1,11 @@ # coding: utf-8 from sqlalchemy import Column, DateTime, Integer, String, Text from sqlalchemy.schema import FetchedValue -from application import db + + + +from application import db + class AppErrorLog(db.Model): diff --git a/config/base_setting.py b/config/base_setting.py index 434d3e8..e25b538 100644 --- a/config/base_setting.py +++ b/config/base_setting.py @@ -16,4 +16,9 @@ IGNORE_CHECK_LOGIN_URLS = [ ] PAGE_SIZE = 50 -PAGE_DISPLAY = 10 \ No newline at end of file +PAGE_DISPLAY = 10 + +STATUS_MAPPING = { + "1":"正常", + "0":"已删除" +} \ No newline at end of file diff --git a/config/local_setting.py b/config/local_setting.py index 7b862fc..ef1eb0f 100644 --- a/config/local_setting.py +++ b/config/local_setting.py @@ -5,3 +5,4 @@ SQLALCHEMY_ECHO = True SQLALCHEMY_DATABASE_URI = 'mysql://root:123456@127.0.0.1/food_db' SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ENCODING = "utf8mb4" +# RELEASE_VERSION = "20190730" diff --git a/web/controllers/account/Account.py b/web/controllers/account/Account.py index 36ce28c..a0358ee 100644 --- a/web/controllers/account/Account.py +++ b/web/controllers/account/Account.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- -from flask import Blueprint,request,redirect -from common.libs.Helper import ops_render,iPagination +from flask import Blueprint,request,redirect,jsonify +from common.libs.Helper import ops_render,iPagination,getCurrentDate from common.libs.UrlManager import UrlManager +from common.libs.user.UserService import UserService from common.models.User import User from common.models.log.AppAccessLog import AppAccessLog +from sqlalchemy import or_ route_account = Blueprint( 'account_page',__name__ ) from application import app,db @route_account.route( "/index" ) @@ -13,12 +15,17 @@ def index(): page = int(req['p']) if ('p' in req and req['p']) else 1 query = User.query + if 'mix_kw' in req: + rule = or_( User.nickname.ilike( "%{0}%".format( req['mix_kw'] ) ),User.mobile.ilike( "%{0}%".format( req['mix_kw'] ) )) + query = query.filter( rule ) + if 'status' in req and int( req['status'] ) > -1: + query = query.filter( User.status == int( req['status']) ) page_params = { 'total': query.count(), 'page_size': app.config['PAGE_SIZE'], 'page': page, 'display': app.config['PAGE_DISPLAY'], - 'url': '/account/index' + 'url': request.full_path.replace( "&p={}".format(page),"") } pages = iPagination(page_params) @@ -29,6 +36,8 @@ def index(): resp_data['list'] = list resp_data['pages'] = pages + resp_data['search_con'] = req + resp_data['status_mapping'] = app.config['STATUS_MAPPING'] return ops_render("account/index.html", resp_data) @route_account.route( "/info" ) @@ -48,6 +57,111 @@ def info(): return ops_render("account/info.html", resp_data) -@route_account.route( "/set" ) +@route_account.route( "/set" ,methods=["GET", "POST"]) def set(): - return ops_render( "account/set.html" ) + default_pwd = "******" + if request.method == "GET": + resp_data = {} + req = request.args + uid = int( req.get( "id",0)) + info = None + if uid: + info = User.query.filter_by( uid = uid ).first() + resp_data['info'] = info + return ops_render( "account/set.html",resp_data) + resp = { 'code':200,'msg':'操作成功~~','data':{} } + req = request.values + + id = req['id'] if 'id' in req else 0 + nickname = req['nickname'] if 'nickname' in req else '' + mobile = req['mobile'] if 'mobile' in req else '' + email = req['email'] if 'email' in req else '' + login_name = req['login_name'] if 'login_name' in req else '' + login_pwd = req['login_pwd'] if 'login_pwd' in req else '' + + if nickname is None or len( nickname ) < 1: + resp['code'] = -1 + resp['msg'] = "请输入符合规范的姓名~~" + return jsonify( resp ) + + if mobile is None or len( mobile ) < 1: + resp['code'] = -1 + resp['msg'] = "请输入符合规范的手机号码~~" + return jsonify( resp ) + + if email is None or len( email ) < 1: + resp['code'] = -1 + resp['msg'] = "请输入符合规范的邮箱~~" + return jsonify( resp ) + + if login_name is None or len( login_name ) < 1: + resp['code'] = -1 + resp['msg'] = "请输入符合规范的登录用户名~~" + return jsonify( resp ) + + if login_pwd is None or len( email ) < 6: + resp['code'] = -1 + resp['msg'] = "请输入符合规范的登录密码~~" + return jsonify( resp ) + + has_in = User.query.filter( User.login_name == login_name,User.uid!= id).first() + if has_in: + resp['code'] = -1 + resp['msg'] = "该登录名已存在,请换一个试试~~" + return jsonify(resp) + + user_info = User.query.filter_by(uid=id).first() + if user_info: + model_user = user_info + else: + model_user = User() + model_user.created_time = getCurrentDate() + model_user.login_salt = UserService.geneSalt() + + model_user.nickname = nickname + model_user.mobile = mobile + model_user.email = email + model_user.login_name = login_name + + if login_pwd != default_pwd: + model_user.login_pwd = UserService.genePwd( login_pwd,model_user.login_salt ) + + model_user.created_time = getCurrentDate() + + db.session.add( model_user ) + db.session.commit() + return jsonify(resp) + +@route_account.route("/ops",methods = [ "POST" ]) +def ops(): + resp = {'code': 200, 'msg': '操作成功~~', 'data': {}} + req = request.values + + id = req['id'] if 'id' in req else 0 + act = req['act'] if 'act' in req else '' + if not id : + resp['code'] = -1 + resp['msg'] = "请选择要操作的账号~~" + return jsonify(resp) + + if act not in [ 'remove','recover' ] : + resp['code'] = -1 + resp['msg'] = "操作有误,请重试~~" + return jsonify(resp) + + user_info = User.query.filter_by(uid=id).first() + if not user_info: + resp['code'] = -1 + resp['msg'] = "指定账号不存在~~" + return jsonify(resp) + + if act == "remove": + user_info.status = 0 + elif act == "recover": + user_info.status = 1 + + user_info.update_time = getCurrentDate() + db.session.add(user_info) + db.session.commit() + return jsonify(resp) + diff --git a/web/controllers/user/User.py b/web/controllers/user/User.py index 6fdcc86..090ac35 100644 --- a/web/controllers/user/User.py +++ b/web/controllers/user/User.py @@ -36,9 +36,15 @@ def login(): return jsonify(resp) if user_info.login_pwd != UserService.genePwd(login_pwd, user_info.login_salt): - resp['code'] = -1 - resp['msg'] = "请输入正确的登录用户名和密码-2~~" - return jsonify(resp) + resp['code'] = -1 + resp['msg'] = "请输入正确的登录用户名和密码-2~~" + return jsonify(resp) + + if user_info.status !=1: + resp['code'] = -1 + resp['msg'] = "帐号已被禁用,请联系管理员处理~~" + return jsonify(resp) + response = make_response(json.dumps(resp)) response.set_cookie(app.config['AUTH_COOKIE_NAME'], '%s#%s' % ( diff --git a/web/interceptors/AuthInterceptor.py b/web/interceptors/AuthInterceptor.py index e554a9c..39ef1c9 100644 --- a/web/interceptors/AuthInterceptor.py +++ b/web/interceptors/AuthInterceptor.py @@ -5,6 +5,7 @@ from flask import request,g,redirect from common.models.User import ( User ) from common.libs.user.UserService import ( UserService ) from common.libs.UrlManager import ( UrlManager ) +from common.libs.LogService import LogService import re @app.before_request @@ -22,7 +23,8 @@ def before_request(): g.current_user=None if user_info: g.current_user=user_info - + # 加入日志 + LogService.addAccessLog() pattern = re.compile('%s' % "|".join(ignore_urls)) if pattern.match(path): return diff --git a/web/interceptors/ErrorInterceptor.py b/web/interceptors/ErrorInterceptor.py new file mode 100644 index 0000000..5e8824b --- /dev/null +++ b/web/interceptors/ErrorInterceptor.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +from application import app +from common.libs.Helper import ops_render +from common.libs.LogService import LogService + +@app.errorhandler( 404 ) +def error_404( e ): + LogService.addErrorLog( str( e ) ) + return ops_render( 'error/error.html',{ 'status':404,'msg':'很抱歉!您访问的页面不存在' } ) \ No newline at end of file diff --git a/web/static/js/account/index.js b/web/static/js/account/index.js new file mode 100644 index 0000000..be574a8 --- /dev/null +++ b/web/static/js/account/index.js @@ -0,0 +1,51 @@ +; +var account_index_ops = { + init:function(){ + this.eventBind(); + }, + eventBind:function(){ + var that = this; + $(".wrap_search .search").click(function(){ + $(".wrap_search").submit(); + }); + + $(".remove").click( function(){ + that.ops( "remove",$(this).attr("data") ); + } ); + + $(".recover").click( function(){ + that.ops( "recover",$(this).attr("data") ); + } ); + }, + ops:function( act,id ){ + var callback = { + 'ok':function(){ + $.ajax({ + url:common_ops.buildUrl( "/account/ops" ), + type:'POST', + data:{ + act:act, + id:id + }, + dataType:'json', + success:function( res ){ + var callback = null; + if( res.code == 200 ){ + callback = function(){ + window.location.href = window.location.href; + } + } + common_ops.alert( res.msg,callback ); + } + }); + }, + 'cancel':null + }; + common_ops.confirm( ( act == "remove" ? "确定删除?":"确定恢复?" ), callback ); + } + +}; + +$(document).ready( function(){ + account_index_ops.init(); +} ); \ No newline at end of file diff --git a/web/static/js/account/set.js b/web/static/js/account/set.js new file mode 100644 index 0000000..22f9d83 --- /dev/null +++ b/web/static/js/account/set.js @@ -0,0 +1,89 @@ +; +var account_set_ops = { + init:function(){ + this.eventBind(); + }, + eventBind:function(){ + $(".wrap_account_set .save").click(function(){ + var btn_target = $(this); + if( btn_target.hasClass("disabled") ){ + common_ops.alert("正在处理!!请不要重复提交~~"); + return; + } + + var nickname_target = $(".wrap_account_set input[name=nickname]"); + var nickname = nickname_target.val(); + + var mobile_target = $(".wrap_account_set input[name=mobile]"); + var mobile = mobile_target.val(); + + var email_target = $(".wrap_account_set input[name=email]"); + var email = email_target.val(); + + var login_name_target = $(".wrap_account_set input[name=login_name]"); + var login_name = login_name_target.val(); + + var login_pwd_target = $(".wrap_account_set input[name=login_pwd]"); + var login_pwd = login_pwd_target.val(); + + if( nickname.length < 1 ){ + common_ops.tip( "请输入符合规范的姓名~~",nickname_target ); + return false; + } + + if( mobile.length < 1 ){ + common_ops.tip( "请输入符合规范的手机号码~~",mobile_target ); + return false; + } + + if( email.length < 1 ){ + common_ops.tip( "请输入符合规范的邮箱~~",email_target ); + return false; + } + + if( login_name.length < 1 ){ + common_ops.tip( "请输入符合规范的登录用户名~~",login_name_target ); + return false; + } + + if( login_pwd.length < 6 ){ + common_ops.tip( "请输入符合规范的登录密码~~",login_pwd_target ); + return false; + } + + btn_target.addClass("disabled"); + + var data = { + nickname: nickname, + mobile: mobile, + email: email, + login_name:login_name, + login_pwd:login_pwd, + id:$(".wrap_account_set input[name=id]").val() + }; + + $.ajax({ + url:common_ops.buildUrl( "/account/set" ), + type:'POST', + data:data, + dataType:'json', + success:function( res ){ + btn_target.removeClass("disabled"); + var callback = null; + if( res.code == 200 ){ + callback = function(){ + window.location.href = common_ops.buildUrl("/account/index"); + } + } + common_ops.alert( res.msg,callback ); + } + }); + + + }); + } +}; + +$(document).ready( function(){ + account_set_ops.init(); +} ); \ No newline at end of file diff --git a/web/templates/account/index.html b/web/templates/account/index.html index 82f787d..308163e 100644 --- a/web/templates/account/index.html +++ b/web/templates/account/index.html @@ -1,16 +1,6 @@ {% extends "common/layout_main.html" %} {% block content %} -
-
-
- -
-
-
+{% include "common/tab_account.html" %}