diff --git a/README.md b/README.md index 2b9934e28b66809c4883d79adfc09e5bdb01a4a6..f5367bf867938f078111223fbb0790f760175c8e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ -centos安装命令:wget http://file.kwebapp.cn/sh/install/intapp/kcwebplus.sh && bash kcwebplus.sh \ No newline at end of file +centos安装命令:wget http://file.kwebapp.cn/sh/install/intapp/kcwebplus.sh && bash kcwebplus.sh + +tar zcvf lkmall.chengliao.com.tar.gz lkmall.chengliao.com +scp -r /www/lkmall.chengliao.com.tar.gz 47.97.115.105:/www/ \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index ed8d0eb2f85edf9e65d66ceb592f16753d300409..ce98ea678e0e68c9e900fa7d4a6c7b32f2238fb0 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- # #导入模块 -from . import intapp \ No newline at end of file +from . import intapp +from . import index \ No newline at end of file diff --git a/app/common/__init__.py b/app/common/__init__.py index 2629661e0659a720418988bac392ec98226899d2..5609cbcea36920e562477f5cbb74b3b4cb2625e8 100644 --- a/app/common/__init__.py +++ b/app/common/__init__.py @@ -41,11 +41,11 @@ def serlogin(username,sign,timestamp,random,types="session"): {'title':'首页','icon':config.domain['kcwebimg']+'/icon/home.png','url':'/intapp/index/index/home',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, {'title':'管理员','icon':config.domain['kcwebimg']+'/icon/admin.png','url':'/intapp/index/admin',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, # {'title':'终端管理','icon':config.domain['kcwebimg']+'/icon/terminal.png','url':'/intapp/index/socket/terminallist',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, - {'title':'导航管理','icon':config.domain['kcwebimg']+'/icon/menu.png','url':'/intapp/index/menu',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, + # {'title':'导航管理','icon':config.domain['kcwebimg']+'/icon/menu.png','url':'/intapp/index/menu',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, {'title':'模块管理','icon':config.domain['kcwebimg']+'/icon/modular.png','url':'/intapp/index/modular',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, {'title':'插件管理','icon':config.domain['kcwebimg']+'/icon/plug.png','url':'/intapp/index/plug',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, - {'title':'计划任务','icon':config.domain['kcwebimg']+'/icon/plan.png','url':'/intapp/index/plan',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, - {'title':'任务队列','icon':config.domain['kcwebimg']+'/icon/task.png','url':'/intapp/index/task',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, + # {'title':'计划任务','icon':config.domain['kcwebimg']+'/icon/plan.png','url':'/intapp/index/plan',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, + # {'title':'任务队列','icon':config.domain['kcwebimg']+'/icon/task.png','url':'/intapp/index/task',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000}, {'title':'系统配置','icon':config.domain['kcwebimg']+'/icon/setup.png','url':'/intapp/index/setup',"types":"left","pid":0,"admin_id":inifo['id'],"sort":10000} ] plugmenu=sqlite('plug',model_app_path).select() @@ -144,7 +144,7 @@ def return_list(lists,count,pagenow,pagesize): 'lists':lists } return data -def successjson(data=[],code=0,msg="成功",status='200 ok'): +def successjson(data=[],code=0,msg="成功",status='200 ok',cache=False): """成功说在浏览器输出包装过的json 参数 data 结果 默认[] @@ -155,6 +155,8 @@ def successjson(data=[],code=0,msg="成功",status='200 ok'): 参数 status http状态码 默认 200 + 参数 cache 是否启用浏览器缓存(状态码304缓存) + 返回 json字符串结果集 """ res={ @@ -163,8 +165,8 @@ def successjson(data=[],code=0,msg="成功",status='200 ok'): "time":int(time.time()), "data":data } - return response.json(res,status) -def errorjson(data=[],code=1,msg="失败",status='400 error'): + return response.json(res,status,response_cache=cache) +def errorjson(data=[],code=1,msg="失败",status='400 error',cache=False): """错误时在浏览器输出包装过的json 参数 data 结果 默认[] @@ -175,9 +177,11 @@ def errorjson(data=[],code=1,msg="失败",status='400 error'): 参数 status http状态码 默认 200 + 参数 cache 是否启用浏览器缓存(状态码304缓存) + 返回 json字符串结果集 """ - return successjson(data=data,code=code,msg=msg,status=status) + return successjson(data=data,code=code,msg=msg,status=status,cache=cache) def randoms(lens=6,types=1): """生成随机字符串 @@ -215,11 +219,12 @@ def file_get_content(filename,encoding=False): encoding 是否返回文件编码 默认否 """ fileData='' - with open(filename, 'rb') as f: - cur_encoding = chardet.detect(f.read())['encoding'] - #用获取的编码读取该文件而不是python3默认的utf-8读取。 - with open(filename,encoding=cur_encoding) as file: - fileData = file.read() + if os.path.isfile(filename): + with open(filename, 'rb') as f: + cur_encoding = chardet.detect(f.read())['encoding'] + #用获取的编码读取该文件而不是python3默认的utf-8读取。 + with open(filename,encoding=cur_encoding) as file: + fileData = file.read() if encoding: return fileData,cur_encoding else: @@ -254,7 +259,7 @@ class system_start: vague 是否模糊匹配 """ if id: - where=[("id","eq",id),"and",("admin_id","gt",0)] + where=[("id","eq",id)] if 'Linux' in get_sysinfo()['uname'][0]: if vague: f = open("/usr/bin/startkcweb") @@ -293,4 +298,12 @@ def get_local_ip(): g_local_ip = [l for l in (ip_from_ip_port, ip_from_host_name) if l][0] except (Exception) as e: print("get_local_ip found exception : %s" % e) - return g_local_ip if("" != g_local_ip and None != g_local_ip) else socket.gethostbyname(socket.gethostname()) \ No newline at end of file + return g_local_ip if("" != g_local_ip and None != g_local_ip) else socket.gethostbyname(socket.gethostname()) + +def sysisphone(): + "判断是不是手机端访问" + HTTP_USER_AGENT=request.HEADER.GET()['HTTP_USER_AGENT'] + if "Android" in HTTP_USER_AGENT or 'iPhone' in HTTP_USER_AGENT: + return True + else: + return False \ No newline at end of file diff --git a/app/common/file/config.conf b/app/common/file/config.conf index a6aee50895cca581173ea2e52690b592a6273b76..e5c0567887dfa7315c8eda88577f500ddc8fa05b 100644 --- a/app/common/file/config.conf +++ b/app/common/file/config.conf @@ -1 +1 @@ -{"aliyun": {"address": "http://oss-cn-beijing.aliyuncs.com", "bucket": "fanshubackups", "access_key": "LTAISSz1gBwL1oOo", "access_key_secret": "MoGi9FusUZx6Vjp8FgLrRkxU22kFON", "backpath": "kcweb"}} \ No newline at end of file +{"aliyun": {"address": "http://oss-cn-beijing.aliyuncs.com", "bucket": "", "access_key": "", "access_key_secret": "", "backpath": "kcweb"}, "system": {"name": "kcwebplus-云管", "logo": "https://imgmt.kwebapp.cn/icon/api.png", "kcwebuser": {}}} \ No newline at end of file diff --git a/app/common/html/login.html b/app/common/html/login.html index 09094684a4199a77c5826e6899730801536b3028..9f7c7517503f41a20ab7b1259486091bff0b9364 100644 --- a/app/common/html/login.html +++ b/app/common/html/login.html @@ -66,7 +66,7 @@ var vm = new Vue({ timestamp= Date.parse(new Date())/1000; random=md5('feafwefasas'+timestamp) sign=md5(self.username+md5('kcw'+self.password)+timestamp+random) - self.get("/intapp/index/pub/login/"+self.username+"/"+sign+"/"+timestamp+"/"+random,{},'登录中...').then(function(res){ + self.get("/index/index/index/login/"+self.username+"/"+sign+"/"+timestamp+"/"+random,{},'登录中...').then(function(res){ if(res.code==0){ location.reload() } diff --git a/app/common/model.py b/app/common/model.py index 7c60028f43c889376ec2e8e25647bcdb79235b1b..44947a409cec030dda9e8713d062dd8f43035ffb 100644 --- a/app/common/model.py +++ b/app/common/model.py @@ -74,7 +74,7 @@ class model_intapp_menu(modelsqliteintapp): sqlite('menu',model_app_path).where("title='"+title+"' and sort='"+str(sort)+"'").delete() elif title and types: sqlite('menu',model_app_path).where("title='"+title+"' and types='"+types+"'").delete() - elif title and admin_id: + else: sqlite('menu',model_app_path).where("title='"+title+"' and admin_id='"+str(admin_id)+"'").delete() diff --git a/app/config/app.py b/app/config/app.py index 12b586740c1724f502211511ef1ddcf374db0ff9..af79eb967ba660e852f8ebafa312808afadbda19 100644 --- a/app/config/app.py +++ b/app/config/app.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from .database import * -app['app_debug']=True #是否开启调试模式 +app['app_debug']=False #是否开启调试模式 app['tpl_folder']='./app' #设置模板文件目录名 注意:所有的配置目录都是以您的运行文件所在目录开始 app['before_request']='before_request' #设置请求前要执行的函数名 app['after_request']='after_request' #设置请求后要执行的函数名 @@ -33,24 +33,15 @@ email['sendNick']='' #发件人昵称 email['theme']='' #默认主题 email['recNick']='' #默认收件人昵称 -#mongodb配置 -mongo['host']='127.0.0.1' -mongo['port']='27017' -mongo['user']='' -mongo['password']='' -mongo['db']='test' -mongo['retryWrites']=False #是否支持重新写入 - #路由配置 route['default']=True #是否开启默认路由 默认路由开启后面不影响以下配置的路由,模块名/版本名/控制器文件名/方法名 作为路由地址 如:http://www.kcw.com/modular/plug/index/index/ -route['modular']='' #指定访问配置固定模块 (如果配置了该值,将无法通过改变url访问不同模块) -route['plug']='' #指定访问固定插件 (如果配置了该值,将无法通过改变url访问不同插件) +route['modular']="" #指定访问配置固定模块 (如果匹配了该值,将无法通过改变url访问不同模块) +route['plug']="" #指定访问固定插件 (如果匹配了该值,将无法通过改变url访问不同插件) route['defmodular']='intapp' #默认模块 当url不包括模块名时 route['defplug']='index' #默认插件 当url不包括插件名时 route['files']='index' #默认路由文件(控制器) 当url不包括控制器名时 route['funct']='index' #默认路由函数 (操作方法) 当url不包括操作方法名时 route['methods']=['POST','GET'] #默认请求方式 -#sqlite配置 -sqlite['db']='kcwlicuxweb' #sqlite数据库文件 + diff --git a/app/config/database.py b/app/config/database.py index 6fb9289f63637d9a46cd57ff1917e2685540d1a2..c27b858d15e04ad4fe5782c418b2d69e72b5e8c3 100644 --- a/app/config/database.py +++ b/app/config/database.py @@ -1,17 +1,28 @@ # -*- coding: utf-8 -*- from .redis import * database['type']='mysql' # 数据库类型 目前支持mysql和sqlite -database['debug']=True #是否开启数据库调试描述 +database['debug']=False #是否开启数据库调试描述 database['host']=['127.0.0.1']#服务器地址 [地址1,地址2,地址3...] 多个地址分布式(主从服务器)下有效 database['port']=[3306] #端口 [端口1,端口2,端口3...] database['user']=['root'] #用户名 [用户名1,用户名2,用户名3...] database['password']=['root'] #密码 [密码1,密码2,密码3...] database['db']=['test'] #数据库名 [数据库名1,数据库名2,数据库名3...] -database['charset']='utf8' #数据库编码默认采用utf8 +database['charset']='utf8mb4' #数据库编码默认采用utf8mb4 database['pattern']=False # True数据库长连接模式 False数据库短连接模式 注:建议web应用有效,cli应用方式下,如果长时间运行建议使用mysql().close()关闭 database['cli']=False # 是否以cli方式运行 database['dbObjcount']=1 # 连接池数量(单个数据库地址链接数量),数据库链接实例数量 mysql长链接模式下有效 database['deploy']=0 # 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) mysql数据库有效 database['master_num']=1 #主服务器数量 不能超过host服务器数量 (等于服务器数量表示读写不分离:主主复制。 小于服务器表示读写分离:主从复制。) mysql数据库有效 database['master_dql']=False #主服务器是否可以执行dql语句 是否可以执行select语句 主服务器数量大于等于host服务器数量时必须设置True -database['break']=0 #断线重连次数,0表示不重连。 注:cli模式下 10秒进行一次重连并且连接次数是当前配置的300倍 \ No newline at end of file +database['break']=0 #断线重连次数,0表示不重连。 注:cli模式下 10秒进行一次重连并且连接次数是当前配置的300倍 + +#mongodb配置 +mongo['host']='127.0.0.1' +mongo['port']='27017' +mongo['user']='' +mongo['password']='' +mongo['db']='test' +mongo['retryWrites']=False #是否支持重新写入 + +#sqlite配置 +sqlite['db']='kcwlicuxweb' #sqlite数据库文件 \ No newline at end of file diff --git a/app/index/README.md b/app/index/README.md new file mode 100644 index 0000000000000000000000000000000000000000..32dce566980cfe80d93c55d01b7b0815b23cc126 --- /dev/null +++ b/app/index/README.md @@ -0,0 +1 @@ +kcweb公共模块 \ No newline at end of file diff --git a/app/index/__init__.py b/app/index/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..72f4562d7cd39f3714c594f3aa34d0cd5cd9c7b9 --- /dev/null +++ b/app/index/__init__.py @@ -0,0 +1 @@ +from . import controller \ No newline at end of file diff --git a/app/index/common/__init__.py b/app/index/common/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..6b23e23a4f1cc8bc65212a2415b4e9c9923fe3d8 --- /dev/null +++ b/app/index/common/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from .autoload import * \ No newline at end of file diff --git a/app/index/common/autoload.py b/app/index/common/autoload.py new file mode 100644 index 0000000000000000000000000000000000000000..fe233919111e09f728bbf122b2bc372bccd1e726 --- /dev/null +++ b/app/index/common/autoload.py @@ -0,0 +1 @@ +from app.common import * \ No newline at end of file diff --git a/app/index/common/file/sqlite/.gitignore b/app/index/common/file/sqlite/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0179ab13c5a4f4c0c82ae8b30df046ed2556abdb --- /dev/null +++ b/app/index/common/file/sqlite/.gitignore @@ -0,0 +1 @@ +intapp \ No newline at end of file diff --git a/app/index/controller/__init__.py b/app/index/controller/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..6a0389200c3dbfe0c77443814666268ed08060c3 --- /dev/null +++ b/app/index/controller/__init__.py @@ -0,0 +1,2 @@ + +from . import index \ No newline at end of file diff --git a/app/index/controller/index/README.md b/app/index/controller/index/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b853e39e43ee925a2e15497b3cfdd51786ee231b --- /dev/null +++ b/app/index/controller/index/README.md @@ -0,0 +1 @@ +kcweb内置用户管理插件 包括登录 管理员管理等 \ No newline at end of file diff --git a/app/index/controller/index/__init__.py b/app/index/controller/index/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3471b9b2359f2a4e9c365ec5dff7186de9623922 --- /dev/null +++ b/app/index/controller/index/__init__.py @@ -0,0 +1 @@ +from . import index \ No newline at end of file diff --git a/app/index/controller/index/common/__init__.py b/app/index/controller/index/common/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..60767acb1935b5b933b889bf3903da2c5caae055 --- /dev/null +++ b/app/index/controller/index/common/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from .model import * \ No newline at end of file diff --git a/app/index/controller/index/common/autoload.py b/app/index/controller/index/common/autoload.py new file mode 100644 index 0000000000000000000000000000000000000000..ca177e97a4924892d1827cdb863baac58947a9ef --- /dev/null +++ b/app/index/controller/index/common/autoload.py @@ -0,0 +1 @@ +from app.index.common import * \ No newline at end of file diff --git a/app/index/controller/index/common/file/sqlite/.gitignore b/app/index/controller/index/common/file/sqlite/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..72a3e83b95c3b825bfa74389fa7962abef8cf27f --- /dev/null +++ b/app/index/controller/index/common/file/sqlite/.gitignore @@ -0,0 +1 @@ +intappindex \ No newline at end of file diff --git a/app/index/controller/index/common/model.py b/app/index/controller/index/common/model.py new file mode 100644 index 0000000000000000000000000000000000000000..9a154382ed6d3218a94297365862a8bebd0b7992 --- /dev/null +++ b/app/index/controller/index/common/model.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +from .autoload import * +# 可以在这里初始化数据库 +model_intapp_index_path=os.path.split(os.path.realpath(__file__))[0]+"/file/sqlite/intappindex" #数据存放目录 diff --git a/app/index/controller/index/index.py b/app/index/controller/index/index.py new file mode 100644 index 0000000000000000000000000000000000000000..a4fb861361f1f817008ff12a681de238118b0743 --- /dev/null +++ b/app/index/controller/index/index.py @@ -0,0 +1,27 @@ +from .common import * +def before_request(): + pass +def index(): + return "默认模块" +def outlogin(): + account_token=request.args.get("account_token") + if account_token: + del_cache(account_token) + else: + del_session('userinfo') + return successjson() +def get_account_token(username,sign,timestamp,random,types="get_account_token"): + "获取用户token" + status,code,msg,account_token=serlogin(username,sign,timestamp,random,types) + if status: + return successjson(data={"account_token":account_token},msg=msg) + else: + return errorjson(code=code,msg=msg) +def login(username,sign,timestamp,random,types="session"): + "登录" + status,code,msg,account_token=serlogin(username,sign,timestamp,random,types) + if status: + return successjson(data=account_token,msg=msg) + else: + return errorjson(code=code,msg=msg) + diff --git a/app/index/controller/index/install.txt b/app/index/controller/index/install.txt new file mode 100644 index 0000000000000000000000000000000000000000..fde6665e72eab0f28b090d94afdba781c4db892f --- /dev/null +++ b/app/index/controller/index/install.txt @@ -0,0 +1 @@ +kcweb \ No newline at end of file diff --git a/app/index/controller/index/tpl/index/home.html b/app/index/controller/index/tpl/index/home.html new file mode 100644 index 0000000000000000000000000000000000000000..beca5716b718bd6c0160f4b4c2e154c1b092e8af --- /dev/null +++ b/app/index/controller/index/tpl/index/home.html @@ -0,0 +1,51 @@ + + + + +${title} + + + + + + + + + + + + + + + + + + + +
+ ${content} +
+ + + diff --git a/app/index/controller/index/tpl/index/index.html b/app/index/controller/index/tpl/index/index.html new file mode 100644 index 0000000000000000000000000000000000000000..beca5716b718bd6c0160f4b4c2e154c1b092e8af --- /dev/null +++ b/app/index/controller/index/tpl/index/index.html @@ -0,0 +1,51 @@ + + + + +${title} + + + + + + + + + + + + + + + + + + + +
+ ${content} +
+ + + diff --git a/app/index/install.txt b/app/index/install.txt new file mode 100644 index 0000000000000000000000000000000000000000..fde6665e72eab0f28b090d94afdba781c4db892f --- /dev/null +++ b/app/index/install.txt @@ -0,0 +1 @@ +kcweb \ No newline at end of file diff --git a/app/intapp/controller/__init__.py b/app/intapp/controller/__init__.py index 6a0389200c3dbfe0c77443814666268ed08060c3..90b3d0450033971e101e374870a5df94f4fc9a87 100644 --- a/app/intapp/controller/__init__.py +++ b/app/intapp/controller/__init__.py @@ -1,2 +1,12 @@ +import re +def error(e,data): + try: + plug=str(e).split("has no attribute")[1] + plug=re.sub("[' ]","",plug) + except: + plug='' + header={"Content-Type":"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"} + header['Location']="/intapp/index/plug/index/intapp/"+plug + return '{"code":1,"msg":"您访问的地址不存在","data":"'+str(e)+'"}','302 Found',header from . import index \ No newline at end of file diff --git a/app/intapp/controller/index/admin.py b/app/intapp/controller/index/admin.py index 77c27d8c1ae793ede8231de40320aef43fe0943a..d2b4fee2bb08ecc42bec31ea562bda93d51e8092 100644 --- a/app/intapp/controller/index/admin.py +++ b/app/intapp/controller/index/admin.py @@ -1,8 +1,14 @@ from .common import * def index(): - return response.tpl() + if sysisphone(): + return response.tpl("../tplm/admin/index") + else: + return response.tpl() def role(): - return response.tpl() + if sysisphone(): + return response.tpl("../tplm/admin/role") + else: + return response.tpl() def getpluglist(modular="intapp"): "本地插件列表" path="app/"+modular+"/controller/" @@ -17,11 +23,14 @@ def getpluglist(modular="intapp"): for k in data: # k['value']=k['modular']+"/"+k['name'] data[i]['role']=json_decode(k['role']) - if k['name'] not in lists: - # print(k['name'],lists) - del data[i] + # if k['name'] not in lists: + # # print(k['name'],lists) + # del data[i] i+=1 return successjson(data) +def dellogin(): + shutil.rmtree(config.session['path']) + return successjson() def getlist(id=0): "获取列表" if id: @@ -55,17 +64,21 @@ def insert(): return errorjson(msg="失败") else: return successjson() -def delete(): +def delete(id=0): "批量删除" - try: - id=request.get_json() - if 1 in id: - id.remove(1) - sqlite("admin",model_app_path).where('id','in',id).delete() - except: - return errorjson(msg="失败") - else: + if id: + sqlite("admin",model_app_path).where('id',id).delete() return successjson() + else: + try: + id=request.get_json() + if 1 in id: + id.remove(1) + sqlite("admin",model_app_path).where('id','in',id).delete() + except: + return errorjson(msg="失败") + else: + return successjson() def update(id=0): "更新内容" data=request.get_json() @@ -80,7 +93,6 @@ def update(id=0): except:pass else: sqlite("admin",model_app_path).where("id",id).update(data) - shutil.rmtree(config.session['path']) return successjson() def setpwd(): "设置管理员登录密码" @@ -149,7 +161,6 @@ def updaterole(id=0): except:pass else: sqlite("role",model_app_path).where("id",id).update(data) - shutil.rmtree(config.session['path']) return successjson() def deleterole(): "批量删除" diff --git a/app/intapp/controller/index/common/autoload.py b/app/intapp/controller/index/common/autoload.py index e9ece292743d0144070d5c40ff89b122bedcc736..a98a5a139aafc5d2336b255878a033b15f33f652 100644 --- a/app/intapp/controller/index/common/autoload.py +++ b/app/intapp/controller/index/common/autoload.py @@ -1,3 +1,10 @@ from app.intapp.common import * from apscheduler.schedulers.blocking import BlockingScheduler -import threading,subprocess,multiprocessing \ No newline at end of file +import threading,subprocess,multiprocessing +def get_process_id(name): + try: + child = subprocess.Popen(['pgrep', '-f', name],stdout=subprocess.PIPE, shell=False) + response = child.communicate()[0] + return [int(pid) for pid in response.split()] + except: + return [] \ No newline at end of file diff --git a/app/intapp/controller/index/common/model.py b/app/intapp/controller/index/common/model.py index 26bc1f21968e60e5602013607d12c43f16aeff5a..dc6467ec11edb3f067a3a4f2dd1b2360230ed6e0 100644 --- a/app/intapp/controller/index/common/model.py +++ b/app/intapp/controller/index/common/model.py @@ -33,28 +33,26 @@ try: except: model_intapp_interval=model_intapp_interval() model_intapp_interval.create_table() -# class model_intapp_terminal(modelsqliteintapp): -# "终端列表" -# table="terminal" -# fields={ -# "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 -# "icon":model.dbtype.varchar(LEN=128,DEFAULT=''), -# "title":model.dbtype.varchar(LEN=128,DEFAULT=''), -# "host":model.dbtype.varchar(LEN=32,DEFAULT=''), -# "port":model.dbtype.varchar(LEN=32,DEFAULT=''), -# "username":model.dbtype.varchar(LEN=32,DEFAULT=''), -# "password":model.dbtype.varchar(LEN=32,DEFAULT=''), -# "blacklist":model.dbtype.text(), #命令黑名单 -# "whitelist":model.dbtype.text(), #命令白名单 -# "types":model.dbtype.varchar(LEN=32,DEFAULT='共享连接'), #连接方式 -# "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 -# "updtime":model.dbtype.int(LEN=11,DEFAULT=0) #添加时间 -# } -# try: -# sqlite('terminal',model_intapp_index_path).find() -# except: -# model_intapp_terminal=model_intapp_terminal() -# model_intapp_terminal.create_table() +class model_intapp_pythonrun(modelsqliteintapp): + "项目运行管理" + table="pythonrun" + fields={ + "id":model.dbtype.int(LEN=11,PRI=True,A_L=True), #设置id为自增主键 + "icon":model.dbtype.varchar(LEN=128,DEFAULT=''), + "title":model.dbtype.varchar(LEN=128,DEFAULT=''), + "descs":model.dbtype.varchar(LEN=512,DEFAULT=''), + "paths":model.dbtype.varchar(LEN=512,DEFAULT=''), #项目路径 + "filename":model.dbtype.varchar(LEN=32,DEFAULT=''), #运行文件 + "types":model.dbtype.varchar(LEN=32,DEFAULT=''), + "other":model.dbtype.varchar(LEN=512,DEFAULT=''), + "addtime":model.dbtype.int(LEN=11,DEFAULT=0), #添加时间 + "updtime":model.dbtype.int(LEN=11,DEFAULT=0) #添加时间 + } +try: + sqlite('pythonrun',model_intapp_index_path).find() +except: + model_intapp_pythonrun=model_intapp_pythonrun() + model_intapp_pythonrun.create_table() # class model_intapp_shelllog(modelsqliteintapp): # "终端操作日志" # table="shelllog" diff --git a/app/intapp/controller/index/index.py b/app/intapp/controller/index/index.py index 9305d5d5f6c96b19652a0461bd5db2568467b520..cd231a5b88cb9fcc811d1f7dadea8ac3357fc431 100644 --- a/app/intapp/controller/index/index.py +++ b/app/intapp/controller/index/index.py @@ -1,14 +1,23 @@ from .common import * import psutil def index(): - return response.tpl(userinfo=G.userinfo) + if os.path.isfile("app/common/file/config.conf"): + data=json_decode(file_get_content("app/common/file/config.conf")) + else: + data={ + 'system':{ + "logo":"","name":"" + } + } + if sysisphone(): + return response.tpl("../tplm/index/index",userinfo=G.userinfo,fileconfig=data) + else: + return response.tpl(userinfo=G.userinfo,fileconfig=data) def home(): - return response.tpl() -# def pub(html): -# return response.tpl("pub/%s" % html) -# def s(fun,html): -# return response.tpl("%s/%s" % (fun,html)) - + if sysisphone(): + return response.tpl("../tplm/index/home") + else: + return response.tpl() def menu(): admin_id=G.userinfo['id'] data={ diff --git a/app/intapp/controller/index/install.txt b/app/intapp/controller/index/install.txt index 8116b777919a1815a4f0ac3ffc14c0e95974867a..3f68567f72dd3319433bc4a64a052e7074fd8bb3 100644 --- a/app/intapp/controller/index/install.txt +++ b/app/intapp/controller/index/install.txt @@ -1,2 +1,6 @@ +kcweb>=4.12.0 +gunicorn==20.0.4 +apscheduler==3.6.3 +psutil==5.7.0 pexpect==4.8.0 -psutil==5.7.0 \ No newline at end of file +oss2==2.12.1 \ No newline at end of file diff --git a/app/intapp/controller/index/menu.py b/app/intapp/controller/index/menu.py index 91c040bc11ada642c6c9065c7a2a9a18eb582ef9..652280694cbc9dbc60b4ea5964b89c165a71200f 100644 --- a/app/intapp/controller/index/menu.py +++ b/app/intapp/controller/index/menu.py @@ -1,7 +1,10 @@ from .common import * import base64,psutil def index(): - return response.tpl() + if sysisphone(): + return response.tpl("../tplm/menu/index") + else: + return response.tpl() def menulist(pid=0): pagenow=request.args.get('pagenow') pagesize=request.args.get('pagesize') @@ -37,7 +40,7 @@ def menudelete(): idstr="0" for k in id: idstr+=","+str(k) - sqlite("menu",model_app_path).where("id in ("+idstr+") and admin_id != 0").delete() + sqlite("menu",model_app_path).where("id in ("+idstr+")").delete() return successjson() def menuinsert(): data=request.get_json() diff --git a/app/intapp/controller/index/modular.py b/app/intapp/controller/index/modular.py index 561a24e6eda50076e0e40b83c00bbaac7ff7a79a..c2b24990c8d89ffcaeaa710dd33483cf2ac6c929 100644 --- a/app/intapp/controller/index/modular.py +++ b/app/intapp/controller/index/modular.py @@ -1,7 +1,10 @@ from .common import * kcwebuserinfopath=os.path.split(os.path.realpath(__file__))[0]+"/common/file/" def index(): - return response.tpl() + if sysisphone(): + return response.tpl("../tplm/modular/index") + else: + return response.tpl() if not os.path.exists(kcwebuserinfopath): os.makedirs(kcwebuserinfopath) def kcwebsebduser(): @@ -37,11 +40,10 @@ def banduser(): def modular_list(kw='',pagenow=1): http=Http() - http.openurl(config.domain['kcwebapi']+"/pub/modular_list","POST",{ + http.openurl(config.domain['kcwebapi']+"/pub/modular_list","get",params={ "kw":kw,"pagenow":pagenow }) res=json_decode(http.get_text) - del http lists=res['data']['lists'] for k in lists: k['status']=0 #0未安装 1已安装 2安装中 3卸载中 4不可以安装 diff --git a/app/intapp/controller/index/plan.py b/app/intapp/controller/index/plan.py index 3744e20eac9cbaafdbf6838c873d57266ca55ffa..1dbad6d2aa856682393db2884b1907508d01b9a4 100644 --- a/app/intapp/controller/index/plan.py +++ b/app/intapp/controller/index/plan.py @@ -3,7 +3,10 @@ from .common import * indexconfigpath=os.path.split(os.path.realpath(__file__))[0]+"/common/file/sqlite/" def index(): - return response.tpl() + if sysisphone(): + return response.tpl("../tplm/plan/index") + else: + return response.tpl() def get(id=0): "获取列表" if id: diff --git a/app/intapp/controller/index/plug.py b/app/intapp/controller/index/plug.py index 0ffdfc9834a2293ddfbe1570cb6d627d53475723..4589076a4eec45c157a75e483ef7488a50d651c6 100644 --- a/app/intapp/controller/index/plug.py +++ b/app/intapp/controller/index/plug.py @@ -1,7 +1,19 @@ from .common import * kcwebuserinfopath=os.path.split(os.path.realpath(__file__))[0]+"/common/file/" -def index(modular="intapp"): - return response.tpl(modular=modular) +def index(modular="intapp",kw=''): + lefttext=request.args.get('lefttext') + if not lefttext: + lefttext='应用' + lefturl=request.args.get('lefturl') + if not lefturl: + lefturl='myapp' + lefttype=request.args.get('lefttype') + if not lefttype: + lefttype='' + if sysisphone(): + return response.tpl("../tplm/plug/index",modular=modular,kw=kw,lefttext=lefttext,lefturl=lefturl,lefttype=lefttype) + else: + return response.tpl(modular=modular,kw=kw) def getpluglist(modular="intapp"): "本地插件列表" path="app/"+modular+"/controller/" @@ -17,13 +29,14 @@ def getpluglist(modular="intapp"): del data[i] i+=1 return successjson(data) -def plug_list(modular="intapp",pagenow=1,group=False): +def plug_list(modular="intapp",pagenow=1,group=''): "云插件列表" + kw=request.args.get("kw") + if not kw: + kw='' plug=sqlite('plug',model_app_path).select() http=Http() - http.openurl(config.domain['kcwebapi']+"/pub/plug_list","POST",{ - "kw":request.args.get("kw"),"modular":modular,"pagenow":pagenow,"group":group - }) + http.openurl(config.domain['kcwebapi']+"/pub/plug_list?modular="+modular+"&pagenow="+pagenow+"&group="+group+"&kw="+kw) res=json_decode(http.get_text) del http lists=res['data']['lists'] diff --git a/app/intapp/controller/index/pub.py b/app/intapp/controller/index/pub.py index 0ea49c27a6c0eadca21e582e5c5e26e9f4f2a1c2..bfbd2ae6cfae3b48c6607165b5c5a9818a73c995 100644 --- a/app/intapp/controller/index/pub.py +++ b/app/intapp/controller/index/pub.py @@ -1,6 +1,5 @@ from .common import * import subprocess,pexpect - def before_request(): pass def checkserver(): diff --git a/app/intapp/controller/index/role.txt b/app/intapp/controller/index/role.txt index 9707eaa56901ef7a50bba1098713950af1e5c26f..9add180e0264d63722c38ef7ea3faf715bc7c11b 100644 --- a/app/intapp/controller/index/role.txt +++ b/app/intapp/controller/index/role.txt @@ -50,21 +50,28 @@ shell执行能力,/intapp/index/index/shell 添加计划,/intapp/index/plan/add 删除计划,/intapp/index/plan/delpl 计划日志,/intapp/index/plan/log -保存计划配置,/intapp/index/plan/setconfig 任务页面,/intapp/index/task/index 任务列表,/intapp/index/task/task 任务状态,/intapp/index/task/taskstatus -设置页面,/intapp/index/setup/index +设置,/intapp/index/setup/index +基本配置,/intapp/index/setup/basepage +开机启动项,/intapp/index/setup/startpage +备份恢复,/intapp/index/setup/bacrecpage +项目管理器,/intapp/index/setup/pythonrun +启动/停止项目管理,/intapp/index/setup/restart +设置/添加项目管理,/intapp/index/setup/setpythonrun +删除项目管理,/intapp/index/setup/delpythonrun +项目管理列表,/intapp/index/setup/pythonrulists +项目管理日志,/intapp/index/setup/logpythonrun +获取/保存配置信息,/intapp/index/setup/setbaseconfig 添加启动项,/intapp/index/setup/addstart 删除启动项,/intapp/index/setup/delstart -列出启动项,/intapp/index/setup/startlist -备份全部,/intapp/index/setup/backup +获取启动项,/intapp/index/setup/startlist +阿里云备份列表,/intapp/index/setup/aliyunosslist +阿里云备点恢复,/intapp/index/setup/aliyunossdownload +备份全部文稿,/intapp/index/setup/backup 恢复全部文稿,/intapp/index/setup/recovery -下载备份,/intapp/index/setup/download -上传备份,/intapp/index/setup/postsup -保存配置信息,/intapp/index/setup/setconfig -阿里云列表,/intapp/index/setup/aliyunosslist -从阿里云备份点恢复,/intapp/index/setup/aliyunossdownload - +下载备份文件,/intapp/index/setup/download +上传备份文件,/intapp/index/setup/postsup diff --git a/app/intapp/controller/index/setup.py b/app/intapp/controller/index/setup.py index fd057570c22956b91abf023151ae12efd43a208e..0aa83a584873307b8ccbbd0e88208e9595497394 100644 --- a/app/intapp/controller/index/setup.py +++ b/app/intapp/controller/index/setup.py @@ -1,13 +1,185 @@ from .common import * import base64,oss2 def index(): - return response.tpl() + if sysisphone(): + return response.tpl("../tplm/setup/index") + else: + return response.tpl() +def basepage(): + "基本配置" + if sysisphone(): + return response.tpl("../tplm/setup/basepage") + else: + return response.tpl() +def startpage(): + "开机启动项" + if sysisphone(): + return response.tpl("../tplm/setup/startpage") + else: + return response.tpl() +def bacrecpage(): + "备份恢复页面" + if sysisphone(): + return response.tpl("../tplm/setup/bacrecpage") + else: + return response.tpl() +def pythonrun(): + "项目管理器" + if sysisphone(): + return response.tpl("../tplm/setup/pythonrun") + else: + return response.tpl() +def restart(types='stop'): + "启动/停止项目管理" + data=request.get_json() + interpreter=md5(data['paths']+data['types']+data['filename']+data['other']) #解释器 + if types=='start': + if data['types']=='python3.6': + if not os.path.isfile("/usr/bin/"+interpreter): + os.system("ln -s /usr/local/python/python3.6/bin/python3 /usr/bin/"+interpreter) + elif data['types']=='php7.2': + if os.path.isfile("/usr/local/php/php7.2/bin/php"): + os.system("ln -s /usr/local/php/php7.2/bin/php /usr/bin/"+interpreter) + else: + return errorjson(msg="您必须使用本系统的软件插件安装php7.2后才能使用该功能") + elif data['types']=='php7.3': + if os.path.isfile("/usr/local/php/php7.3/bin/php"): + os.system("ln -s /usr/local/php/php7.3/bin/php /usr/bin/"+interpreter) + else: + return errorjson(msg="您必须使用本系统的软件插件安装php7.3后才能使用该功能") + if data['other']: #带运行参数 + os.system("cd "+data['paths']+"&& nohup "+interpreter+" "+data['filename']+" "+data['other']+" > "+data['paths']+"/"+interpreter+".log 2>&1 &") + else: + os.system("cd "+data['paths']+"&& nohup "+interpreter+" "+data['filename']+" > "+interpreter+".log 2>&1 &") + time.sleep(1) + if get_process_id(interpreter): + return successjson() + else: + return errorjson(msg="启动失败") + elif types=='stop': + os.system("pkill -9 "+interpreter[:12]) + return successjson() +def setpythonrun(): + "设置/添加项目管理" + if 'Linux' in get_sysinfo()['platform']: + data=request.get_json() + + interpreter=md5(data['paths']+data['types']+data['filename']+data['other']) #解释器 + if not os.path.isfile("/usr/bin/"+interpreter): + if data['types']=='python3.6': + os.system("ln -s /usr/local/python/python3.6/bin/python3 /usr/bin/"+interpreter) + elif data['types']=='php7.2': + if os.path.isfile("/usr/local/php/php7.2/bin/php"): + os.system("ln -s /usr/local/php/php7.2/bin/php /usr/bin/"+interpreter) + else: + return errorjson(msg="您必须使用本系统的软件插件安装php7.2后才能使用该功能") + elif data['types']=='php7.3': + if os.path.isfile("/usr/local/php/php7.3/bin/php"): + os.system("ln -s /usr/local/php/php7.3/bin/php /usr/bin/"+interpreter) + else: + return errorjson(msg="您必须使用本系统的软件插件安装php7.3后才能使用该功能") + if data['other']: #带运行参数 + os.system("cd "+data['paths']+"&& nohup "+interpreter+" "+data['filename']+" "+data['other']+" > "+data['paths']+"/"+interpreter+".log 2>&1 &") + else: + os.system("cd "+data['paths']+"&& nohup "+interpreter+" "+data['filename']+" > "+data['paths']+"/"+interpreter+".log 2>&1 &") + time.sleep(1) + if get_process_id(interpreter): + if data['id']: + arr=sqlite("pythonrun").where("id",data['id']).find() + interpreterj=md5(arr['paths']+arr['types']+arr['filename']+arr['other']) #解释器 + if interpreterj!=interpreter:#删除之前的 + os.system("pkill -9 "+interpreterj[:12]) + os.remove("/usr/bin/"+interpreterj) + data.update(updtime=times(),addtime=times()) + del data['status'] + sqlite("pythonrun").where("id",data['id']).update(data) + return successjson() + else: + del data['id'] + data.update(updtime=times(),addtime=times()) + sqlite("pythonrun").insert(data) + return successjson() + else: + return errorjson(interpreter) + else: + return errorjson(msg="不支持该系统,当前只支持linux") +def logpythonrun(id): + "项目管理日志" + arr=sqlite("pythonrun").where('id',id).find() + interpreter=md5(arr['paths']+arr['types']+arr['filename']+arr['other']) #解释器 + data=file_get_content(arr['paths']+"/"+interpreter+".log") + return successjson(data) +def delpythonrun(id=''): + "删除项目管理" + try: + if id: + id=[id] + else: + id=request.get_json() + arr=sqlite("pythonrun").where('id','in',id).field("paths,types,filename,other").select() + for k in arr: + interpreter=md5(k['paths']+k['types']+k['filename']+k['other']) #解释器 + os.system("pkill -9 "+interpreter[:12]) + if os.path.isfile("/usr/bin/"+interpreter): + os.remove("/usr/bin/"+interpreter) + sqlite("pythonrun").where('id','in',id).delete() + except: + return errorjson(msg="失败") + else: + return successjson() +def pythonrulists(id=''): + "项目管理列表" + if id: + return successjson(sqlite("pythonrun").find(id)) + where=None + kw=request.args.get('kw') + pagenow=request.args.get('pagenow') + pagesize=request.args.get('pagesize') + if kw: + where=[("title","like","%"+str(kw)+"%"),'or',("descs","like","%"+str(kw)+"%")] + if not pagenow: + pagenow=1 + else: + pagenow=int(pagenow) + if not pagesize: + pagesize=10 + else: + pagesize=int(pagesize) + lists=sqlite("pythonrun").where(where).page(pagenow,pagesize).select() + for k in lists: + interpreter=md5(k['paths']+k['types']+k['filename']+k['other']) #解释器 + if get_process_id(interpreter): + k['status']=1 #运行中 + else: + k['status']=0 #已停止 + count=sqlite("pythonrun").where(where).count() + data=return_list(lists,count,pagenow,pagesize) + return successjson(data) +def setbaseconfig(types='get'): + "保存配置信息" + if types=='get': + if os.path.isfile("app/common/file/config.conf"): + data=json_decode(file_get_content("app/common/file/config.conf")) + if not data['aliyun']['backpath']: + data['aliyun']['backpath']="kcweb" + else: + data={} + return successjson(data) + else: + config=request.get_json() + file_set_content("app/common/file/config.conf",json_encode(config)) + return successjson(msg="保存成功") + def addstart(): "添加启动项" data=request.get_json() if sqlite("start").connect(model_app_path).where("value",data['value']).count(): return errorjson(msg="禁止重复添加") - if system_start.insert_Boot_up(cmd=data['value'],name=data['name'],types=data['types'],admin_id=G.userinfo['id']): + try: + icon=data['icon'] + except: + icon='' + if system_start.insert_Boot_up(cmd=data['value'],name=data['name'],types=data['types'],admin_id=G.userinfo['id'],icon=icon): return successjson() else: return errorjson(msg="添加失败,该系统支不支持") @@ -33,24 +205,19 @@ def startlist(): lists=yz[0] count=yz[1] data=return_list(lists,count,pagenow,pagesize) - if os.path.isfile("app/common/file/config.conf"): - data['config']=json_decode(file_get_content("app/common/file/config.conf")) - if not data['config']['aliyun']['backpath']: - data['config']['aliyun']['backpath']="kcweb" - else: - data['config']={} + return successjson(data) -def setconfig(): - "保存配置信息" - config=request.get_json() - file_set_content("app/common/file/config.conf",json_encode(config)) - return successjson() -def aliyunosslist(): + +def aliyunosslist(types='app'): if not os.path.isfile("app/common/file/config.conf"): return errorjson(msg="请先配置阿里云oss配置信息") + data=json_decode(file_get_content("app/common/file/config.conf")) prefix=request.args.get("prefix") if not prefix: - prefix="backups/" + if types=='app': + prefix="backups/"+data['aliyun']['backpath']+"/app/" + else: + prefix="backups/"+data['aliyun']['backpath']+"/backup/mysql/" data=[] try: fileconfig=json_decode(file_get_content("app/common/file/config.conf")) @@ -61,10 +228,18 @@ def aliyunosslist(): for obj in oss2.ObjectIterator(bucket, prefix = prefix, delimiter = '/'): # 通过is_prefix方法判断obj是否为文件夹。 if obj.is_prefix(): # 文件夹 - data.append({"name":obj.key.split("/")[-2],"path":obj.key,"type":"folder"}) + data.insert(0,{"name":obj.key.split("/")[-2],"path":obj.key,"type":"folder"}) else: # 文件 - data.append({"name":obj.key.split("/")[-1],"path":obj.key,"type":"file"}) + data.insert(0,{"name":obj.key.split("/")[-1],"path":obj.key,"type":"file"}) except:pass + # data1=[] + # i=len(data) + # while True: + # i+=1 + # if i<0: + # break + # else: + # data1.append(data[i]) return successjson(data) def aliyunossdownload(types=""): "从阿里云备份点恢复" @@ -92,15 +267,19 @@ def aliyunossdownload(types=""): return successjson() def backup(types=''): "备份全部" - filelist=get_file("app") - if os.path.exists("backup"): - shutil.rmtree("backup") - for k in filelist: - if k['type']=='folder' and '__pycache__' not in k['path']: - if 'common/file' == k['path'][-11:]: - shutil.copytree(k['path'],"backup/"+k['path']) + paths=request.args.get("paths") + if paths: #备份目录 app/common/file + shutil.copytree(paths,"backup/"+paths) + else: #备份全部 + filelist=get_file("app") + if os.path.exists("backup"): + shutil.rmtree("backup") + for k in filelist: + if k['type']=='folder' and '__pycache__' not in k['path']: + if 'common/file' == k['path'][-11:]: + shutil.copytree(k['path'],"backup/"+k['path']) + # print(k['path'],"backup/"+k['path']) if types=='aliyun':#备份文件上传到阿里云oss - print("本地备份成功") if not os.path.isfile("app/common/file/config.conf"): print("您没有保存阿里云oss修改配置信息而无法上传") else: @@ -122,7 +301,7 @@ def backup(types=''): filelist.append(obj.key) i=0 while True: - if len(filelist)-i <= 5: #在阿里云保留5个备份文件 + if len(filelist)-i <= 30: #在阿里云保留30个备份文件 break bucket.delete_object(filelist[i]) i+=1 @@ -131,8 +310,11 @@ def backup(types=''): if not config.app['cli']: return successjson(msg="所有文稿备份成功") def recovery(): - "恢复全部文稿" - if os.path.exists("backup/app"): + "恢复文稿" + paths=request.args.get("paths") + if paths: #恢复指定目录 app/common/file + shutil.copytree("backup/"+paths,paths) + elif os.path.exists("backup/app"): #恢复全部文稿 filelist=get_file("backup/app") for k in filelist: if k['type']=='folder' and '__pycache__' not in k['path']: @@ -141,7 +323,7 @@ def recovery(): if os.path.exists(path): shutil.rmtree(path) shutil.copytree(k['path'],path) - # print(k['path'],path) + print(k['path'],path) return successjson(msg="所有文稿恢复成功") else: return errorjson(msg="备份目录不存在") @@ -164,3 +346,36 @@ def postsup(): return successjson() else: return errorjson(msg="上传失败") +def dowfile(name=''): + "下载指定文件" + pathname=request.args.get("pathname") + return response.download(pathname) +def uploadfile(): + "上传文件导指定目录" + pathname=request.args.get("pathname") + if request.binary.save('file',pathname): + return successjson() + else: + return errorjson(msg="上传失败") +def backxz(name=''): + "压缩指定文件夹并下载" + paths=request.args.get("paths") + zip.packzip(paths,"backxz.zip") + f=open("backxz.zip","rb") + body=f.read() + f.close() + os.remove("backxz.zip") + return body,"200 ok",{"Content-Type":"application/zip","Accept-Ranges":"bytes"} +def upunback(): + "上传zip压缩包并解压指定文件夹" + paths=request.args.get("paths") + if request.binary.save('file',"backxz."+request.binary.filesuffix('file')): + try: + zip.unzip_file("backxz.zip",paths) + os.remove("backxz.zip") + except: + return errorjson(msg="文件格式错误") + return successjson() + else: + return errorjson(msg="上传失败") + return successjson() diff --git a/app/intapp/controller/index/task.py b/app/intapp/controller/index/task.py index 1a80e0bb1fa06e40d00a5b91b4eaac962fcd80c9..9dddbf3c3d86d7f14bd4e1fe27a14dbb15c081da 100644 --- a/app/intapp/controller/index/task.py +++ b/app/intapp/controller/index/task.py @@ -1,6 +1,9 @@ from .common import * def index(): - return response.tpl() + if sysisphone(): + return response.tpl("../tplm/task/index") + else: + return response.tpl() def task(): pagenow=request.args.get('pagenow') pagesize=request.args.get('pagesize') diff --git a/app/intapp/controller/index/tpl/admin/index.html b/app/intapp/controller/index/tpl/admin/index.html index e87ff5d7b91e8383d34196185c8361628860819f..d1fe2c7f552ff7cf76d87b9631d8f4fe76a6f648 100644 --- a/app/intapp/controller/index/tpl/admin/index.html +++ b/app/intapp/controller/index/tpl/admin/index.html @@ -34,7 +34,11 @@ 搜索 添加管理员账户 - 角色管理 + + 角色管理 + 清除所有会话 + +
@@ -90,7 +94,8 @@ - + + 选择图片 @@ -122,6 +127,10 @@
diff --git a/app/intapp/controller/index/tpl/menu/index.html b/app/intapp/controller/index/tpl/menu/index.html index 418280771387d137f168b977c448f337269760c8..e4fa666a68f0fd8ace9444170734f87c4bfacc41 100644 --- a/app/intapp/controller/index/tpl/menu/index.html +++ b/app/intapp/controller/index/tpl/menu/index.html @@ -83,7 +83,8 @@ width="500px"> - + + 选择图片 @@ -110,6 +111,10 @@ + + + + + + + + + + + +
+
+
+
+ 备份所有 + 恢复所有 + 下载备份文件 +
+
+ + +
将备份文件拖到此处,或点击上传
+
只能上传压缩包zip文件
+
+
+
+
+

阿里云oss文稿备份点

+ + + + + + + + +
+
+

阿里云oss mysql备份点

+ + + + + + + + +
+
+
+ + + \ No newline at end of file diff --git a/app/intapp/controller/index/tpl/setup/basepage.html b/app/intapp/controller/index/tpl/setup/basepage.html new file mode 100644 index 0000000000000000000000000000000000000000..f514ae0d33c5496c72e4aaa8ff2255cc544afe28 --- /dev/null +++ b/app/intapp/controller/index/tpl/setup/basepage.html @@ -0,0 +1,154 @@ + + + + + +基本配置 + + + + + + + + + + + + + + + + + + + +
+ +
+ 系统设置 + +
+ + + + + + + 选择图片 + + + 绑定 + + + 保存 + + +
+ +
+ 阿里云oss对象储存配置 + 前往官网 +
+ + + + + + + + + + + + + + + + + + 保存 + + +
+
+ + + \ No newline at end of file diff --git a/app/intapp/controller/index/tpl/setup/index.html b/app/intapp/controller/index/tpl/setup/index.html index 2355ec3931876e83cb817e83db2c1c4d6c417326..ee41a5f8ebd9d27ee3ae88d6bb448efcec21aa74 100644 --- a/app/intapp/controller/index/tpl/setup/index.html +++ b/app/intapp/controller/index/tpl/setup/index.html @@ -34,133 +34,28 @@
-
- - -
-    - - 添加启动项 - + + 基本配置 + 开机启动项 + 备份恢复 + cli项目管理器 + 计划任务 + 导航管理 + 任务队列 + + +
+ +
+
- - - - - - - - - - - - - - - -
-
- 备份所有 - 恢复所有 - 下载备份文件 -
-
- - -
将备份文件拖到此处,或点击上传
-
只能上传压缩包zip文件
-
-
+ + +
+
-
-

阿里云oss文稿备份点

- - - - - - - - -
-
-

阿里云oss mysql备份点

- - - - - - - - -
- - - - - - - - - - - - - - - - - - - - 保存 - - - - - - - - - - - - - - - - 取 消 - 添加 - - -
+
+
diff --git a/app/intapp/controller/index/tpl/setup/pythonrun.html b/app/intapp/controller/index/tpl/setup/pythonrun.html new file mode 100644 index 0000000000000000000000000000000000000000..67faaa9db65b080291d46acffede66d209bba237 --- /dev/null +++ b/app/intapp/controller/index/tpl/setup/pythonrun.html @@ -0,0 +1,316 @@ + + + + +kcwebplus + + + + + + + + + + + + + + + + + + + +
+
+    + + + 搜索 + 添加项目 + + 下载数据 + + 上传intapp_index.zip + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+    删除选中  + + +
+
+ + +
+ + + + + + 选择图片 + + + + + + + + + + + + + + + + python3.6解释器 + php7.2解释器 + php7.3解释器 +
+ 您必须提前在“软件管理”中安装php7.2,已安装请忽略,其他安装方式将无效 + 您必须提前在“软件管理”中安装php7.3,已安装请忽略,其他安装方式将无效 +
+ + + + + + 取 消 + 修改并运行 + 添加并运行 + +
+
+ +
{{runlog}}
+
+
+ + + diff --git a/app/intapp/controller/index/tpl/setup/startpage.html b/app/intapp/controller/index/tpl/setup/startpage.html new file mode 100644 index 0000000000000000000000000000000000000000..24919c7b14f694ba80cf460805f16a23501f1415 --- /dev/null +++ b/app/intapp/controller/index/tpl/setup/startpage.html @@ -0,0 +1,169 @@ + + + + + +kcwebplus + + + + + + + + + + + + + + + + + + + +
+
+
+    + + 添加启动项 + +
+ + + + + + + + + + + + + + + + + + + + 选择图片 + + + + + + + + + + 取 消 + 添加 + + +
+
+ + + \ No newline at end of file diff --git a/app/intapp/controller/index/tplm/admin/index.html b/app/intapp/controller/index/tplm/admin/index.html new file mode 100644 index 0000000000000000000000000000000000000000..678307b87c3b75365d88a4c5abc6d9a13f097beb --- /dev/null +++ b/app/intapp/controller/index/tplm/admin/index.html @@ -0,0 +1,261 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+
+
+
{{item.username}}({{item.nickname}})
+
{{item.describes}}
+
+
+ 手机:{{item.phone}} + 姓名:{{item.name}} +
+
+
+
+ 权限:{{item.title}} +
+
+
{{time_date(item.logintime)}} 登录
+
+
+
+
+ +
+
+ 添加管理员 + + 清除所有会话 +
+
+
+ 加载中... +
+
+ 下一页 + 暂无数据 + 我已到底了 +
+
+ +
+ + 确定 +
+
+ +
+ + + + + + + + + + + + 修改 + 添加 + +
+
+ +
+ +
+
+
+ + + diff --git a/app/intapp/controller/index/tplm/index/home.html b/app/intapp/controller/index/tplm/index/home.html new file mode 100644 index 0000000000000000000000000000000000000000..940f4c0736e8011589647cb2f7c4183f1d050906 --- /dev/null +++ b/app/intapp/controller/index/tplm/index/home.html @@ -0,0 +1,267 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + +
+
+
系统 {{data.platform}}
+
控制板已不间断运行: {{data.rundate}}
+
+
+
+
CPU使用率
+
+ +
+
+ +
+
+ +
+
+ +
+
{{cpumes.cpu.count}}核心
+
+
+
物理内存使用率
+
+ +
+
+ +
+
+ +
+
+ +
+
{{Math.ceil(cpumes.memory.physics.used/1024/1024)}}MB / {{Math.ceil(cpumes.memory.physics.count/1024/1024)}}MB
+
+
+
+ +
+
swap内存使用率
+
+ +
+
+ +
+
+ +
+
+ +
+
{{Math.ceil(cpumes.memory.swap.used/1024/1024)}}MB / {{Math.ceil(cpumes.memory.swap.count/1024/1024)}}MB
+
+
+
{{item.name}}
+
+ +
+
+ +
+
+ +
+
+ +
+
{{parseInt(item.used/1024/1024/1024)}}GB / {{parseInt(item.count/1024/1024/1024)}}GB
+
{{parseInt(item.used/1024/1024)}}MB / {{parseInt(item.count/1024/1024)}}MB
+
+
+
+
+
+
+ + + diff --git a/app/intapp/controller/index/tplm/index/index.html b/app/intapp/controller/index/tplm/index/index.html new file mode 100644 index 0000000000000000000000000000000000000000..13241bd64a33e215b45e5fec4c312083415cd7e4 --- /dev/null +++ b/app/intapp/controller/index/tplm/index/index.html @@ -0,0 +1,354 @@ + + + + +${fileconfig['system']['name']}-${userinfo['nickname']}-kcweb云管 + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ {{header.lefturl.text}} +
+
+
+  ${userinfo['name']} +
+
{{header.title}}
+
+
+
+
+
+
+ +
+ + + +
{{item.title}}
+
+
+ + + +
{{item.title}}
+
+
+
+ +
+ + + {{item.title}} + + + + 我的应用 + + + + {{item.title}} + + + +
+ + +
+
+
姓名
+
${userinfo['name']}
+ +
+
+
昵称
+
${userinfo['nickname']}
+ +
+
+
设置登录密码
+
+ +
+
+
重启服务器
+
+ 运行中 + 服务器重启中... + 等待服务器启动 +
+ +
+
+
重启应用
+
+ 运行中 + 应用重启中... + 服务器重启中... + 等待服务器启动 +
+ +
+ 退出登录 +
+
+ + + +
+ + + diff --git a/app/intapp/controller/index/tplm/menu/index.html b/app/intapp/controller/index/tplm/menu/index.html new file mode 100644 index 0000000000000000000000000000000000000000..3e28265539808b22d4762f331615f34172503f6f --- /dev/null +++ b/app/intapp/controller/index/tplm/menu/index.html @@ -0,0 +1,60 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + +
+ +
+ + + diff --git a/app/intapp/controller/index/tplm/modular/index.html b/app/intapp/controller/index/tplm/modular/index.html new file mode 100644 index 0000000000000000000000000000000000000000..aa0313c40a80d0cce3fc04022e2ffb16db516a7d --- /dev/null +++ b/app/intapp/controller/index/tplm/modular/index.html @@ -0,0 +1,192 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+
+ +
+ + +
+
+
+
+
{{item.title}}
+
{{item.describes}}
+
+
+ 待安装 + 已安装 + 安装中 + 卸载中 + +
+
+
+
+ 模块名:{{item.name}} +     下载:{{item.dow_num}} +
+
+
更新于:{{time_date(item.updtime)}}
+
+
+
+
+ +
+
+ 加载中... +
+
+ 下一页 + 我已到底了 +
+
+
+ +
+ + 确定 +
+
+
+ + + diff --git a/app/intapp/controller/index/tplm/plan/index.html b/app/intapp/controller/index/tplm/plan/index.html new file mode 100644 index 0000000000000000000000000000000000000000..66335abcb9461d38a29e435b816d40cba44fd281 --- /dev/null +++ b/app/intapp/controller/index/tplm/plan/index.html @@ -0,0 +1,61 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + + +
+ +
+ + + diff --git a/app/intapp/controller/index/tplm/plug/index.html b/app/intapp/controller/index/tplm/plug/index.html new file mode 100644 index 0000000000000000000000000000000000000000..a3e4b254c8505be1c4e1d9d25b23eb7a9680fdc4 --- /dev/null +++ b/app/intapp/controller/index/tplm/plug/index.html @@ -0,0 +1,199 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+
+ +
+ + +
+
+
+
+
{{item.title}}
+
{{item.describes}}
+
+
+ 待安装 + 安装中 + 卸载中 + + 已安装 + 可升级到 {{item.edition[0]}} + + +
+
+
+
+ 插件名:{{item.name}} + +
+
+
发布于:{{time_date(item.addtime)}}
+
+
+
+
+ +
+
+ 加载中... +
+
+ 下一页 + 我已到底了 +
+
+
+ +
+ + 确定 +
+
+
+ + + diff --git a/app/intapp/controller/index/tplm/setup/bacrecpage.html b/app/intapp/controller/index/tplm/setup/bacrecpage.html new file mode 100644 index 0000000000000000000000000000000000000000..36c4bb1989c4b5e39fad6c53636c42297c7e96a7 --- /dev/null +++ b/app/intapp/controller/index/tplm/setup/bacrecpage.html @@ -0,0 +1,184 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/app/intapp/controller/index/tplm/setup/basepage.html b/app/intapp/controller/index/tplm/setup/basepage.html new file mode 100644 index 0000000000000000000000000000000000000000..3961b81aa920c3135b6c3af7c8f2661be2bc9735 --- /dev/null +++ b/app/intapp/controller/index/tplm/setup/basepage.html @@ -0,0 +1,119 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + 保存 + +
+ +
+
+
+ + + diff --git a/app/intapp/controller/index/tplm/setup/index.html b/app/intapp/controller/index/tplm/setup/index.html new file mode 100644 index 0000000000000000000000000000000000000000..82cbf22e6fbac72069ba565dc3cd70890182f09c --- /dev/null +++ b/app/intapp/controller/index/tplm/setup/index.html @@ -0,0 +1,69 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + +
+ + + +
{{item.title}}
+
+
+
+ + + diff --git a/app/intapp/controller/index/tplm/setup/pythonrun.html b/app/intapp/controller/index/tplm/setup/pythonrun.html new file mode 100644 index 0000000000000000000000000000000000000000..50df67920401087013f911f17fc02918765e8a1a --- /dev/null +++ b/app/intapp/controller/index/tplm/setup/pythonrun.html @@ -0,0 +1,299 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+ +
+
+ +
+ + +
+
+
+
+
{{item.title}}
+
{{item.descs}}
+
+
+ + 运行中  + + + 已停止  + + +
+
+
+
+ 运行目录:{{item.paths}} +
+
+
启动文件:{{item.filename}}
+
+
+
+
+ +
+
+ 加载中... +
+
+ 下一页 + 暂无数据 + 我已到底了 +
+
+
+ +
+ + + + + + + + + + + + + + + + + 保存并运行 + 添加并运行 + +
+
+ +
{{runlog}}
+
+ +
+ +
+
+
+ + + diff --git a/app/intapp/controller/index/tplm/setup/startpage.html b/app/intapp/controller/index/tplm/setup/startpage.html new file mode 100644 index 0000000000000000000000000000000000000000..b3f6ac70b7e6a11aaf6f61f54ddd173db72ada75 --- /dev/null +++ b/app/intapp/controller/index/tplm/setup/startpage.html @@ -0,0 +1,153 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + +
+
+
+
+
{{item.name}}
+
执行内容:{{item.value}}
+
+
+
+
+ {{time_date(item.updtime)}} 更新 +
+
+
{{time_date(item.addtime)}} 添加
+
+
+
+
+ +
+
+ 暂无数据 +
+
+ 添加启动项 +
+ + + + + + + + + 添加 + + +
+ +
+
+
+ + + diff --git a/app/intapp/controller/index/tplm/task/index.html b/app/intapp/controller/index/tplm/task/index.html new file mode 100644 index 0000000000000000000000000000000000000000..9f9c5bded0b8d884b354196a119f8ffc8ac3b18b --- /dev/null +++ b/app/intapp/controller/index/tplm/task/index.html @@ -0,0 +1,118 @@ + + + + +kcweb云管 + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ 加载中... +
+
+ 下一页 + 暂无数据 + 我已到底了 +
+
+ + + diff --git a/app/static/js/function.js b/app/static/js/function.js index 9df98f7630274ae61e7bfc73cbbb197d1d81e907..29e6de1d2d77cbafd7287e747eca5d85aa4853b4 100644 --- a/app/static/js/function.js +++ b/app/static/js/function.js @@ -52,7 +52,7 @@ axios_instance.interceptors.response.use(function(res){ Vue.prototype.get=function(url,params,text){ self=this if(text){//self.$message({message: text,type: 'error'}); - var Loading = self.$loading({lock: true,text: text,spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 1)'}); + var Loading = self.$loading({lock: true,text: text,spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'}); } return new Promise(function(resolve,reject){ axios_instance.get(url,{params:params}) @@ -67,6 +67,8 @@ Vue.prototype.get=function(url,params,text){ self.$notify({title: '错误',duration:3000,message: '服务器内部错误',type: 'error'}); }else if(err.response.status==401){ self.$notify({title: '访问受限',duration:5000,message:"您无此时接口权限,可联系管理员申请",type: 'warning'}); + }else if(err.response.status==404){ + self.$notify({title: '404',duration:5000,message:err.response.data.msg,type: 'warning'}); }else{ if (err.response.data.hasOwnProperty('msg')){ msg=err.response.data.msg @@ -139,6 +141,8 @@ Vue.prototype.post=function(url,params,text){ }else{ self.$notify({title: '访问受限',duration:5000,message:"您无此时接口权限,可联系管理员申请",type: 'warning'}); } + }else if(err.response.status==404){ + self.$notify({title: '404',duration:5000,message:err.response.data.msg,type: 'warning'}); }else{ if (err.response.data.hasOwnProperty('msg')){ msg=err.response.data.msg diff --git a/app/static/js/functionm.js b/app/static/js/functionm.js new file mode 100644 index 0000000000000000000000000000000000000000..5d0c540ccc4858799dda16d908599387116a0199 --- /dev/null +++ b/app/static/js/functionm.js @@ -0,0 +1,327 @@ +Vue.prototype.is_url=function(URL){ + var Expression=/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/; + var objExp=new RegExp(Expression); + if(objExp.test(URL)==true){ + return true; + }else{ + return false; + } +} + +Vue.prototype.$axios = axios; +var axios_instance = axios.create({ + // baseURL:'http://intapp.kwebapp.cn', + timeout:600000, + // params:{signparam:''}, + withCredentials: false,// `withCredentials` 表示跨域请求时是否需要使用凭证 + // transformRequest: [function (data) { + // data = Qs.stringify(data); + // return data; + // }], + +}); +//请求拦截 +axios_instance.interceptors.request.use(function(axiosconfig){ + // var login=localStorage.getItem('login'); + // if(login){ + // login=Base64.decode(login); + // login=JSON.parse(login); + // var login_random=Math.ceil(Math.random()*100); + // var login_time=config.time; + // var login_sign=md5(login.password+login_time+login_random); + // config.signparam=Base64.encode(JSON.stringify({'login_random':login_random,'login_id':login.login_id,'login_sign':login_sign,'login_time':login_time})); + // axiosconfig.params.signparam=config.signparam; + // } + // axiosconfig.baseURL='http://intapp.kwebapp.cn'; + return axiosconfig; +},function(error){ + return Promise.reject(error); +}) +//响应拦截 +axios_instance.interceptors.response.use(function(res){ + return res; +},function(error){ + if(error.response.data){ + if(error.response.data.code==-1||error.response.data.code==5){ + window.location.href="/intapp" + } + } + return Promise.reject(error); +}) +//get请求 +Vue.prototype.get=function(url,params,text){ + var self=this + if(text){ + var Loading=self.$toast.loading({message: text,forbidClick: true,duration:0}); + } + return new Promise(function(resolve,reject){ + axios_instance.get(url,{params:params}) + .then(function(res){ + if(text){setTimeout(function(){Loading.clear();},100)} + resolve(res.data); + }) + .catch(function(err){ + if(text){setTimeout(function(){Loading.clear();},100)} + if (err.response) { + if(err.response.status==500){ + self.$notify({title: '错误',duration:3000,message: '服务器内部错误',type: 'warning'}); + }else if(err.response.status==401){ + self.$notify({title: '访问受限',duration:5000,message:"您无此时接口权限,可联系管理员申请",type: 'warning'}); + }else if(err.response.status==404){ + self.$notify({title: '404',duration:5000,message:err.response.data.msg,type: 'warning'}); + }else{ + if (err.response.data.hasOwnProperty('msg')){ + msg=err.response.data.msg + self.$notify({title: '警告',duration:10000,message: msg,type: 'warning'}); + } + } + }else if (err.request){ + self.$notify({message: '无法链接到服务器',type: 'warning'}); + }else{ + self.$notify({message: '网络异常',type: 'warning'}); + } + reject(err) + }) + }) +} +//delete请求 +Vue.prototype.delete=function(url,params,text){ + self=this + if(text){ + var Loading=self.$toast.loading({message: text,forbidClick: true,duration:0}); + } + return new Promise(function(resolve,reject){ + axios_instance.delete(url,{data:params}) + .then(function(res){ + if(text){setTimeout(function(){Loading.clear();},100)} + if(res.data.code==0){ + resolve(res.data); + }else{ + self.$notify({message: res.data.msg,type: 'warning'}); + } + }) + .catch(function(err){ + if(text){setTimeout(function(){Loading.clear();},100)} + if (err.response) { + if (err.response.data.hasOwnProperty('msg')){ + msg=err.response.data.msg + }else{ + msg=err.response.data + } + self.$notify({message: "错误码:"+err.response.status+","+msg,type: 'warning'}); + }else if (err.request){ + self.$notify({message: "无法链接到服务器",type: 'warning'}); + }else{ + self.$notify({message: "网络异常,",type: 'warning'}); + } + reject(err) + }) + }) +} +//post请求 +Vue.prototype.post=function(url,params,text){ + self=this + if(text){ + // var Loading = self.$loading({lock: true,text: text,spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'}); + var Loading=self.$toast.loading({message: text,forbidClick: true,duration:0}); + } + return new Promise(function(resolve,reject){ + axios_instance.post(url,params) + .then(function(res){ + if(text){setTimeout(function(){Loading.clear();},100)} + resolve(res.data); + }) + .catch(function(err){ + if(text){setTimeout(function(){Loading.clear();},100)} + if (err.response) { + if(err.response.status==500){ + self.$notify({title: '错误',duration:3000,message: '服务器内部错误',type: 'warning'}); + }else if(err.response.status==401){ + if (err.response.data.hasOwnProperty('msg')){ + self.$notify({message:err.response.data.msg,type: 'warning'}); + }else{ + self.$notify({message:"您无此时接口权限,可联系管理员申请",type: 'warning'}); + } + }else if(err.response.status==404){ + self.$notify({message:err.response.data.msg,type: 'warning'}); + }else{ + if (err.response.data.hasOwnProperty('msg')){ + msg=err.response.data.msg + self.$notify({message: msg,type: 'warning'}); + } + } + }else if (err.request){ + self.$notify({message: '无法链接到服务器',type: 'warning'}); + }else{ + self.$notify({message: '网络异常',type: 'warning'}); + } + reject(err) + }) + }) +} +//put请求 +Vue.prototype.put=function(url,params,text){ + self=this + if(text){ + // var Loading = self.$loading({lock: true,text: text,spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'}); + var Loading=self.$toast.loading({message: text,forbidClick: true,duration:0}); + } + return new Promise(function(resolve,reject) { + axios_instance.put(url,params) + .then(function(res) { + if(text){setTimeout(function(){Loading.clear();},100)} + if(res.data.code==0){ + resolve(res.data); + }else{ + self.$notify({message: res.data.msg,type: 'warning'}); + } + }) + .catch(function(err) { + if(text){setTimeout(function(){Loading.clear();},100)} + if (err.response) { + if (err.response.data.hasOwnProperty('msg')){ + msg=err.response.data.msg + }else{ + msg=err.response.data + } + self.$notify({message: "错误码:"+err.response.status+","+msg,type: 'warning'}); + }else if (err.request){ + self.$notify({message: "无法链接到服务器",type: 'warning'}); + }else{ + self.$notify({message: "网络异常,",type: 'warning'}); + } + reject(err) + }) + }) +} + +//get请求 获取内容 +Vue.prototype.getcontent=function(url,text,data){ + self=this + var params={}; + if(data){ + params=data; + } + if(text){ + // var Loading = self.$loading({lock: true,text: text,spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'}); + var Loading=self.$toast.loading({message: text,forbidClick: true,duration:0}); + } + return new Promise(function(resolve,reject) { + axios_instance.get(url,{params:params}) + .then(function(res) { + if(text){setTimeout(function(){Loading.clear();},100)} + resolve(res.data); + }) + .catch(function(err){ + if(text){setTimeout(function(){Loading.clear();},100)} + reject(err) + }) + }) +} +//复制内容到剪贴板 +Vue.prototype.copy=function(content){ + if(content){ + let val = content; // 要复制的内容 + document.addEventListener('copy', save); // 监听浏览器copy事件 + document.execCommand('copy'); // 执行copy事件,这时监听函数会执行save函数。 + document.removeEventListener('copy', save); // 移除copy事件 + function save(e) { + e.clipboardData.setData('text/plain', val); // 剪贴板内容设置 + e.preventDefault(); + } + self.$notify({message: "复制成功:",type: 'success'}); + }else{ + self.$notify({message: "内容不能为空:",type: 'warning'}); + } +} + +Vue.prototype.time_date=function(time,datestatus){ + var mytime=Date.parse(new Date())/1000; + var mydate = new Date(mytime*1000); + var myYear=mydate.getFullYear(); + var myMonth=(mydate.getMonth()+1); + var myday=mydate.getDate(); + + var date = new Date(time*1000); + var Year=date.getFullYear(); //if(Year<10){Year="0"+Year;} + var Month=(date.getMonth()+1); //if(Month<10){Month="0"+Month;} + var day=date.getDate(); //if(day<10){day="0"+day;} + var Hours=date.getHours();//if(Hours<10){Hours="0"+Hours;} + var Minutes=date.getMinutes(); if(Minutes<10){Minutes="0"+Minutes;} + var Seconds=date.getSeconds(); if(Seconds<10){Seconds="0"+Seconds;} + if (datestatus){ + return Year+"-"+Month+"-"+day+" "+Hours+":"+Minutes+":"+Seconds; + } + var k=''; + var sjc=mytime-time; + if(sjc<=15){ + k="刚刚"; + }else if(sjc<=60){ + k=sjc+"秒前"; + }else if(sjc<=60*60){ + k=Math.floor(sjc/60)+"分"+sjc%60+"秒前"; + }else if(sjc<=60*60*24*2){ + if(myday==day){ + if(Hours<=6){ + k="凌晨0"+Hours+"点"+Minutes; + }else if(Hours<10){ + k="早上0"+Hours+"点"+Minutes; + }else if(Hours<12){ + k="上午"+Hours+"点"+Minutes; + }else if(Hours==12){ + k="中午"+Hours+"点"+Minutes; + }else if(Hours<=18){ + k="下午"+(Hours)+"点"+Minutes; + }else{ + k="晚上"+(Hours)+"点"+Minutes; + } + }else if(myday==day+1){ + if(Hours<10){Hours="0"+Hours;} + k="昨天"+Hours+"点"+Minutes; + }else if(myday==day+2){ + if(Hours<10){Hours="0"+Hours;} + k="前天"+Hours+"点"+Minutes; + }else{ + k=day+"号"+Hours+"点"+Minutes; + } + }else if(sjc<=60*60*24*30){ + if(day<10){day="0"+day;} + if(myMonth==Month){ + k=day+"号"+Hours+"点"+Minutes + }else{ + if(Month<10){Month="0"+Month;} + k=Month+"月"+day+"号"+Hours+"点"+Minutes + } + }else if(sjc<=60*60*24*30*12){ + if(day<10){day="0"+day;} + if(Year==myYear){ + if(Month<10){Month="0"+Month;} + k=Month+"月"+day+"日"; + }else{ + if(Month<10){Month="0"+Month;} + k=date.getFullYear()+"年"+Month+"月"; + } + }else{ + if(Month<10){Month="0"+Month;} + k=Year+"年"+Month+"月"; + } + return k; +} +Vue.prototype.time_date1=function(time){ + var date = new Date(time*1000); + var dqtime=Date.parse(new Date())/1000; + var k=''; + var sjc=dqtime-time; + if(sjc<=60*60*24){ + k=date.getHours()+":"+date.getMinutes()+":"+date.getSeconds(); + }else if(sjc<=60*60*24*7){ + k=Math.floor(sjc/(60*60*24))+"天前"; + }else if(sjc<=60*60*24*30){ + k=Math.floor(sjc/(60*60*24*7))+"星期前"; + }else if(sjc<=60*60*24*30*12){ + k=(date.getMonth()+1)+"月"+date.getDate()+"日"; + }else{ + k=date.getFullYear()+"年"+(date.getMonth()+1)+"月"; + } + return k; +} \ No newline at end of file diff --git a/kcweb/Events.py b/kcweb/Events.py index 54f63cfa83e20193c84ef53033fa14fcd0605cdc..1e6cd7e298bc3d149e41dc1cbdfec0c2f537d0b9 100644 --- a/kcweb/Events.py +++ b/kcweb/Events.py @@ -15,6 +15,7 @@ class MyFileSystemEventHander(FileSystemEventHandler): eventgtimexz=time.time() # print('* 更新文件:%s' % event.src_path) time.sleep(2) + time.sleep(0.2) self.restart() class Events: command = ['echo', 'ok'] diff --git a/kcweb/app.py b/kcweb/app.py index 6f9e3c86e108154c6279df3a0de90f75b603a31a..ebf10f982bce01a59420027a2bcac8c796167aff 100644 --- a/kcweb/app.py +++ b/kcweb/app.py @@ -10,6 +10,7 @@ from .utill import filetype from kcweb.utill.cache import cache as kcwcache from wsgiref.simple_server import make_server from kcweb.utill.db import mysql as kcwmysql +from kcweb.utill.db import sqlite as kcwsqlite class web: __name=None __appname=None @@ -22,23 +23,36 @@ class web: p=(config.app['staticpath']+env['RAW_URI'].replace(' ','')) status='200 ok' if os.path.isfile(p): - kind = filetype.guess(p) - if kind is None: - f=open(p,"rb") - body=f.read() - f.close() - resheader=[ - ("Cache-Control","public, max-age=43200"), - ] + resheader=[("Cache-Control","public, max-age=2592000"),] + ETag=md5(p) + try: + HTTP_IF_NONE_MATCH=env['HTTP_IF_NONE_MATCH'] + except KeyError: + HTTP_IF_NONE_MATCH=None + if HTTP_IF_NONE_MATCH: + status="304 Not Modified" + body='' else: - f=open(p,"rb") - body=f.read() - f.close() - resheader=[ - ("Content-Type",kind.mime), - ("Cache-Control","public, max-age=43200"), - ("Accept-Ranges","bytes"), - ] + kind = filetype.guess(p) + if kind is None: + f=open(p,"rb") + body=f.read() + f.close() + else: + f=open(p,"rb") + body=f.read() + f.close() + resheader=[ + ("Content-Type",kind.mime), + ("Cache-Control","public, max-age=43200"), + ("Accept-Ranges","bytes"), + ] + resheader.append(('Content-Type',kind.mime)) + resheader.append(("Accept-Ranges","bytes")) + dateArray = datetime.utcfromtimestamp(times()-86400) + otherStyleTime = dateArray.strftime('%a, %d %b %Y %H:%M:%S GMT') + resheader.append(("Last-Modified",otherStyleTime)) + resheader.append(("ETag",ETag)) else: files=None try: @@ -145,19 +159,7 @@ class web: ) except KeyboardInterrupt: pass - def __get_modular(self,header): - "获取模块" - modular='' - route=self.__config.route - if route['modular']: - if isinstance(route['modular'],str): - modular=route['modular'] - else: - HTTP_HOST=header['HTTP_HOST'].split(".")[0] - for mk in route['modular']: - if HTTP_HOST in mk: - modular=mk[HTTP_HOST] - return modular + def __getconfigroute(self,PATH_INFO,header): "使用配置路由" route=self.__config.route @@ -195,10 +197,40 @@ class web: break except:pass return routedefault,PATH_INFO + def __get_modular(self,header): + "获取模块" + modular='' + route=self.__config.route + if route['modular']: + if isinstance(route['modular'],str): + modular=route['modular'] + else: + HTTP_HOST=header['HTTP_HOST'].split(".")[0] + for mk in route['modular']: + if HTTP_HOST in mk: + modular=mk[HTTP_HOST] + return modular + def __get_plug(self,header): + "获取插件" + plug='' + route=self.__config.route + if route['plug']: + if isinstance(route['plug'],str): + plug=route['plug'] + else: + HTTP_HOST=header['HTTP_HOST'].split(".")[0] + for mk in route['plug']: + if HTTP_HOST in mk: + plug=mk[HTTP_HOST] + return plug def defaultroute(self,header,PATH_INFO): "路由匹配" route=self.__config.route modular=web.__get_modular(self,header) + if route['plug']: + getplug=web.__get_plug(self,header) + else: + getplug='' routedefault=route['default'] methods=route['methods'] if routedefault: @@ -216,8 +248,10 @@ class web: ##默认路由start ################################################################################# if modular: - if route['plug']: #匹配模块并且匹配了插件 - plug=route['plug'] + # if route['plug']: #匹配模块并且匹配了插件 + # plug=route['plug'] + if getplug: + plug=getplug routedefault,PATH_INFO=web.__getconfigroute( self, PATH_INFO, @@ -255,8 +289,10 @@ class web: else: param.append(urllib.parse.unquote(path)) i+=1 - elif route['plug']: #配置版本的但没有匹配插件 - plug=route['plug'] + # elif route['plug']: #配置模块但没有匹配插件 + # plug=route['plug'] + elif getplug: + plug=getplug routedefault,PATH_INFO=web.__getconfigroute( self, PATH_INFO, @@ -297,6 +333,7 @@ class web: #默认路由end ############################################################ if not modular: modular=route['defmodular'] + return methods,modular,plug,files,funct,tuple(param) def __tran(self,data,status,resheader): "转换控制器返回的内容" @@ -320,6 +357,7 @@ class web: body=data return body,status,resheader def __set_globals(self,header): + globals.HEADER.GET=header globals.HEADER.Method=header['REQUEST_METHOD'] globals.HEADER.URL=header['RAW_URI'] globals.HEADER.PATH_INFO=header['PATH_INFO'] @@ -567,6 +605,8 @@ class web: #关闭数据库连接 dbs=kcwmysql.mysql() dbs.close() + # dbs=kcwsqlite.sqlite() + # dbs.close() if isinstance(resheaders,list): @@ -639,23 +679,33 @@ class web: p=(config.app['staticpath']+reqheader['RAW_URI'].replace(' ','')) status='200 ok' if os.path.isfile(p): - kind = filetype.guess(p) - if kind is None: - f=open(p,"rb") - body=f.read() - f.close() - resheader=[ - ("Cache-Control","public, max-age=43200"), - ] + resheader=[("Cache-Control","public, max-age=2592000"),("Accept-Ranges","bytes")] + ETag=md5(p) + try: + HTTP_IF_NONE_MATCH=globals.HEADER.GET['HTTP_IF_NONE_MATCH'] + except: + HTTP_IF_NONE_MATCH=None + if HTTP_IF_NONE_MATCH: + status="304 Not Modified" else: - f=open(p,"rb") - body=f.read() - f.close() - resheader=[ - ("Content-Type",kind.mime), - ("Cache-Control","public, max-age=43200"), - ("Accept-Ranges","bytes"), - ] + kind = filetype.guess(p) + if kind is None: + f=open(p,"rb") + body=f.read() + f.close() + if '.css' in p[-5:]: + resheader.append(("Content-Type","text/css")) + elif '.js' in p[-5:]: + resheader.append(("Content-Type","application/javascript")) + else: + f=open(p,"rb") + body=f.read() + f.close() + resheader.append(("Content-Type",kind.mime)) + dateArray = datetime.utcfromtimestamp(times()-86400) + otherStyleTime = dateArray.strftime('%a, %d %b %Y %H:%M:%S GMT') + resheader.append(("Last-Modified",otherStyleTime)) + resheader.append(("ETag",ETag)) else: status,resheader,body=web.__routes(self,reqheader) resheader.append(('Server', "kcweb"+config.kcweb['version'])) diff --git a/kcweb/common/autoload.py b/kcweb/common/autoload.py index 46460b56b0e3756bf4d1f5bde238a6902546efc1..6a5bcb6839bf52a660e7b580ab3681732410c076 100644 --- a/kcweb/common/autoload.py +++ b/kcweb/common/autoload.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -import time,hashlib,json,re,os,platform,sys,shutil,requests,importlib,traceback,pip,gzip,tarfile,zipfile,random +import time,hashlib,json,re,os,platform,sys,shutil,requests,importlib,traceback,pip,gzip,tarfile,zipfile,random,copy import datetime as core_datetime from kcweb import config from kcweb.utill.dateutil.relativedelta import relativedelta as core_relativedelta @@ -12,6 +12,7 @@ from kcweb.utill.http import Http from kcweb.utill.queues import Queues from kcweb.utill.db import model from mako.template import Template as kcwTemplate +from mako.lookup import TemplateLookup import smtplib from email.mime.text import MIMEText from email.utils import formataddr @@ -298,12 +299,23 @@ def Template(path,**context): return Templates(str(config.app['tpl_folder'])+str(path),**context) def Templates(path,**context): "模板渲染引擎函数,需要完整的模板目录文件" - body='' - with open(path, 'r',encoding='utf-8') as f: - content=f.read() - t=kcwTemplate(content) - body=t.render(**context) + lookup = TemplateLookup(directories=['']) + # body='' + # with open(path, 'r',encoding='utf-8') as f: + # contents=f.read() + # t=kcwTemplate(contents,lookup=lookup,module_directory=config.cache['path']+"/Template") + # body=t.render(**context) + + # t=kcwTemplate(filename=path,module_directory=config.cache['path']+"/Template",lookup=lookup) + t=lookup.get_template(path) + body=t.render(**context) return body +def getfunction(strs): + """获取指定文件对象 + + strs :app.index.common.autoload 获取app/index/common/目录下的autoload对象 + """ + return importlib.import_module(strs) def mysql(table=None,configss=None): """mysql数据库操作实例 @@ -575,8 +587,20 @@ class kcwtar: return False class response: - def tpl(path=None,status='200 ok',header={"Content-Type":"text/html; charset=utf-8"},**context): - "返回模板内容" + def tpl(path=None,status='200 ok',response_cache=False,ETag=None,header={"Content-Type":"text/html; charset=utf-8"},**context): + """返回模板内容 + + path 文件地址 + + status 响应状态码 + + response_cache 是否启用浏览器缓存 响应状态码200 ok时有效 + + ETag 缓存标识 响应状态码200 ok时有效 + + header 响应头 + """ + headers=copy.deepcopy(header) getroutecomponent=globals.VAR.component if path: if path[:1]=="/": @@ -585,25 +609,181 @@ class response: Temppath="/"+getroutecomponent[1]+"/controller/"+getroutecomponent[2]+"/tpl/"+path+".html" else: Temppath="/"+getroutecomponent[1]+"/controller/"+getroutecomponent[2]+"/tpl/"+getroutecomponent[3]+"/"+getroutecomponent[4]+".html" - return Template(Temppath,config=config,**context),status,header - def json(res=[],status='200 ok',header={"Content-Type":"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}): - "响应json内容" - return json_encode(res),status,header - def pic(body): + if status=='200 ok' and response_cache: + if not ETag: + ttt='' + for k in context.keys(): + ttt+=k+str(context[k]) + ETag=md5(Temppath+ttt+globals.HEADER.URL) + try: + HTTP_IF_NONE_MATCH=globals.HEADER.GET['HTTP_IF_NONE_MATCH'] + except: + HTTP_IF_NONE_MATCH=None + if HTTP_IF_NONE_MATCH and get_cache(ETag): + status="304 Not Modified" + body='' + else: + if isinstance(response_cache,int) and response_cache>1: + headers['response_cache']=str(response_cache)+" s" + set_cache(ETag,1,response_cache) + else: + headers['response_cache']="default" + set_cache(ETag,1) + body=Template(Temppath,config=config,**context) + dateArray = core_datetime.datetime.utcfromtimestamp(times()-86400) + otherStyleTime = dateArray.strftime('%a, %d %b %Y %H:%M:%S GMT') + headers['Last-Modified']=otherStyleTime + headers['ETag']=ETag + return body,status,headers + elif status: + return Template(Temppath,config=config,**context),status,headers + else: + return Template(Temppath,config=config,**context),'200 ok',headers + def json(res=[],status='200 ok',response_cache=False,ETag=None,header={"Content-Type":"application/json; charset=utf-8","Access-Control-Allow-Origin":"*"}): + """响应json内容 + + res body内容 + + status 响应状态码 + + response_cache 是否启用浏览器缓存 响应状态码200 ok时有效 + + ETag 缓存标识 响应状态码200 ok时有效 + + header 响应头 + """ + headers=copy.deepcopy(header) + if status=='200 ok' and response_cache: + if not ETag: + ETag=md5(globals.HEADER.URL) + try: + HTTP_IF_NONE_MATCH=globals.HEADER.GET['HTTP_IF_NONE_MATCH'] + except: + HTTP_IF_NONE_MATCH=None + if(HTTP_IF_NONE_MATCH and get_cache(ETag)): + status="304 Not Modified" + body='' + else: + if isinstance(response_cache,int) and response_cache>1: + set_cache(ETag,1,response_cache) + headers['response_cache']=str(response_cache)+" s" + else: + set_cache(ETag,1) + headers['response_cache']="default" + body=json_encode(res) + dateArray = core_datetime.datetime.utcfromtimestamp(times()-86400) + otherStyleTime = dateArray.strftime('%a, %d %b %Y %H:%M:%S GMT') + headers['Last-Modified']=otherStyleTime + headers['ETag']=ETag + + else: + body=json_encode(res) + return body,status,headers + def pic(body,response_cache=True,ETag=None): """输出图片 - body 图片二进制内容或图片路径 + body 图片二进制内容或图片路径 建议使用图片路径 + + response_cache 是否启用浏览器缓存 body使用图片路径时有效 + + ETag 缓存标识 """ + status='200 ok' + header={"Cache-Control":"public, max-age=2592000"} if isinstance(body,str): - filename=body - f=open(filename,"rb") - body=f.read() - f.close() - kind = filetype.guess(filename) - ContentType=kind.mime + if response_cache: + if not ETag: + ETag=md5(body+globals.HEADER.URL) + try: + HTTP_IF_NONE_MATCH=globals.HEADER.GET['HTTP_IF_NONE_MATCH'] + except: + HTTP_IF_NONE_MATCH=None + if(HTTP_IF_NONE_MATCH and get_cache(ETag)): + status="304 Not Modified" + body='' + else: + if isinstance(response_cache,int) and response_cache>1: + set_cache(ETag,1,response_cache) + else: + set_cache(ETag,1) + filename=body + f=open(filename,"rb") + body=f.read() + f.close() + kind = filetype.guess(filename) + try: + header['Content-Type']=kind.mime + except: + header['Content-Type']="image/png" + else: + filename=body + f=open(filename,"rb") + body=f.read() + f.close() + kind = filetype.guess(filename) + try: + header['Content-Type']=kind.mime + except: + header['Content-Type']="image/png" + dateArray = core_datetime.datetime.utcfromtimestamp(times()-86400) + otherStyleTime = dateArray.strftime('%a, %d %b %Y %H:%M:%S GMT') + header['Last-Modified']=otherStyleTime + header['ETag']=ETag + else: + header['Content-Type']="image/png" + return body,status,header + def video(body): + """输出音频 + + body 音频二进制内容或音频路径 + """ + status='200 ok' + header={"Cache-Control":"public, max-age=2592000"} + if isinstance(body,str): + ETag=md5(body) + try: + HTTP_IF_NONE_MATCH=globals.HEADER.GET['HTTP_IF_NONE_MATCH'] + except: + HTTP_IF_NONE_MATCH=None + if(HTTP_IF_NONE_MATCH and get_cache(ETag)): + status="304 Not Modified" + body='' + else: + set_cache(ETag,1,2592000) + filename=body + f=open(filename,"rb") + body=f.read() + f.close() + kind = filetype.guess(filename) + try: + header['Content-Type']=kind.mime + except: + header['Content-Type']="video/mp4" + dateArray = core_datetime.datetime.utcfromtimestamp(times()-86400) + otherStyleTime = dateArray.strftime('%a, %d %b %Y %H:%M:%S GMT') + header['Last-Modified']=otherStyleTime + header['ETag']=ETag else: - ContentType="image/png" - return body,'200 ok',{"Content-Type":ContentType,"Cache-Control":"public, max-age=60"} + header['Content-Type']="video/mp4" + return body,status,header + # def video(body): + # """输出音频 + + # body 音频二进制内容或音频路径 + # """ + # if isinstance(body,str): + # filename=body + # f=open(filename,"rb") + # body=f.read() + # f.close() + # kind = filetype.guess(filename) + # try: + # ContentType=kind.mime + # except: + # ContentType="video/mp4" + # else: + # ContentType="video/mp4" + # return body,'200 ok',{"Content-Type":ContentType,"Cache-Control":"public, max-age=600"} def download(pathname): """下载文件 @@ -676,10 +856,10 @@ class create: while True: timestamp=times() sign=md5(str(username)+str(timestamp)+md5(md5(password))) - http.set_header['username']=username - http.set_header['timestamp']=str(timestamp) - http.set_header['sign']=sign - http.openurl(config.domain['kcwebapi']+"/user/userinfo") + # http.set_header['username']=username + # http.set_header['timestamp']=str(timestamp) + # http.set_header['sign']=sign + http.openurl(config.domain['kcwebapi']+"/user/userinfo/?username="+username+"×tamp="+str(timestamp)+"&sign="+sign) arr=json_decode(http.get_text) if not arr: os.remove(self.appname+"/"+self.modular+"/controller/"+plug+".zip") @@ -703,7 +883,7 @@ class create: else: os.remove(self.appname+"/"+self.modular+"/controller/"+plug+".zip") return False,arr['msg'] - http.openurl(config.domain['kcwebapi']+"/user/uploadplug/",'POST', + http.openurl(config.domain['kcwebapi']+"/user/uploadplug/?username="+username+"×tamp="+str(timestamp)+"&sign="+sign,'POST', data={'name':str(plug),'describes':'','modular':self.modular}, files={'file':open(self.appname+"/"+self.modular+"/controller/"+plug+".zip", 'rb')}) arr=json_decode(http.get_text) @@ -718,6 +898,9 @@ class create: elif arr['code']==0: os.remove(self.appname+"/"+self.modular+"/controller/"+plug+".zip") return True,arr['msg'] + elif arr['code']==0: + os.remove(self.appname+"/"+self.modular+"/controller/"+plug+".zip") + return False,arr['msg'] else: os.remove(self.appname+"/"+self.modular+"/controller/"+plug+".zip") return False,arr['msg'] @@ -732,10 +915,11 @@ class create: else: http=Http() i=0 + j=0 tplug=plug modular=self.modular while True: - http.openurl(config.domain['kcwebapi']+"/pub/plug","POST",data={"modular":modular,"name":str(tplug),"edition":str(edition),"token":token}) + http.openurl(config.domain['kcwebapi']+"/pub/plug","GET",params={"modular":modular,"name":str(tplug),"edition":str(edition),"token":token}) arr=json_decode(http.get_text) if arr: if arr['code']==-1 and cli: @@ -752,6 +936,8 @@ class create: modular="api" tplug="index" #默认插件 elif arr['code']==0 and arr['data']: + i=0 + j+=1 arr=arr['data'] r=requests.get(arr['dowurl']) f = open(self.appname+"/"+self.modular+"/controller/"+plug+".zip", "wb") @@ -759,75 +945,82 @@ class create: if chunk: f.write(chunk) f.close() - if os.path.isfile(self.appname+"/"+self.modular+"/controller/"+plug+".zip"):#安装打包好的插件 - zip.unzip_file(self.appname+"/"+self.modular+"/controller/"+plug+".zip",self.appname+"/"+self.modular+"/controller/"+plug+"/") - os.remove(self.appname+"/"+self.modular+"/controller/"+plug+".zip") - if os.path.isfile(self.appname+"/"+self.modular+"/controller/"+plug+"/install.txt"): #安装依赖包 - install_requires=[] - try: - f=open(self.appname+"/"+self.modular+"/controller/"+plug+"/install.txt") - while True: - line = f.readline() - if not line: - break - elif len(line) > 2: - install_requires.append(line) - f.close() - except: - shutil.rmtree(self.appname+"."+self.modular+"/controller/"+plug) - return False,"error" - if len(install_requires): - try: - install_requires.insert(0,"install") - if 0 != pip.main(install_requires): - shutil.rmtree(self.appname+"/"+self.modular+"/controller/"+plug) - return False,"error" - except AttributeError as e: - shutil.rmtree(self.appname+"/"+self.modular+"/controller/"+plug) - if config.app['app_debug']: - print("建议更新您的pip版本。参考命令:Python -m pip install --user --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/") - return False,str(e) - # try: - # m=importlib.import_module(self.appname+"."+self.modular+"/controller/"+plug+".install") - # except: - # shutil.rmtree(self.appname+"."+self.modular+"/controller/"+plug) - # print(traceback.format_exc()) - # return False,"插件依赖包文件不存在或依赖包文件格式错误" - # else: - # try: - # a=m.install() - # except: - # shutil.rmtree(self.appname+"."+self.modular+"/controller/"+plug) - # return False,"插件依赖包install函数被破坏" - # if not a[0]: - # shutil.rmtree(self.appname+"."+self.modular+"/controller/"+plug) - # return False,str(a[1]) - - f=open(self.appname+"/"+self.modular+"/controller/__init__.py","r",encoding='utf-8') - text=f.read() - f.close() - text=re.sub("\nfrom . import "+plug,"",text) - text=re.sub("from . import "+plug,"",text) - f=open(self.appname+"/"+self.modular+"/controller/__init__.py","w",encoding='utf-8') - text+="\nfrom . import "+plug - f.write(text) - f.close() - - f=open(self.appname+"/"+self.modular+"/controller/"+plug+"/common/autoload.py","r",encoding='utf-8') - text=f.read() - f.close() - text=re.sub("app.api",self.appname+"."+self.modular,text) - f=open(self.appname+"/"+self.modular+"/controller/"+plug+"/common/autoload.py","w",encoding='utf-8') - f.write(text) - f.close() - - return True,"插件安装成功,"+plug+"=="+str(arr['edition']) - else: + if zipfile.is_zipfile(self.appname+"/"+self.modular+"/controller/"+plug+".zip") and os.path.isfile(self.appname+"/"+self.modular+"/controller/"+plug+".zip"): + break + if j >= 10: return False,str(plug)+"插件下载失败" + time.sleep(0.1) else: - return False,str(plug)+"插件下载失败" + return False,str(plug)+"插件搜索失败" else: return False,self.modular+"模块下找不到"+str(plug)+"插件" + if os.path.isfile(self.appname+"/"+self.modular+"/controller/"+plug+".zip"):#安装打包好的插件 + zip.unzip_file(self.appname+"/"+self.modular+"/controller/"+plug+".zip",self.appname+"/"+self.modular+"/controller/"+plug+"/") + os.remove(self.appname+"/"+self.modular+"/controller/"+plug+".zip") + if os.path.isfile(self.appname+"/"+self.modular+"/controller/"+plug+"/install.txt"): #安装依赖包 + install_requires=[] + try: + f=open(self.appname+"/"+self.modular+"/controller/"+plug+"/install.txt") + while True: + line = f.readline() + if not line: + break + elif len(line) > 2: + install_requires.append(line) + f.close() + except: + shutil.rmtree(self.appname+"."+self.modular+"/controller/"+plug) + return False,"error" + if len(install_requires): + try: + install_requires.insert(0,"install") + if 0 != pip.main(install_requires): + shutil.rmtree(self.appname+"/"+self.modular+"/controller/"+plug) + return False,"error" + except AttributeError as e: + shutil.rmtree(self.appname+"/"+self.modular+"/controller/"+plug) + if config.app['app_debug']: + print("建议更新您的pip版本。参考命令:Python -m pip install --user --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/") + return False,str(e) + if os.path.isfile(self.appname+"."+self.modular+"/controller/"+plug+"/install.py"): + try: + m=importlib.import_module(self.appname+"."+self.modular+"/controller/"+plug+".install") + except: + shutil.rmtree(self.appname+"."+self.modular+"/controller/"+plug) + print(traceback.format_exc()) + return False,"插件依赖包文件不存在或依赖包文件格式错误" + else: + try: + a=m.install() + except: + shutil.rmtree(self.appname+"."+self.modular+"/controller/"+plug) + return False,"插件依赖包install函数被破坏" + # if not a[0]: + # shutil.rmtree(self.appname+"."+self.modular+"/controller/"+plug) + # return False,str(a[1]) + + f=open(self.appname+"/"+self.modular+"/controller/__init__.py","r",encoding='utf-8') + text=f.read() + f.close() + text=re.sub("\nfrom . import "+plug,"",text) + text=re.sub("from . import "+plug,"",text) + f=open(self.appname+"/"+self.modular+"/controller/__init__.py","w",encoding='utf-8') + text+="\nfrom . import "+plug + f.write(text) + f.close() + + f=open(self.appname+"/"+self.modular+"/controller/"+plug+"/common/autoload.py","r",encoding='utf-8') + text=f.read() + f.close() + text=re.sub("app.api",self.appname+"."+self.modular,text) + f=open(self.appname+"/"+self.modular+"/controller/"+plug+"/common/autoload.py","w",encoding='utf-8') + f.write(text) + f.close() + + + return True,"插件安装成功,"+plug+"=="+str(arr['edition']) + else: + return False,str(plug)+"插件获取失败" def uninstallmodular(self): "卸载模块" f=open(self.appname+"/__init__.py","r") @@ -857,10 +1050,10 @@ class create: while True: timestamp=times() sign=md5(str(username)+str(timestamp)+md5(md5(password))) - http.set_header['username']=username - http.set_header['timestamp']=str(timestamp) - http.set_header['sign']=sign - http.openurl(config.domain['kcwebapi']+"/user/uploadmodular/",'POST', + # http.set_header['username']=username + # http.set_header['timestamp']=str(timestamp) + # http.set_header['sign']=sign + http.openurl(config.domain['kcwebapi']+"/user/uploadmodular/?username="+username+"×tamp="+str(timestamp)+"&sign="+sign,'POST', data={'name':str(self.modular),'describes':''}, files={'file':open(self.appname+"/"+self.modular+".zip", 'rb')}) arr=json_decode(http.get_text) @@ -890,7 +1083,7 @@ class create: os.remove(self.appname+"/"+self.modular+".zip") return False,arr['msg'] - http.openurl(config.domain['kcwebapi']+"/user/uploadmodular/",'POST', + http.openurl(config.domain['kcwebapi']+"/user/uploadmodular/?username="+username+"×tamp="+str(timestamp)+"&sign="+sign,'POST', data={'name':str(self.modular),'describes':''}, files={'file':open(self.appname+"/"+self.modular+".zip", 'rb')}) arr=json_decode(http.get_text) @@ -940,11 +1133,31 @@ class create: "from "+self.appname+" import config\n"+ "G=globals.G") f.close() + + content='' + f=open(self.appname+"/"+self.modular+"/common/autoload.py","r",encoding='utf-8') + while True: + line = f.readline() + if not line: + break + elif 'from' not in line and 'import' not in line: + content+=line + f.close() f=open(self.appname+"/"+self.modular+"/common/autoload.py","w",encoding='utf-8') - f.write("from "+self.appname+".common import *") + f.write("from "+self.appname+".common import *\n"+content) + f.close() + + content='' + f=open(self.appname+"/"+self.modular+"/controller/index/common/autoload.py","r",encoding='utf-8') + while True: + line = f.readline() + if not line: + break + elif 'from' not in line and 'import' not in line: + content+=line f.close() f=open(self.appname+"/"+self.modular+"/controller/index/common/autoload.py","w",encoding='utf-8') - f.write("from "+self.appname+"."+self.modular+".common import *") + f.write("from "+self.appname+"."+self.modular+".common import *\n"+content) f.close() return True,"应用创建成功" else: @@ -957,7 +1170,7 @@ class create: i=0 modular=self.modular while True: - http.openurl(config.domain['kcwebapi']+"/pub/modular","POST",data={"name":modular,"token":token}) + http.openurl(config.domain['kcwebapi']+"/pub/modular","POST",params={"name":modular,"token":token}) arr=json_decode(http.get_text) if arr: if arr['code']==-1 and cli: @@ -974,12 +1187,19 @@ class create: modular="api" elif arr['code']==0 and arr['data']: arr=arr['data'] - r=requests.get(arr['dowurl']) - f = open(self.appname+"/"+self.modular+".zip", "wb") - for chunk in r.iter_content(chunk_size=1024*100): - if chunk: - f.write(chunk) - f.close() + #循环下载模块 + i=0 + while i < 5: + r=requests.get(arr['dowurl']) + f = open(self.appname+"/"+self.modular+".zip", "wb") + for chunk in r.iter_content(chunk_size=1024*100): + if chunk: + f.write(chunk) + f.close() + time.sleep(0.3) + if os.path.isfile(self.appname+"/"+self.modular+".zip"): + break + i+=1 if os.path.isfile(self.appname+"/"+self.modular+".zip"):#安装打包好的模块 zip.unzip_file(self.appname+"/"+self.modular+".zip",self.appname+"/"+self.modular+"/") os.remove(self.appname+"/"+self.modular+".zip") @@ -1009,33 +1229,51 @@ class create: if config.app['app_debug']: print("建议更新您的pip版本。参考命令:Python -m pip install --user --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/") return False,str(e) - # try: - # m=importlib.import_module(self.appname+'.'+self.modular+'.install') - # except: - # shutil.rmtree(self.appname+"/"+self.modular) - # print(traceback.format_exc()) - # return False,"模块依赖包文件不存在或依赖包文件格式错误" - # else: - # try: - # a=m.install() - # except: - # shutil.rmtree(self.appname+"/"+self.modular) - # return False,"模块依赖包install方法被破坏" - # if not a[0]: - # shutil.rmtree(self.appname+"/"+self.modular) - # return False,str(a[1]) + if os.path.isfile(self.appname+"/"+self.modular+"/install.py"):#如果存在依赖文件 + try: + m=importlib.import_module(self.appname+'.'+self.modular+'.install') + except: + shutil.rmtree(self.appname+"/"+self.modular) + print(traceback.format_exc()) + return False,"模块依赖包文件不存在或依赖包文件格式错误" + else: + try: + a=m.install() + except: + shutil.rmtree(self.appname+"/"+self.modular) + return False,"模块依赖包install方法被破坏" + # if not a[0]: + # shutil.rmtree(self.appname+"/"+self.modular) + # return False,str(a[1]) content="\nfrom . import "+self.modular f=open(self.appname+"/__init__.py","a",encoding='utf-8') f.write(content) f.close() - + content='' + f=open(self.appname+"/"+self.modular+"/common/autoload.py","r",encoding='utf-8') + while True: + line = f.readline() + if not line: + break + elif 'from' not in line and 'import' not in line: + content+=line f.close() f=open(self.appname+"/"+self.modular+"/common/autoload.py","w",encoding='utf-8') - f.write("from "+self.appname+".common import *") + f.write("from "+self.appname+".common import *\n"+content) + f.close() + + content='' + f=open(self.appname+"/"+self.modular+"/controller/index/common/autoload.py","r",encoding='utf-8') + while True: + line = f.readline() + if not line: + break + elif 'from' not in line and 'import' not in line: + content+=line f.close() f=open(self.appname+"/"+self.modular+"/controller/index/common/autoload.py","w",encoding='utf-8') - f.write("from "+self.appname+"."+self.modular+".common import *") + f.write("from "+self.appname+"."+self.modular+".common import *\n"+content) f.close() else: return False,self.modular+"模块下载失败" diff --git a/kcweb/common/request.py b/kcweb/common/request.py index 3468bdfa6aa825dc7f8747f8e9dce7c7ad717cbf..4a65a1da2cf0d87911d532912817df0b22802c60 100644 --- a/kcweb/common/request.py +++ b/kcweb/common/request.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from kcweb.common import globals as kcwglobals -from urllib import parse -import json +import json,urllib class args: "获取url" + def params(): + return urllib.parse.parse_qs(urllib.parse.urlparse(kcwglobals.HEADER.URL).query) def get(name): """获取键值对 @@ -11,11 +12,11 @@ class args: return 值 """ - params = parse.parse_qs(parse.urlparse(kcwglobals.HEADER.URL).query) + params = args.params() try: k=params[name][0] except: - k=None + k='' return k def get_json(): """获取 json get内容 @@ -41,9 +42,9 @@ class froms: return 值 """ data=kcwglobals.HEADER.BODY_DATA - params = parse.parse_qs(parse.urlparse("?"+str(data)).query) + params = urllib.parse.parse_qs(urllib.parse.urlparse("?"+str(data)).query) try: - k=parse.unquote(params[name][0]) + k=urllib.parse.unquote(params[name][0]) except: k=None return k @@ -57,7 +58,7 @@ class froms: data={} for k in lists: ar=k.split("=") - data[ar[0]]=ar[1] + data[ar[0]]=urllib.parse.unquote(ar[1]) return data except:return None class binary: @@ -101,6 +102,8 @@ class binary: else: return None class HEADER: + def GET(): + return kcwglobals.HEADER.GET def Method(): return kcwglobals.HEADER.Method def URL(): @@ -111,6 +114,10 @@ class HEADER: return kcwglobals.HEADER.SERVER_PROTOCOL def HTTP_HOST(): return kcwglobals.HEADER.HTTP_HOST + def HTTP_COOKIE(): + return kcwglobals.HEADER.HTTP_COOKIE + def HTTP_USER_AGENT(): + return kcwglobals.HEADER.HTTP_USER_AGENT def get_data(): "获取请求参数体" return kcwglobals.HEADER.BODY_DATA diff --git a/kcweb/config/__init__.py b/kcweb/config/__init__.py index 8734767d36c6f633c80eff314f2d5cef0cccc19f..dfb4d200e325fe619d945bf52b2e051a733382f3 100644 --- a/kcweb/config/__init__.py +++ b/kcweb/config/__init__.py @@ -55,7 +55,7 @@ database['port']=[3306] #端口 [端口1,端口2,端口3...] database['user']=['root'] #用户名 [用户名1,用户名2,用户名3...] database['password']=['root'] #密码 [密码1,密码2,密码3...] database['db']=['test'] #数据库名 [数据库名1,数据库名2,数据库名3...] -database['charset']='utf8' #数据库编码默认采用utf8 +database['charset']='utf8mb4' #数据库编码默认采用utf8mb4 database['pattern']=False # True数据库长连接模式 False数据库短连接模式 注:建议web应用有效,cli应用方式下,如果长时间运行建议使用mysql().close()关闭 database['cli']=app['cli'] # 是否以cli方式运行 database['dbObjcount']=1 # 连接池数量(单个数据库地址链接数量),数据库链接实例数量 mysql长链接模式下有效 @@ -100,7 +100,7 @@ email['recNick']='' #默认收件人昵称 kcweb={} kcweb['name']='kcweb' #项目的名称 -kcweb['version']='4.11.9' #项目版本 +kcweb['version']='4.12.3' #项目版本 kcweb['description']='' #项目的简单描述 kcweb['long_description']='' #项目详细描述 kcweb['license']='MIT' #开源协议 mit开源 @@ -116,6 +116,7 @@ domain={} domain['kcwebfile']="https://file.kwebapp.cn" domain['kcwebstatic']="https://static.kwebapp.cn" domain['kcwebimg']="https://img.kwebapp.cn" +# domain['kcwebapi']="https://kcweb.kwebapp.cn" domain['kcwebapi']="https://kcweb.kwebapp.cn" #其他配置 diff --git a/kcweb/setup.py b/kcweb/setup.py index 556d8b25f36f615713167cdb5c662822f5548ec6..db8bfac6cc0b70c06cc8241b0d09801340097055 100644 --- a/kcweb/setup.py +++ b/kcweb/setup.py @@ -16,7 +16,7 @@ def file_get_content(k): return con confkcw={} confkcw['name']='kcweb' #项目的名称 -confkcw['version']='4.12.0' #项目版本 +confkcw['version']='4.12.3' #项目版本 confkcw['description']='' #项目的简单描述 confkcw['long_description']="增加websocket" #项目详细描述 confkcw['license']='MIT License' #开源协议 mit开源 diff --git a/kcweb/utill/cache/cache.py b/kcweb/utill/cache/cache.py index 710b8540fd57d6d7bc044825d311927e145b20fa..8df20e7079fabaf114a35273f14c9b8e1c4b483e 100644 --- a/kcweb/utill/cache/cache.py +++ b/kcweb/utill/cache/cache.py @@ -235,7 +235,7 @@ class cache: try: f=open(self.__config['path']+"/"+self.__name,"r") except Exception: - return None + return "" json_str=f.read() f.close() ar=json_decode(json_str) @@ -244,7 +244,7 @@ class cache: if (times()-ar['time']) > ar['expire']: self.__delfilecache() - return None + return "" else: return ar['values'] else: diff --git a/kcweb/utill/db/mysql.py b/kcweb/utill/db/mysql.py index 52f1f8dfea7884590590a1cc68c621136a3c28cc..3dffb8d54c8507b74b3a364242b1fd5e82a59d39 100644 --- a/kcweb/utill/db/mysql.py +++ b/kcweb/utill/db/mysql.py @@ -2,7 +2,7 @@ from .pymysql import connect,escape_string # import config.conf as config import kcweb.config as config -import time,traceback,decimal,random +import time,traceback,decimal,random,copy dbconfig=config.database class mysql: """数据库实例""" @@ -20,7 +20,7 @@ class mysql: def __del__(self): pass def close(self): - "关闭连接,该方法无需理会,框架自动完成" + "关闭连接,web一下模式下该方法无需理会,框架自动完成" if not self.__config['pattern'] and mysql.__conn: if self.__connlists: for k in self.__connlists: @@ -38,7 +38,7 @@ class mysql: i=0 for thost in self.__config['host']: identifier=thost+str(self.__config['port'][i])+self.__config['user'][i]+self.__config['password'][i]+self.__config['db'][i] - print(mysql.__conn) + # print(mysql.__conn) for k in mysql.__conn[identifier]: try: k['obj'].close() @@ -55,6 +55,7 @@ class mysql: mysql.__conn={} if self.__config['debug']: print("mysql短连接已关闭",mysql.__conn) + mysql.__config=copy.deepcopy(dbconfig) __dbcount=1 def __setdbcount(self): "设置数据库配置总数量" @@ -228,6 +229,7 @@ class mysql: print("无法链接到数据库服务器,准备第%d次重新链接:%s" % (self.__errorcounts,e)) self.__connects(typess) else: + # self.__config=copy.deepcopy(dbconfig) self.__errorcounts=0 raise Exception(e) else: @@ -237,6 +239,7 @@ class mysql: print("无法链接到数据库服务器,开始重新链接") self.__connects(typess) else: + # self.__config=copy.deepcopy(dbconfig) self.__errorcounts=0 raise Exception(e) else: @@ -431,6 +434,7 @@ class mysql: description=self.__cursor.description #获取字段 result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() + self.__None() if description is None: return res else: @@ -458,6 +462,7 @@ class mysql: description=self.__cursor.description #获取字段 result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() + self.__None() if description is None: return res else: @@ -492,6 +497,7 @@ class mysql: description=self.__cursor.description #获取字段 result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() + self.__None() lists=[] keys =[] for field in description:#获取字段 @@ -523,7 +529,7 @@ class mysql: description=self.__cursor.description #获取字段 result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() - + self.__None() item = dict() keys =[] for field in description:#获取字段 @@ -546,11 +552,19 @@ class mysql: self.__setsql('count') if self.__buildSql: self.__sqls="("+self.__sql+")" + self.__None() return self.__sql self.__execute() result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() - cou=int(result[0][0]) + if self.__group: + cou=len(result) + else: + try: + cou=int(result[0][0]) + except IndexError: + cou=0 + # self.__None() return cou def max(self,field): """查询某字段的最大值 @@ -561,11 +575,13 @@ class mysql: self.__setsql('max') if self.__buildSql: self.__sqls="("+self.__sql+")" + self.__None() return self.__sql self.__execute() result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() cou=int(result[0][0]) + self.__None() return cou def min(self,field): """查询某字段的最小值 @@ -576,10 +592,12 @@ class mysql: self.__setsql('min') if self.__buildSql: self.__sqls="("+self.__sql+")" + self.__None() return self.__sql self.__execute() result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() + self.__None() cou=int(result[0][0]) return cou def avg(self,field): @@ -591,10 +609,12 @@ class mysql: self.__setsql('avg') if self.__buildSql: self.__sqls="("+self.__sql+")" + self.__None() return self.__sql self.__execute() result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() + self.__None() cou=int(result[0][0]) return cou def sum(self,field): @@ -606,14 +626,35 @@ class mysql: self.__setsql('sum') if self.__buildSql: self.__sqls="("+self.__sql+")" + self.__None() return self.__sql self.__execute() result = self.__cursor.fetchall() #获取查询结果 self.__cursor.close() + self.__None() cou=int(result[0][0]) return cou - + def setinc(self,field,key=1,affair=False): + """更新字段增加 + + 参数 field 要更新的字段 + + 参数 key 字段需要加多少 + + 参数 affair 是否开启事务 True表示手动提交事务 False表示自动提交事务 + """ + data={"field":field,"key":key} + self.__setsql('setinc',data) + res=self.__execute('DML') + if affair==False and self.__startTrans==False: + if not self.__config['pattern']: + self.__conn[self.__masteridentifier].commit() + else: + self.__conn[self.__masteridentifier][self.__dbobjident]['obj'].commit() + self.__cursor.close() + self.__None() + return res def update(self,data,affair=False): """数据表更新 @@ -629,6 +670,7 @@ class mysql: else: self.__conn[self.__masteridentifier][self.__dbobjident]['obj'].commit() self.__cursor.close() + self.__None() return res def delete(self,affair=False): """数据表删除 @@ -646,6 +688,7 @@ class mysql: else: self.__conn[self.__masteridentifier][self.__dbobjident]['obj'].commit() self.__cursor.close() + self.__None() return res def insert(self,dicts,affair=False): """插入数据库 单条插入或多条插入 @@ -664,6 +707,7 @@ class mysql: else: self.__conn[self.__masteridentifier][self.__dbobjident]['obj'].commit() self.__cursor.close() + self.__None() return res __startTrans=False @@ -754,13 +798,18 @@ class mysql: self.__field=field return self __limit=[] - def limit(self,offset, length = None): + def limit(self,offset=1, length = None): """设置查询数量 参数 offset:int 起始位置 参数 length:int 查询数量 """ + if not offset: + offset=1 + offset=int(offset) + if length: + length=int(length) self.__limit=[offset,length] return self def page(self,pagenow=1, length = 20): @@ -770,6 +819,12 @@ class mysql: 参数 length:int 查询数量 """ + if not pagenow: + pagenow=1 + if not length: + length=20 + pagenow=int(pagenow) + length=int(length) offset=(pagenow-1)*length self.__limit=[offset,length] return self @@ -892,6 +947,8 @@ class mysql: self.__sql="SELECT AVG(%s) FROM %s" % (self.__field,self.__table) elif types=='sum': self.__sql="SELECT SUM(%s) FROM %s" % (self.__field,self.__table) + elif types=='setinc': + self.__sql="update %s set %s=%s+%s" % (self.__table,data['field'],data['field'],data['key']) elif types=='update': strs='' for k in data: @@ -961,6 +1018,12 @@ class mysql: self.__sql=self.__sql + " WHERE %s" % self.__listTrans() else: print("参数where类型错误") + if self.__group: + s=self.__group + if self.__group1: + for key in self.__group1: + s=s+","+key + self.__sql=self.__sql+" GROUP BY "+s if self.__order: s='' if isinstance(self.__order,list): @@ -994,12 +1057,6 @@ class mysql: else: s=self.__order self.__sql=self.__sql+" ORDER BY "+s - if self.__group: - s=self.__group - if self.__group1: - for key in self.__group1: - s=s+","+key - self.__sql=self.__sql+" GROUP BY "+s if self.__having: self.__sql=self.__sql+" HAVING "+self.__having if self.__limit: diff --git a/kcweb/utill/db/sqlite copy.py b/kcweb/utill/db/sqlite copy.py new file mode 100644 index 0000000000000000000000000000000000000000..ba6140e4864d52bc452e473eb630d9a117debd11 --- /dev/null +++ b/kcweb/utill/db/sqlite copy.py @@ -0,0 +1,685 @@ +# -*- coding: utf-8 -*- +from kcweb.config import sqlite as sqliteconfig +import time,traceback,re +import random,sqlite3,os,hashlib +class sqlite: + __config=sqliteconfig + __configt={} + __conn={} + __cursor={} + __sql=None + __sqls=None + def md5(self,strs): + """md5加密 + + 参数 strs:要加密的字符串 + + return String类型 + """ + m = hashlib.md5() + b = strs.encode(encoding='utf-8') + m.update(b) + return m.hexdigest() + def close(self): + "关闭连接" + for k in sqlite.__conn.keys(): + sqlite.__cursor[k].close() + sqlite.__conn[k].close() + sqlite.__conn={} + sqlite.__cursor={} + sqlite.__configt={} + def __setconn(self): + if not self.__configt: + self.__configt=sqliteconfig + try: + self.__conn[self.md5(self.__configt['db'])] + except KeyError: + try: + if '/' in self.__configt['db']: + self.__conn[self.md5(self.__configt['db'])] = sqlite3.connect(self.__configt['db'],check_same_thread=False) + else: + self.__conn[self.md5(self.__configt['db'])] = sqlite3.connect(os.path.split(os.path.realpath(__file__))[0]+"/sqlitedata/"+self.__configt['db'],check_same_thread=False) + except Exception as e: + raise Exception(e) + self.__cursor[self.md5(self.__configt['db'])]=self.__conn[self.md5(self.__configt['db'])].cursor() + def __execute(self,typess='DQL'): + self.__setconn() + # print(self.__sql) + try: + res=self.__cursor[self.md5(self.__configt['db'])].execute(self.__sql) + except Exception as e: + + raise Exception(e) + else: + return res + def connect(self,config): + if isinstance(config,str): + self.__configt['db']=config + elif isinstance(config,dict): + if 'db' in config: + self.__configt['db']=config['db'] + return self + __table="" + def table(self,table): + """设置表名 + + 参数 table:str 表名 + """ + self.__table=table + return self + def query(self,sql): + self.__sql=sql + self.__execute(sql,'DQL') + # self.close() + def execute(self,sql): + self.__sql=sql + res=self.__execute('DML') + rowcount=res.rowcount + # self.close() + return rowcount + # def create_table(self): + # self.__sql=("CREATE TABLE "+self.__table+ + # "(ID INT PRIMARY KEY NOT NULL,"+ + # "NAME TEXT NOT NULL,"+ + # "AGE INT NOT NULL,"+ + # "ADDRESS CHAR(50),"+ + # "SALARY REAL);") + # # print(self.__sql) + # # exit() + # self.execute(self.__sql) + def select(self,id=None): + """select查询 + + 返回 list(列表) + """ + if id : + self.__where="id=%d" % id + self.__setsql() + if self.__buildSql: + self.__sqls="("+self.__sql+")" + self.__None() + return self.__sqls + self.__execute() + description=self.__cursor[self.md5(self.__configt['db'])].description #获取字段 + result = self.__cursor[self.md5(self.__configt['db'])].fetchall() #获取查询结果 + # self.close() + lists=[] + data_dict=[] + for field in description:#获取字段 + data_dict.append(field[0]) + for k in result: + i=0 + dicts={} + for j in k: + dicts[data_dict[i]]=j + i=i+1 + lists.append(dicts) + self.__None(table=False) + return lists + def find(self,id=None): + """查询一条记录 + + 返回 字典 + """ + if id : + self.__where="id=%s" % id + self.limit(1) + self.__setsql() + if self.__buildSql: + self.__sqls="("+self.__sql+")" + self.__None() + return self.__sqls + + self.__execute() + description=self.__cursor[self.md5(self.__configt['db'])].description #获取字段 + result = self.__cursor[self.md5(self.__configt['db'])].fetchall() #获取查询结果 + # self.close() + data_dict=[] + for field in description:#获取字段 + data_dict.append(field[0]) + dicts={} + for k in result: + i=0 + for j in k: + dicts[data_dict[i]]=j + i=i+1 + self.__None(table=False) + return dicts + def count(self,field="*"): + """查询数量 + + 返回 int 数字 + """ + self.__field=field + self.__setsql('count') + if self.__buildSql: + self.__sqls="("+self.__sql+")" + return self.__sql + self.__execute() + result = self.__cursor[self.md5(self.__configt['db'])].fetchall() #获取查询结果 + # self.close() + if self.__group: + cou=len(result) + else: + try: + cou=int(result[0][0]) + except IndexError: + cou=0 + self.__None(table=False) + return cou + def max(self,field): + """查询某字段的最大值 + + 返回 int 数字 + """ + self.__field=field + self.__setsql('max') + if self.__buildSql: + self.__sqls="("+self.__sql+")" + return self.__sql + self.__execute() + result = self.__cursor[self.md5(self.__configt['db'])].fetchall() #获取查询结果 + # self.close() + cou=int(result[0][0]) + self.__None(table=False) + return cou + def min(self,field): + """查询某字段的最小值 + + 返回 int 数字 + """ + self.__field=field + self.__setsql('min') + if self.__buildSql: + self.__sqls="("+self.__sql+")" + return self.__sql + self.__execute() + result = self.__cursor[self.md5(self.__configt['db'])].fetchall() #获取查询结果 + # self.close() + cou=int(result[0][0]) + self.__None(table=False) + return cou + def avg(self,field): + """查询某字段的平均值 + + 返回 int 数字 + """ + self.__field=field + self.__setsql('avg') + if self.__buildSql: + self.__sqls="("+self.__sql+")" + return self.__sql + self.__execute() + result = self.__cursor[self.md5(self.__configt['db'])].fetchall() #获取查询结果 + # self.close() + cou=int(result[0][0]) + self.__None(table=False) + return cou + def sum(self,field): + """查询某字段之和 + + 返回 int 数字 + """ + self.__field=field + self.__setsql('sum') + if self.__buildSql: + self.__sqls="("+self.__sql+")" + return self.__sql + self.__execute() + result = self.__cursor[self.md5(self.__configt['db'])].fetchall() #获取查询结果 + # self.close() + cou=int(result[0][0]) + self.__None(table=False) + return cou + def update(self,data,affair=False): + """数据表更新 + + 参数 data 要更新的内容 格式:{"name":"测试","age":20} + + 参数 affair 是否开启事务 True表示手动提交事务 False表示自动提交事务 + """ + self.__setsql('update',data) + res=self.__execute('DML') + if affair==False and self.__startTrans==False: + self.commit() + rowcount=res.rowcount + # self.close() + self.__None(table=False) + return rowcount + def delete(self,affair=False): + """数据表删除 + + 参数 affair 是否开启事务 True表示手动提交事务 False表示自动提交事务 + """ + self.__setsql('delete') + if self.__where: + res=self.__execute('DML') + else: + return 0 + if affair==False and self.__startTrans==False: + self.commit() + rowcount=res.rowcount + # self.close() + self.__None(table=False) + return rowcount + def insert(self,dicts,affair=False): + """插入数据库 单条插入或多条插入 + + 参数 dicts 要插入的内容 单条格式:{"name":"测试","age":20} 。 多条格式:[{"name":"测试","age":20},{"name":"测试","age":20}] + + 参数 affair 是否开启事务 True表示手动提交事务 False表示自动提交事务 + + 返回插入的数量 + """ + self.__setsql('insert',dicts) + res=self.__execute('DML') + if affair==False and self.__startTrans==False: + self.commit() + rowcount=res.rowcount + # self.close() + self.__None(table=False) + return rowcount + __startTrans=False + def startTrans(self): + "开启事务,仅对 update方法、delete方法、install方法有效" + self.__startTrans=True + def commit(self): + """事务提交 + + 增删改后的任务进行提交 + """ + self.__conn[self.md5(self.__configt['db'])].commit() + def rollback(self): + """事务回滚 + + 增删改后的任务进行撤销 + """ + self.__conn[self.md5(self.__configt['db'])].rollback() + def getsql(self): + """得到生成的sql语句""" + return self.__sql + __buildSql=None + def buildSql(self): + """构造子查询""" + self.__buildSql=True + return self + def __None(self,table=True): + "清除所有赋值条件" + self.__lock=None + self.__distinct=None + self.__join=None + self.__joinstr='' + self.__alias=None + self.__having=None + self.__group=None + self.__group1=None + self.__order=None + self.__order1=None + self.__limit=None + self.__field="*" + self.__where=None + self.__wheres=() + self.__buildSql=None + if table: + self.__table=None + __where=None + __wheres=() + def where(self,where = None,*wheres): + """设置过滤条件 + + 传入方式: + "id",2 表示id='2' + + "id","in",2,3,4,5,6,...表示 id in (2,3,4,5,6,...) + + "id","in",[2,3,4,5,6,...]表示 id in (2,3,4,5,6,...) + + [("id","gt",6000),"and",("name","like","%超")] 表示 ( id > "6000" and name LIKE "%超" ) + + "id","eq",1 表示 id = '1' + + eq 等于 + neq 不等于 + gt 大于 + egt 大于等于 + lt 小于 + elt 小于等于 + like LIKE + """ + self.__where=where + self.__wheres=wheres + # print(len(self.__wheres)) + return self + __field='*' + def field(self,field = "*"): + """设置过滤显示条件 + + 参数 field:str 字符串 + """ + self.__field=field + return self + __limit=[] + def limit(self,offset, length = None): + """设置查询数量 + + 参数 offset:int 起始位置 + + 参数 length:int 查询数量 + """ + self.__limit=[offset,length] + return self + def page(self,pagenow=1, length = 20): + """设置分页查询 + + 参数 pagenow:int 页码 + + 参数 length:int 查询数量 + """ + offset=(pagenow-1)*length + self.__limit=[offset,length] + return self + __order=None + __order1=None + def order(self,strs=None,*strs1): + """设置排序查询 + + 传入方式: + + "id desc" + + "id",'name','appkey','asc' + + "id",'name','appkey' 不包含asc或desc的情况下 默认是desc + + ['id','taskid',{"task_id":"desc"}] + """ + self.__order=strs + self.__order1=strs1 + return self + __group=None + __group1=None + def group(self,strs=None,*strs1): + """设置分组查询 + + 传入方式: + + "id,name" + + "id","name" + """ + self.__group=strs + self.__group1=strs1 + return self + __having=None + def having(self,strs=None): + """用于配合group方法完成从分组的结果中筛选(通常是聚合条件)数据 + + 参数 strs:string 如:"count(time)>3" + """ + self.__having=strs + return self + + __alias=None + def alias(self,strs=None): + """用于设置当前数据表的别名,便于使用其他的连贯操作例如join方法等。 + + 参数 strs:string 默认当前表作为别名 + """ + if strs: + self.__alias=strs + else: + self.__alias=self.__table + return self + __join=None + __joinstr='' + def join(self,strs,on=None,types='INNER'): + """用于根据两个或多个表中的列之间的关系,从这些表中查询数据 + + 参数 strs string 如:"test t1" test表设置别名t1 + + 参数 on string 如:"t1.id=t2.pid" 设置连接条件 + + 参数 types 支持INNER、LEFT、RIGHT、FULL 默认INNER + + """ + joinstr='' + if strs and on: + joinstr=joinstr+types+" JOIN "+strs+" ON "+on+" " + if joinstr: + self.__joinstr=self.__joinstr+joinstr + return self + __distinct=None + def distinct(self,bools=None): + "用于返回唯一不同的值,配合field方法使用生效,消除所有重复的记录,并只获取唯一一次记录。" + self.__distinct=bools + return self + __lock=None + def lock(self,strs=None): + """用于数据库的锁机制,在查询或者执行操作的时候使用 (暂未实现) + + 排他锁 (Exclusive lock) + + 共享锁 (Shared lock) + + 参数 strs 如:True表示自动在生成的SQL语句最后加上FOR UPDATE, + + + """ + # self.__lock=strs + return self + def __setsql(self,types=None,data = {}): + """生成sql语句""" + if types==None: + self.__sql="SELECT" + if self.__distinct and self.__field: + self.__sql=self.__sql+" DISTINCT" + if self.__alias: + self.__sql=self.__sql+" %s FROM %s %s" % (self.__field,self.__table,self.__alias) + else: + self.__sql=self.__sql+" %s FROM %s" % (self.__field,self.__table) + elif types=='count': + self.__sql="SELECT COUNT(%s) FROM %s" % (self.__field,self.__table) + elif types=='max': + self.__sql="SELECT MAX(%s) FROM %s" % (self.__field,self.__table) + elif types=='min': + self.__sql="SELECT MIN(%s) FROM %s" % (self.__field,self.__table) + elif types=='avg': + self.__sql="SELECT AVG(%s) FROM %s" % (self.__field,self.__table) + elif types=='sum': + self.__sql="SELECT SUM(%s) FROM %s" % (self.__field,self.__table) + elif types=='update': + strs='' + for k in data: + if isinstance(data[k],str): + strs=strs+" %s = '%s' ," % (k,self.escape_string(data[k])) + else: + strs=strs+" %s = %s ," % (k,data[k]) + strs=strs[:-1] + self.__sql="UPDATE %s SET %s" % (self.__table,strs) + # print(self.__sql) + elif types=='delete': + self.__sql="DELETE FROM %s" % (self.__table) + elif types=='insert': + if isinstance(data,dict): + strs='' + val='' + for k in data: + strs=strs+"%s," % k + if isinstance(data[k],str): + val=val+"'%s'," % self.escape_string(data[k]) + else: + val=val+"%s," % data[k] + strs=strs[:-1] + val=val[:-1] + self.__sql="INSERT INTO "+str(self.__table)+" ("+strs+") VALUES ("+val+")" + # print(self.__sql) + elif isinstance(data,list): + strs='' + val='(' + for k in data[0]: + strs=strs+" , "+k + for k in data: + for j in k: + if isinstance(k[j],str): + val=val+"'"+str(k[j])+"'," + else: + val=val+str(k[j])+"," + val=val[:-1] + val=val+"),(" + val=val[:-2] + self.__sql="INSERT INTO "+str(self.__table)+" ("+strs[3:]+") VALUES "+val + + if self.__joinstr: + # print(self.__sql) + self.__sql=self.__sql+" "+self.__joinstr + if self.__where: + if isinstance(self.__where,str): + if self.__wheres: + if len(self.__wheres) == 2: + if isinstance(self.__wheres[1],list): + self.__sql=self.__sql + " WHERE %s %s (" % (self.__where,self.__operator(self.__wheres[0])) + for k in self.__wheres[1]: + self.__sql=self.__sql+str(k)+"," + self.__sql=self.__sql[:-1]+")" + else: + self.__sql=self.__sql + " WHERE %s %s '%s'" % (self.__where,self.__operator(self.__wheres[0]),self.__wheres[1]) + elif len(self.__wheres) > 2: + if self.__wheres[0]=='in': + strs=str(self.__wheres[1]) + i=0 + for k in self.__wheres: + if i > 1: + strs=strs+","+str(k) + i=i+1 + self.__sql=self.__sql + " WHERE %s in (%s)" % (self.__where,strs) + else: + self.__sql=self.__sql + " WHERE %s = '%s'" % (self.__where,self.__wheres[0]) + else: + self.__sql=self.__sql + " WHERE %s" % self.__where + elif isinstance(self.__where,list): + self.__sql=self.__sql + " WHERE %s" % self.__listTrans() + else: + print("参数where类型错误",type(self.__where),self.__where) + if self.__order: + s='' + if isinstance(self.__order,list): + for strs in self.__order: + if isinstance(strs,str): + s=s+strs+"," + else: + pass + for key in strs: + s=s+key+" "+strs[key] + s=s+"," + s=s[:-1] + if isinstance(self.__order,str): + if self.__order1: + if len(self.__order1) > 1: + if self.__order1[len(self.__order1)-1] == 'desc' or self.__order1[len(self.__order1)-1] == 'asc': + i=0 + while i