mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-17 21:25:47 +02:00
v6.8.12
1. Add disk IO information to the homepage 2. Add a clear list button in the upload window 3. Optimize the background task overhead of the panel 4. Optimize the disk information caching mechanism 5. Panel Pro edition is online 6. Optimize panel resource usage 7. Optimize SSL certificate renewal 8. Fix the problem of reporting an error when the security entrance is empty 9. Fix the problem of infinite recursion when copying directories in extreme cases
This commit is contained in:
@@ -2847,4 +2847,125 @@
|
||||
background: #20a53a;
|
||||
border-color: #38983b;
|
||||
color: #fff;
|
||||
}
|
||||
.bt-property-setting .tab-nav{
|
||||
font-size: 0px;
|
||||
}
|
||||
.bt-property-setting .tab-nav span{
|
||||
font-size: 12px;
|
||||
}
|
||||
.bt-property-setting .tab-con{
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
.bt-property-setting .property-box{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bt-property-setting .property-box.active{
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bt-property-setting .property-box .attr-box{
|
||||
margin: 5px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.bt-property-setting .property-box .attr-name{
|
||||
width: 90px;
|
||||
padding-left: 10px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.bt-property-setting .property-box .attr-content{
|
||||
margin-left: 80px;
|
||||
}
|
||||
.bt-property-setting .property-box .attr-content input{
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
border:1px solid#ccc;
|
||||
outline: none;
|
||||
padding-left: 5px;
|
||||
width: 350px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.bt-property-setting .property-box .attr-content input:focus{
|
||||
border-color: #20a53a;
|
||||
}
|
||||
|
||||
.bt-property-setting .property-box .file_icon{
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
left:-10px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.bt-property-setting .property-box .dividing{
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
margin: 10px 0;
|
||||
background-color: #ececec;
|
||||
}
|
||||
|
||||
.bt-property-setting .property-box .attr-box .attr-name,
|
||||
.bt-property-setting .property-box .attr-box .attr-content{
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
}
|
||||
.bt-property-setting .property-box .attr-box .attr-content span{
|
||||
width: 450px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
.details_box_view,.history_box_view{
|
||||
border:1px solid #ececec;
|
||||
}
|
||||
.details_box_view,
|
||||
.history_box_view,
|
||||
.property-box{
|
||||
height:388px !important;
|
||||
overflow:auto;
|
||||
}
|
||||
.details_box_view table,
|
||||
.history_box_view table{
|
||||
width: 100%;
|
||||
}
|
||||
/* .details_box_view table td,
|
||||
.history_box_view table th{
|
||||
|
||||
padding: 5 10px;
|
||||
} */
|
||||
.details_box_view thead tr,
|
||||
.history_box_view thead tr{
|
||||
background-color: #f6f6f6;
|
||||
color: #555;
|
||||
font-weight: 400;
|
||||
}
|
||||
.details_box_view tbody tr:hover,
|
||||
.history_box_view tbody tr:hover{
|
||||
background: #f0f9f7;
|
||||
cursor: pointer;
|
||||
}
|
||||
.details_box_view td div,
|
||||
.details_box_view th div,
|
||||
.history_box_view td div,
|
||||
.history_box_view th div{
|
||||
padding: 5px;
|
||||
height: 30px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.details_box_view thead,
|
||||
.history_box_view thead{
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
}
|
||||
.ellipsis{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -590,9 +590,9 @@ textarea:active,
|
||||
}
|
||||
|
||||
.list_scan {
|
||||
margin: 0 auto;
|
||||
margin-top: 15px;
|
||||
width: 150px
|
||||
margin: 0 auto;
|
||||
margin-top: 15px;
|
||||
width: 155px
|
||||
}
|
||||
|
||||
.list_scan>img {
|
||||
@@ -645,7 +645,7 @@ textarea:active,
|
||||
top: 10px;
|
||||
right: 65px;
|
||||
padding: 5px 10px;
|
||||
width: 115px;
|
||||
width: 200px;
|
||||
border-radius: 4px;
|
||||
background: #dff0d8;
|
||||
color: #20a53a;
|
||||
|
||||
+218
-56
@@ -980,11 +980,11 @@ html {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAKnAAACpwB9NLfEgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAF0SURBVDiNpdJNiM5RGAXw38ukkJVvMYqZRsqYZmyYDTZWbCxsKLG3pCSaWNmNJU2NmhU7pQjFRhYsJCTWykfJRz5eH8fmefn39lLy1FPn3nPv7Zzz3FYS/1Oz/sItwg3cwuo/HWp1KRjEQtzBTizAfHzCDMbwDk97PTCECXzBWyzGYXzDCXzGGjzHJB6DJJ3ekuRc4R1JNja4VUl2FZ5OsrXDNTO4jRcYx1W8wTEcx1xcwna0cbM7xGXYgxF8LakTuIbLZWVdWevHXixvWniY5ECSkVqfbGBJBpOcKjyc5FCSR90WXjXSnV1hdqqNVuH3eInvTQUDSfYnmUkylmRDkvNJ1icZSjJV+wNJriQ5WKr01avPqtfW3O/hNPaVmrO1N14qp35pa/jclORM4dHqDjevMdYLSTZ3uD6/q405mMYHjOJojewIluJHjfdj51L3Vx7GElzHbqzAXazERWzDazzoZaG7+5PcT/Kkwux5rlvBP9dPgIpDWf6ENxgAAAAASUVORK5CYII=")
|
||||
}
|
||||
.menu .menu_xterm {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAADaSURBVDiNrZO9FYJAEIQ/lAZICaEEDQ2xDrNNNaQEW3BSy9ASpAVKkBLO5EDQE/Fnknv7bmd29vY2cs4BICnjA5hZDRA555B0ARYj+Q2QPJy1mS3naZpmwH6EXAGlL7ABVsAO2FZVdYx7ifULgaRX4ODPrmDs7QCs277eQVICXAFmDxd7SWPtPGHmLXYaQDNBpOMMHPgWzhNFngW+QX8K7WcqgMTMSklFgNNwf/jBFAAMwMxKH59eCORBBz1iG0ch236MwJ/eoFXLJE3ldYs3dZlCqM0sj35d5xuDSFMDX6z07gAAAABJRU5ErkJggg==")
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAMBJREFUeNpiYKAQMM6cOVMASBuQozk9Pf0AC5AuAOJ6cgwAWt7IhMQvRKIfAPEEYgxhQWL3o9EFpBgwAeifQhKdD7YI5oWPUMEEmAQR4COyATBwAIgdgIacB2IFYkxhQouWB0BsCA3E86QGIsxvDSBXgGIDSxr5ALTgAk4XADWAQt4fiB2BChcAaQVoGoHheLwuAGqagBz/UNsciQ4DEgE/zAUfQM4DOt+eRANAYTMRZADIrxfIdMUFSnMzA0CAAQD0hjqnYxWD2gAAAABJRU5ErkJggg==")
|
||||
}
|
||||
.menu .current .menu_xterm,
|
||||
.menu .menu_xterm:hover{
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAACwSURBVDiNpZPRDYJADEAfhgVc4ViFFVzBGRjBGVxFR2AFHEFGeH5YkVwAj/iSpjR3fSmXtFIJEvt4AKCi9m7zXMi9Cmr60dyrJ3VQ28inOEuVmoBhGqmcBDSox48tfqckpp5DZr1EFHMAjrP6CowFkqknn+AB3Asli4Ld1FmdgJb3iF1854wRk2CcHZ4jd5FvK4JmbYIuq6sFAWw84m7qmW3PMn3vFi7TEoNK5Z/r/AIpZQNuvOKqnwAAAABJRU5ErkJggg==")
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALhJREFUeNpiYKAQMH78+FEASBuQo5mfn/8AC5AuAOJ6cgwAWt7IhMQvRKIfAPEEYgxhQWL3o9EFpBgwAeifQhKdD7YI5oWPUMEEmAQxZiAbAAMHgNgBaMh5IFYgxhQmtGh5AMSG0EA8T2ogwvzWAHIFKDawpJEPQAsu4DQAqAEU8v5A7AhSCOQboKWRC1CM3QCgpgnI8Q+1zZHoMCA1JcNc8AHkTKBz7Uk0AOS9iRRlJvTwIAsABBgAqiNCt+zqQrsAAAAASUVORK5CYII=")
|
||||
}
|
||||
.menu .menu_folder {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAE3SURBVDiNpZO9SgNBFIW/OySiaBCtbCwE8ReUgGDpE9gExNJmd6O+hM8gmGJn3yKxt7WyEARBUUSbIPhTGFAwxyarSwoZ2AO3mjkf98y9Y5IoI1fKDVQA0jRtOOd2B8BRST5Jkk4IwCSRZVkbOAYeACdpD3iX9DrUpQO+gHaz2XwuRnCSLuM4vpU0AnSAvplNmdlkocbNbN3MTrz3de/9WKVA/07TdN85twbcA5/A8AsLuAO6wI6k2UrhoGZmy3EcH4Zk995vAAd5hA9gBXgJMQ+0ZWanOaAH1IGrEGer1TJgxszOckAFWATOQwDVanUO6EVR9JYD5oGJJEmeAtvfBG7gb4xLwEWgGWA1v59PoQs8Zlm2ANg/RgETwLRz7voXIOnIzBrAdgCgBvgoivowWOUyKv0bfwCvBmEVd9ynHgAAAABJRU5ErkJggg==")
|
||||
@@ -1063,6 +1063,9 @@ html .menu .menu_control:hover {
|
||||
html .menu .menu_firewall:hover {
|
||||
background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP////39/fv7+/f39+3t7evr6+np6efn5+Xl5ePj4+Hh4d/f393d3dnZ2dfX19XV1dHR0cvLy8nJycfHx8PDw8HBwb+/v729vbu7u7m5ube3t7W1tbOzs7Gxsa+vr6enp6WlpaOjo5+fnwDZNpeXl42NjYuLi4mJiSitSCqpSiypSoeHhyirSC6lTIWFhTKhTjiZUDyXUnx8fECRVEKPVHp6enh4eEqHWEiHWHR0dFB+XHBwcFpyYGZmZgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFAwA9ACwAAAAADwAQAAAGdMCesEeiHAACR2c17J0oiUXEE/pgHAsFptYjQFzN4c6UmPQKoXAYIzl/1M1M5AyCDzdzwtveu8wRdXwXbQ8afD0SGD0dEIcNIj01CDl2NQeUPRZzcA8WTQWKYRUGYTkJDlw9MgwLO3AaBh0bBhyHJQEDYE1BACH5BAUEAD0ALAMABgACAAMAAAYHwB6PN+qlggAh+QQFBAA9ACwFAAcAAQADAAAGBUDaCBUEACH5BAUIAD0ALAYACAACAAMAAAYHwBtuNGKpggAh+QQFCAA9ACwIAAcAAQADAAAGBcDZSBUEACH5BAUIAD0ALAkABgABAAMAAAYFwNioFQQAIfkEBQgAPQAsCgAFAAEAAwAABgVA2OgVBAAh+QQFBgA9ACwLAAQAAgADAAAGB0Aab6SD9YIAIfkECTIAPQAsAAAAAA8AEAAABhXAnnBILBqPyKRyyWw6n9CodEqtJoMAOw==")
|
||||
}
|
||||
html .menu .menu_xterm:hover {
|
||||
background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQXAJ6ipUFITySRPIiMkDFRQuXm5jJKQy1kQCGeOzBXQSl3PiWLPVhfZSxrQCpxP9na2yeEPTREQ8LExmRqb5OXm/Hx8TU9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjMyQjYwMTU3OTA2QTExRUJCN0NFQUUwQjRDMzM4RDJDIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjMyQjYwMTU4OTA2QTExRUJCN0NFQUUwQjRDMzM4RDJDIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MzJCNjAxNTU5MDZBMTFFQkI3Q0VBRTBCNEMzMzhEMkMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzJCNjAxNTY5MDZBMTFFQkI3Q0VBRTBCNEMzMzhEMkMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4B//79/Pv6+fj39vX08/Lx8O/u7ezr6uno5+bl5OPi4eDf3t3c29rZ2NfW1dTT0tHQz87NzMvKycjHxsXEw8LBwL++vby7urm4t7a1tLOysbCvrq2sq6qpqKempaSjoqGgn56dnJuamZiXlpWUk5KRkI+OjYyLiomIh4aFhIOCgYB/fn18e3p5eHd2dXRzcnFwb25tbGtqaWhnZmVkY2JhYF9eXVxbWllYV1ZVVFNSUVBPTk1MS0pJSEdGRURDQkFAPz49PDs6OTg3NjU0MzIxMC8uLSwrKikoJyYlJCMiISAfHh0cGxoZGBcWFRQTEhEQDw4NDAsKCQgHBgUEAwIBAAAh+QQFMgAXACwAAAAAEAAQAAAFU6AljmRpBVOqrqtFVXAsy9Q7VMMDzHHN/5UawGQC1CiWg4IoOiINAoGB6BxBENSjyIE4oFKMprYhIFgYkvTQpWWOqm6RcVBI2+/2AuXL6k8CcSYhACH5BAUyABcALAcACQAFAAIAAAUIYJSMBLGcSggAIfkEBTIAFwAsBwAJAAUAAgAABQhgMI0MI51ACAAh+QQFMgAXACwHAAkABQACAAAFCGCUjASxnEoIADs=")
|
||||
}
|
||||
|
||||
html .menu .menu_day:hover {
|
||||
background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAANPT09HR0c3NzcvLy8nJycfHx8XFxcPDw8HBwb+/v729vbu7u7m5ubW1tbOzs7Gxsa2trampqaenp6WlpaOjo6GhoQDZNpubm5WVlY+Pj42NjYuLi4mJiYeHh4WFhYODg35+fnZ2dnR0dHJycnBwcGZmZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgAlACwAAAEADwAOAAAGesCSUKQRGkua0RGjAFQm0EkFoMAIFY9HAHPpXjABiINREohKoaMwHSKUBgvKJEKvTygLw1vCyWj+gBkcEnoGHCUWFmpCHAglBYeLRhsHjxuSRhqOBJeYSI4FnZgeegMdniUgBSULER8dHrCxG7QRDUIPCQq7vLsJDyVBACH5BAUKACUALAcABwACAAEAAAYEQIslCAAh+QQFCgAlACwKAAcAAgABAAAGBECLJQgAIfkEBQoAJQAsBAAJAAIAAQAABgRAiyUIACH5BAUKACUALAcACQACAAEAAAYEQIslCAAh+QQFCgAlACwKAAkAAgABAAAGBECLJQgAIfkEBQoAJQAsBAALAAIAAQAABgRAiyUIACH5BAUKACUALAcACwACAAEAAAYEQIslCAAh+QQFCgAlACwKAAsAAgABAAAGBECLJQgAIfkECTIAJQAsAAABAA8ADgAABhTAknBILBqPyKRyyWw6n9CodEoNAgA7")
|
||||
@@ -1130,7 +1133,46 @@ html .menu .menu_exit:hover {
|
||||
line-height: 50px;
|
||||
border-bottom: 1px solid #eee
|
||||
}
|
||||
.title {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
border-bottom: 1px solid #eee
|
||||
}
|
||||
.title.tabs-nav{
|
||||
padding:0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.title.tabs-nav select{
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 50%;
|
||||
margin-top: -12px;
|
||||
}
|
||||
.tabs-content{
|
||||
height: 442px;
|
||||
}
|
||||
.tabs-content .tabs-item{
|
||||
display: none;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
.tabs-content .tabs-active.tabs-item{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
.title.tabs-nav span{
|
||||
padding: 0 25px;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
.title.tabs-nav span.active{
|
||||
border-bottom: 2px solid #20a53a;
|
||||
|
||||
}
|
||||
.title h3 {
|
||||
display: inline-block;
|
||||
line-height: 50px;
|
||||
@@ -1618,10 +1660,13 @@ html .menu .menu_exit:hover {
|
||||
height:80px;
|
||||
}
|
||||
.bw-info > div{
|
||||
float:left;
|
||||
padding-top:25px;
|
||||
text-align:center;
|
||||
float: left;
|
||||
padding-top: 35px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.bw-info > div p{
|
||||
margin-bottom:7px;
|
||||
}
|
||||
@@ -1629,19 +1674,27 @@ html .menu .menu_exit:hover {
|
||||
font-size:14px;
|
||||
color: #666;
|
||||
}
|
||||
.bw-info .ico-up{
|
||||
width:14px;
|
||||
height:8px;
|
||||
background-color:#f7b851;
|
||||
.bw-info .ico-down,
|
||||
.bw-info .ico-up,
|
||||
.bw-info .ico-write,
|
||||
.bw-info .ico-read{
|
||||
width:10px;
|
||||
height:10px;
|
||||
display:inline-block;
|
||||
margin-right:3px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.bw-info .ico-down{
|
||||
width:14px;
|
||||
height:8px;
|
||||
background-color:#52a9ff;
|
||||
display:inline-block;
|
||||
margin-right:3px;
|
||||
background-color:#52a9ff;
|
||||
}
|
||||
.bw-info .ico-up{
|
||||
background-color:#f7b851;
|
||||
}
|
||||
.bw-info .ico-write{
|
||||
background-color:#6CC0CF;
|
||||
}
|
||||
.bw-info .ico-read{
|
||||
background-color:#FF4683;
|
||||
}
|
||||
.bw-info ul li {
|
||||
height: 56px;
|
||||
@@ -2511,6 +2564,12 @@ html .menu .menu_exit:hover {
|
||||
color: #444;
|
||||
font-size: 12px;
|
||||
font-weight: bold
|
||||
display: inline-block;
|
||||
width: 450px;
|
||||
white-space: pre;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.changepath .path-con-left {
|
||||
@@ -2541,11 +2600,11 @@ html .menu .menu_exit:hover {
|
||||
color: #666
|
||||
}
|
||||
|
||||
.changepath .path-con-right {
|
||||
.changepath .path-con-right{
|
||||
float: left;
|
||||
height: 450px;
|
||||
overflow: auto;
|
||||
width: 520px
|
||||
width: 550px
|
||||
}
|
||||
|
||||
.changepath .path-con-right .default li {
|
||||
@@ -2562,18 +2621,45 @@ html .menu .menu_exit:hover {
|
||||
}
|
||||
|
||||
.path-con-right .file-list {
|
||||
display: none
|
||||
display: none;
|
||||
height:450px;
|
||||
}
|
||||
|
||||
.list-list tr:last-child{
|
||||
border-bottom: 1px solid #ececec
|
||||
}
|
||||
.list-list tr input{
|
||||
border-color: #ddd;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.list-list .bt_open_dir span:nth-child(2){
|
||||
width: 155px;
|
||||
display: inline-block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.path-con-right .list-list td {
|
||||
padding-left: 10px;
|
||||
cursor: pointer
|
||||
line-height: 22px;
|
||||
cursor: pointer;
|
||||
border-top: 1px solid #ececec;
|
||||
white-space: pre;
|
||||
}
|
||||
.path-con-right .list-list tr{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.list-list span.glyphicon {
|
||||
color: #666;
|
||||
margin-right: 10px;
|
||||
font-size: 18px
|
||||
font-size: 16px;
|
||||
vertical-align: middle;
|
||||
top: 1px;
|
||||
}
|
||||
.list-list span.glyphicon-file{
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.list-list span.glyphicon-folder-open {
|
||||
@@ -2583,11 +2669,6 @@ html .menu .menu_exit:hover {
|
||||
.list-list span.glyphicon-cloud-download {
|
||||
font-size: 12px
|
||||
}
|
||||
.list-list tr>td{
|
||||
padding: 5px 10px !important;
|
||||
line-height: 1.42857143;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.newFolderName {
|
||||
border: #ccc 1px solid;
|
||||
@@ -4067,7 +4148,7 @@ html .menu .menu_exit:hover {
|
||||
|
||||
.re-con {
|
||||
float: left;
|
||||
height: 500px;
|
||||
height: 567px;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
@@ -4090,9 +4171,8 @@ html .menu .menu_exit:hover {
|
||||
}
|
||||
|
||||
.re-con-con {
|
||||
height: 500px;
|
||||
height: 567px;
|
||||
margin-left: 120px;
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
@media only screen and (max-width:768px) {
|
||||
@@ -4346,20 +4426,19 @@ html .menu .menu_exit:hover {
|
||||
.color-green{
|
||||
color:green;
|
||||
}
|
||||
.btpro{
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAAAUCAMAAAAEAbViAAAAA3NCSVQICAjb4U/gAAABXFBMVEX///+7jAC7jAC7jAC7jAC7jAC7jAC7jAC7jAC7jAC7jAC7jAC7jAC7jAC7jAD////+/fv+/fr8+vX8+vP69uv38eD28N3179v07NXz69Lz6tHz6c/x6Mzv48Pu48Hr3rX74jnq27D54Djp2av43zfo16fo2Kj33TX33Tbm1aLl1Z/12Tbl057z1zLk0Znj0Jfx1DDizpPu0DPv0S7fyIbqzCroyC/cxH3oySjawXXZv3DkwyTYvWzivyzXu2jWumXevCDUtVzctinathzSslXSs1bRsVHRsVLWsBjVrSbNqkPTrBXLqD3PpCLJozTOphHIozLIojDIoS/HoCzKoQ7GninGnyrFnifJnB/FnCTFnSbEmiDEmyLFmQnCmBvBlxjBlhbBlRXAlRPCkhy/kxDAkwW+kQq9kAi9jwa9jwK9jQC8jgS8jQO8ihm7jAC2gRWweBKpbw+jZgydXgnhk9RtAAAAdHRSTlMAESIzRFVmd4iZqrvM3e7//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wol0KMAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAWdEVYdENyZWF0aW9uIFRpbWUAMDUvMzEvMTikOWwBAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAAg5JREFUOI2dlGlz0zAQhhUHJ45jST2gXKUVR4BijmKKCwX1CKcKLoVQcCmFYgcSjqiy8/9nWCtOJvlEwusZe3Q80rurlRFCyLDsSi7bMtAkKlSlU602W61o+3VDvrnOxlTGliUxkdFcfRjN0aWm3ByXBdgglaqN7N2pmb2t6edba0e3xmctBxWxjecoPfPh2afTtPGkN+J6/2SLxC6ajrQvLC4uPJXvLs6/aC7rkZD35/Awb8RMMc5FGAc9FktMiJS42W5HX+SP6Nv+n13GlFJdlWmEVfCkYcD9fF9MTNO0iHX15o3aRnTncq0W7WcDQvQmeEHO1rlm1ZBnw6lAvrBJQY+3s9fOPSbCMA21BEvdHnvssa7qCm3Hz3N1gpQRsu1ZSk8drFC60nrAmM/DmGv5LAg06yVM75mF0fFyFpWkiUrEoHTx6wKt/d7U/R2hUZjkppoFBxCrYCrkfd9ZcVSkUcAlOrW+Q8+3X13S/SIzHHeFXiZjlctYwiFevwNrDdgCdsD09OzbtZmPh9d6/QFQbiJGzsgFksM5Zcv0WVSUlumcPHdwdv3Xcp5DF5KVowMWvioW7nHKh1gIuYznlxq35aOhshFJCBvEaqC4ztKkntQ9FQ+xEDK5u3r08+Vo0dVHm3Ayvu9nhr1htuDIvc/y/RU2ifqX2MBSHo59g0ZZZJLv9/8ThXyZE/1tQH8B/ly2lqVFKXEAAAAASUVORK5CYII=");
|
||||
background-size: 50px;
|
||||
.btpro,.btpro-gray{
|
||||
background-position: 10px center;
|
||||
background-repeat:no-repeat;
|
||||
padding:2px 0 2px 64px;
|
||||
margin-right:5px;
|
||||
cursor:pointer;
|
||||
background-size: 48px;
|
||||
}
|
||||
.btpro{
|
||||
background-image: url('../img/pro.svg');
|
||||
}
|
||||
.btpro-gray{
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAAAUCAMAAAAEAbViAAAAA3NCSVQICAjb4U/gAAAA51BMVEX////6+vr4+Pj29vbx8fHu7u7r6+vp6eno6Ojl5eXk5OTj4+Pi4uLf39/e3t7d3d3b29vU1NTT09PNzc3Ly8vIyMjFxcXDw8PAwMC+vr67u7u6urq5ubm4uLi3t7e2tra0tLSzs7OysrKxsbGvr6+srKyrq6upqamoqKikpKSjo6OgoKCfn5+enp6dnZ2cnJybm5uampqZmZmYmJiXl5eWlpaVlZWTk5OSkpKQkJCPj4+NjY2MjIyLi4uKioqIiIiHh4eGhoaFhYWDg4OCgoKBgYGAgIB/f39+fn59fX14eHh0dHT///9HdDDXAAAATXRSTlP/////////////////////////////////////////////////////////////////////////////////////////////////////ANNqEYAAAAAJcEhZcwAADpwAAA6cAQeUU90AAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAFnRFWHRDcmVhdGlvbiBUaW1lADA1LzMxLzE4pDlsAQAAAeZJREFUOI2VlH1XmzAUxjNbZutxL2hnXeiGA1kiNdspbJlEC9FmLtD7/T/PkkC78tfw4Rw4IfeXPDf3AgIALyBRJxJ4MFgIYLTU+XJZbTYluVnp4jMeKMvOtfTBq84/lAAnlV4OZTECT0ZLAoQB5AuIFhcPX4azQQ5TQYQxgLKrnwhWq3YmjP/LTiWZ+rkmr8bjoyv93UNR1UKc7mIo7wYFVphSxousZYUWUmotKqVKoZ/Kkj8zjJVSW2XVY5W5Gp7RpNtXSN/3Axkcn55OPpZvX08mJbcTjLUBcdaxKXWsOvDs5ZGpsPBtwebE3m6vMeO84U4MN2HLPsZ4q7bM2Um6s3on5wDEUnB3BnC2IRgnlBfUKcFZ5ti4xm5Pm8Y67liYaR9m0vTT+P4IJr/b+q6ZQ01Q2DjWODC5Mqw43fk2LETaG4kZwOUtQoov3HtmDRdb5paxrAoxrqnJN1lT/o8didyZ/naBflRdS2aGCmvWq1FoSGrqZJfZsTDVgZ8DukOXf3YNEZrD6tA9a56qYOFjQw9Yk/JcoJPVG31z0Das5maDQu1VpLip0zqNVXHAmpTl+/OH57zfdGl/aCqTJIk1HB+yo1znv/T9J/wSdazpDq2rwV9QnwVfbr6+DIU9CzN/+N+m1V+TNr+ixpmAWwAAAABJRU5ErkJggg==");
|
||||
background-repeat:no-repeat;
|
||||
padding:2px 0 2px 64px;
|
||||
margin-right:5px;
|
||||
cursor:pointer;
|
||||
background-image: url('../img/pro-default.svg');
|
||||
}
|
||||
|
||||
/*插件付费*/
|
||||
@@ -4535,7 +4614,7 @@ html .menu .menu_exit:hover {
|
||||
}
|
||||
.bt-radio:checked + .bt-radioinput:after{
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAKBAMAAAB293L0AAAAA3NCSVQICAjb4U/gAAAAKlBMVEX///////////////////////////////////////////////////////9q+00tAAAADnRSTlMAETNEVWZ3iJmqu93u/wlUiAQAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAWdEVYdENyZWF0aW9uIFRpbWUAMDYvMDIvMTjAxKOiAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAADpJREFUCJljYACDTAjFcgRC+xpAuFcYGCqAtK0DA4P2BAbmq0A2404G3QSQpPTi62BFjGsTIJpEQQQATscJDpRQCfQAAAAASUVORK5CYII=");
|
||||
background-repeat: no-repeat;
|
||||
background-repeat: no-repeat;
|
||||
border-radius:100%;
|
||||
content:"";
|
||||
display:inline-block;
|
||||
@@ -4961,7 +5040,7 @@ select[disabled]{
|
||||
line-height:26px;
|
||||
}
|
||||
.domain-ul-list li .checkbox-text{
|
||||
margin-right:5px;
|
||||
margin-right:5px;
|
||||
vertical-align:-2px
|
||||
}
|
||||
.btswitch-btn.bt-waf-firewall{
|
||||
@@ -5010,7 +5089,7 @@ select[disabled]{
|
||||
|
||||
.tab-db-status .tname{
|
||||
width: 155px;
|
||||
padding-right:10px;
|
||||
padding-right:10px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
@@ -5115,7 +5194,7 @@ select[disabled]{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
|
||||
}
|
||||
.bootstrap-select .dropdown-toggle{
|
||||
height: 30px;
|
||||
@@ -7095,7 +7174,7 @@ select[disabled]{
|
||||
height: 5px;
|
||||
}
|
||||
.upload_btn_groud{
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: 5px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
@@ -7268,7 +7347,7 @@ select[disabled]{
|
||||
background: #effffa;
|
||||
}
|
||||
.module_details_item:hover .module_details_body{
|
||||
background: #f8fffd;
|
||||
background: #f8fffd;
|
||||
}
|
||||
.module_details_item:before{
|
||||
/*content:'';*/
|
||||
@@ -7341,7 +7420,7 @@ select[disabled]{
|
||||
color: #20a53a;
|
||||
}
|
||||
.module_details_item{
|
||||
|
||||
|
||||
}
|
||||
.module_details_head{
|
||||
height: 40px;
|
||||
@@ -7418,7 +7497,7 @@ select[disabled]{
|
||||
}
|
||||
.module_details_block .line_content{
|
||||
width:250px;
|
||||
|
||||
|
||||
}
|
||||
/*END*/
|
||||
|
||||
@@ -7731,7 +7810,7 @@ select[disabled]{
|
||||
}
|
||||
.xterm .xterm-viewport:hover::-webkit-scrollbar-thumb{
|
||||
background:#aaa;
|
||||
|
||||
|
||||
}
|
||||
.xterm .xterm-viewport::-webkit-scrollbar-track{
|
||||
box-shadow:inset 0 0 5px rgba(0, 0, 0, 0.2);
|
||||
@@ -7963,6 +8042,40 @@ select[disabled]{
|
||||
margin-right: 4px;
|
||||
color: #ffa515;
|
||||
}
|
||||
.term-move-border{
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
cursor: n-resize;
|
||||
margin-top: -5px;
|
||||
opacity: 0;
|
||||
}
|
||||
.term-tool-button{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 50%;
|
||||
width: 28px;
|
||||
height: 60px;
|
||||
background-color: #565656;
|
||||
border-top-left-radius: 30px;
|
||||
border-bottom-left-radius: 30px;
|
||||
cursor: pointer;
|
||||
z-index: 999;
|
||||
margin-top: -30px;
|
||||
}
|
||||
.term-tool-button span{
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
left: 15%;
|
||||
top: 35%;
|
||||
font-size: 18px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
.term-tool-button:hover{
|
||||
background-color: #D8D8D8;
|
||||
}
|
||||
|
||||
|
||||
.term_item_tab{
|
||||
background: #f1f1f1;
|
||||
font-size: 0;
|
||||
@@ -8137,7 +8250,7 @@ select[disabled]{
|
||||
display: block;
|
||||
height: 19px;
|
||||
color: #bbb;
|
||||
/* vertical-align: bottom;
|
||||
/* vertical-align: bottom;
|
||||
} */
|
||||
.term_item_tab .tab_tootls .glyphicon-resize-full,
|
||||
.term_item_tab .tab_tootls .glyphicon-resize-small{
|
||||
@@ -8262,7 +8375,7 @@ select[disabled]{
|
||||
}
|
||||
.xterm .xterm-viewport:hover::-webkit-scrollbar-thumb{
|
||||
background:#aaa;
|
||||
|
||||
|
||||
}
|
||||
.xterm .xterm-viewport::-webkit-scrollbar-track{
|
||||
box-shadow:inset 0 0 5px rgba(0, 0, 0, 0.2);
|
||||
@@ -8478,7 +8591,7 @@ select[disabled]{
|
||||
margin-top: -200px;
|
||||
border-radius: 2px;
|
||||
padding-bottom: 45px;
|
||||
|
||||
|
||||
}
|
||||
.localhost-form-view>button{
|
||||
margin-left: 100px;
|
||||
@@ -9282,9 +9395,9 @@ select[name="network-io"]{
|
||||
|
||||
/*批量操作*/
|
||||
.batch_title{
|
||||
height: 30px;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin-top: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -9311,7 +9424,55 @@ select[name="network-io"]{
|
||||
.bt_table .divtable{
|
||||
overflow: auto;
|
||||
}
|
||||
.bt_table .text-overflow{
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
word-wrap:break-word;
|
||||
}
|
||||
#recycle_table .divtable{
|
||||
max-height: 480px;
|
||||
}
|
||||
.re-con-con .text-overflow span{
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
display: inline-block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
}
|
||||
.recycle_view .layui-layer-content{
|
||||
overflow: initial !important;
|
||||
}
|
||||
.re-con-con .table thead{
|
||||
position: relative;
|
||||
z-index: 99;
|
||||
}
|
||||
.re-con-con .divtable .table{
|
||||
border: none
|
||||
}
|
||||
.re-con-con .divtable{
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.bt_table .file_icon{
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
background-image: url(../img/file_icon/file.png);
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
margin-left: -5px;
|
||||
}
|
||||
.bt_table .file_folder{
|
||||
background-image: url(../img/file_icon/folder.png);
|
||||
}
|
||||
.bt_table .file_images{
|
||||
background-image: url(../img/file_icon/png.png);
|
||||
}
|
||||
.bt_table .table-mask{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -9657,7 +9818,7 @@ select[name="network-io"]{
|
||||
opacity: .65;
|
||||
cursor: no-drop;
|
||||
box-shadow: none;
|
||||
|
||||
|
||||
}
|
||||
.bt_table_select_group .bt_selects{
|
||||
display: none;
|
||||
@@ -9677,7 +9838,7 @@ select[name="network-io"]{
|
||||
}
|
||||
.bt_table_select_group.active .bt_selects{
|
||||
display: inline-block;
|
||||
|
||||
|
||||
}
|
||||
.bt_table_select_group .bt_selects .item{
|
||||
width: 100%;
|
||||
@@ -9725,7 +9886,7 @@ select[name="network-io"]{
|
||||
}
|
||||
|
||||
.inlineBlock{
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
}
|
||||
/*批量操作end*/
|
||||
|
||||
@@ -9875,9 +10036,10 @@ background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODIiIGhlaWdodD0iODIiIHh
|
||||
width: 70px;
|
||||
}
|
||||
.pro-font-icon{
|
||||
background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAAATCAYAAAFTgessAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAQqADAAQAAAABAAAAEwAAAADt3mdsAAAHFElEQVRYCe2YfZCOVRTAz3137WJZMq2vqDETrZIaIYoMIwy2aX0sWuQPYyIZkxmU8VU0NFOaigzThEnaXR+7CaORr5QZKmLKKiVFLSYlSct6n37nPO/z7Pu+bHZq/FPdnfvcc88599xzzz3n3POuSDWa84pksESl0HhryO1SwdyTpyRPMmStNJLLstFoMPYKBHqFkhbCRZLvrZW7gnmVo/MKEExzQ8Qh4RTgqxKRVW6QfAXtqK2EsMKApI9XInWd4mC4BzkzxclLjO+rtCRem3qrpaVKtjX+znvhzIz4VFnHmCMpcg5kE8PFPhymlYLeGulgY4EsN5KTM2zW0eVJts3/yUcNcB4B6RwhBQ3UGD2RfFCFYoyt7NTDYDXtJdkfM9omuOdwR7siLKzNwgXKRNML/EwBBM8Av91GRcQa8xGsSedC22P1HEODPKnXElxNwKwjtAM2rpF2AR0nmAS8IZgbP4ylBiR9uIG2SSifvwS3ooXXhtRl+OCj4HZKqkzhfLuN00nbwCY2vw4f9cqFqJKLbY5h3HEossH28VDDSWfgvTpHkaaG54NrdMKO2dDTsaXZHfRxN1COQ+sO/gxyfofny9jFLWL9OCz1Aft0gT5RaslSk3dBPN+xC2QViKEI7M7ibUZ0hIUnLRRWQYaL+9g9OPk4QLFJ4LPvSA2ZHiiBzKVusIxRvvDuIvIcsn8EtYGxU4JwNI1CUIZpbLsEAZuIpmIVkNwQOAucRuQ5FMhUOkHUEPv1BryZfhE5z0MfqTTaabq6+gHw6sWfAx+hl9ETG4qk4Uh3JGL/AzPfJwrlTkxkcUhkdMah5jHvxnUs5z5HXW87aJryFdAU5eQRvGILm64H7st4L30nd56RrAghXYCCQ5LxOjcHrIHcCrnE2sOGK5RFjHM5WEMO+CQ9h16PfWprxt4MoJ7aDgXeMNhZGusA06vgzyJ0IaM1lM6yEI1Kno5BVyJ8i32uyi/0nuHMEdYeThuV2wjRprhnBkpeSIWhMQTH31Tg5sB+87CKkA90HpHtPtK+Y7kuTXP7GXsFeCLjLCcv9NZJfeKislXIm0waGyIiX7CmArie/EHkeHIDcH4ETYL3azyCjxqz//GTlsjbmL0owMP/DPB39Jp0Tfpq1kw3QA5B28rL8iy4+GYvEIib2P4Hxn7scwhrjAAepoy+AsGjmRJ3x54UQP+eRGWMyhw0NltGb03XBNUAs84IaIxhZmWzJtjl4RitRZj0NMk5+RDlX1SaKYGwMlJ2LqYabQscDiSSxSJNOlc0rSG4/yPmgCJ5LocUTcNf9HR+crtsVurIJQ2wJCbSJiaoB3utAe5Kn+R5MUPEiCpkBb00vk4KaFWNJLbgpFWxGB65tRTQmoYelh/gU65YqNkSQtoVhP8R198C4SOKG+QTNdPwkomMm2Nbn8SJe+DEfrQ6ossjCsUviLjMPvjyAtbMJYpXVldd9uqPnDbEw7xqr3mXlHIBX0+jEo6yc4U8RBovdn3l12QZ5k1ZaHUa7SMk/hTK7lz5JZ6P2GpEOmuFHh567HLeRiqB34haT1rGGLUCqA1cBk5zW6KyEZmCIqls0JTxPPTJts5Rw9eR9ldVrMCKxmXGd+3PbBLDrGQ2gtwKbA7Vir3TSYkH0TObQ9jLFM+PIfSVakEfzRmOs0YfpAeYa5Wk9dxh8KXoWxrom4oRtFAcQ69saeTUclJdhGQn1HvJzWHdNF68i9Ia0qaQrLJE9oRzAJTqx6CZ74ThtaQSbtd/MaOGS/yMZs1eDqh1/GL46gMPTWRJnOFhr3OwmvDlhxQPb6XotXlUVjO+DE8W/emQ55zpd4J1zVL57GHjGTDMDhnKOWTEUrhf8IaEGJDCy1ou+1jTJCQ5mYksfdgSGjgNq2aK9NbLjbh3GeA48K8p7i+bk8ehn0K/QYz2qzGZnzLhfvx2FIV1pS7CXTt5D97hxp/FD8pTMhbcbvrX4NK0DkLuR8w/VZ7QD7xtvMqnZQeH62iLHYo64i9KKMS3iMyHJ5M+Nsa3Bzt3c90pDq7ReA0Gsk4f3cTmEa+eVZCvEBYT4onc9mRowwnGEfrbMyE01OUvU+ZE5AkOtiJYhyftMN3FwkBLmQnMuyKnnPXzMdw34PSCukldaa7hERoiFFIod7NgF/MMNugJvJh+q9EdvxCcPIZxtjA/D9yFm90frL3WaA92kbzFum+RXYycCL2E+THW9keWestVW3VzBLdcBwE/I3MQxilh/hNzNeY8RjVIMeNa5n3YfTo8c5iDrqIhYCrMk7iJ3ljwE2NL5R8gFVYRv4DSKvhvN+R3ZrFWP0PYpwFKLUSp8YFAPOE+8BuDebVG/6dBLYw7Fc96UNfEDLEP8Axda5NszpSrdSh7jGSPJeCGVWkIiMKLkk505WOuW3TOomO40kpcqdzm/6LPn2VLecVt1xB4AAAAAElFTkSuQmCC);
|
||||
background-image:url('../img/pro.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: auto;
|
||||
background-size: 50px;
|
||||
background-position: center;
|
||||
display: inline-block;
|
||||
width: 66px;
|
||||
height: 19px;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1622528816731" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2577" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><defs><style type="text/css">@font-face { font-family: element-icons; src: url("chrome-extension://moombeodfomdpjnpocobemoiaemednkg/fonts/element-icons.woff") format("woff"), url("chrome-extension://moombeodfomdpjnpocobemoiaemednkg/fonts/element-icons.ttf ") format("truetype"); }
|
||||
</style></defs><path d="M87.04 309.76h849.92c45.056 0 81.92 36.864 81.92 81.92v240.64c0 45.056-36.864 81.92-81.92 81.92H87.04c-45.056 0-81.92-36.864-81.92-81.92v-240.64c0-45.056 36.864-81.92 81.92-81.92z" fill="#8a8a8a" p-id="2578" data-spm-anchor-id="a313x.7781069.0.i0" class="selected"></path><path d="M174.08 475.136l51.712 165.376 51.712-165.376H174.08z m10.752-91.648H125.44l-46.592 73.728h75.776l30.208-73.728zM276.48 456.704l-30.208-73.728h-40.96l-30.208 73.728H276.48z m-193.536 18.432l51.2 63.488 67.072 82.432-47.104-145.92H82.944z m183.808-91.648L296.96 456.704h76.8l-47.616-73.728H266.752z m-15.36 236.032l89.088-109.056 28.672-35.328h-71.68l-46.08 144.384zM529.92 430.592h-67.584v162.304h30.72V532.992h36.352c39.936 0 59.904-17.408 59.904-51.2s-19.968-51.2-59.392-51.2z m-36.864 27.136h34.816c10.752 0 18.432 2.048 23.552 5.632 4.608 3.584 7.168 9.728 7.168 17.92 0 8.704-2.56 14.848-6.656 18.432-5.12 3.584-13.312 5.632-23.552 5.632h-34.816v-47.616zM733.696 567.296l-2.56-25.6c-1.536-13.824-7.68-23.04-18.432-27.648 6.144-2.56 11.264-7.168 14.848-12.288 4.608-6.656 7.168-14.848 7.168-23.04 0-15.36-5.12-27.648-15.872-36.352-9.728-7.68-23.04-11.264-39.424-11.264h-72.704v162.304h30.72V528.896h38.4c8.704 0 14.336 1.536 18.432 5.12 4.096 3.072 6.144 8.704 7.168 16.896l2.048 19.456c1.024 9.728 3.584 16.384 7.168 22.016l0.512 1.024h34.816l-3.584-4.608c-5.12-5.632-8.192-12.8-8.704-21.504z m-96.256-109.568h38.4c10.24 0 17.408 1.536 21.504 5.12 4.096 3.072 6.144 8.704 6.144 16.384 0 7.168-2.048 12.8-6.144 16.384-5.12 4.096-12.288 5.632-21.504 5.632h-38.4v-43.52zM890.88 452.096c-14.336-15.872-33.792-24.064-58.88-24.064s-44.544 8.192-58.88 24.576c-13.824 15.36-20.48 34.816-20.48 59.904 0 24.576 6.656 44.544 20.48 59.904 14.336 15.872 33.792 24.064 58.88 24.064 24.576 0 44.544-8.192 58.88-24.064 13.824-15.36 20.48-35.328 20.48-59.904 0-25.088-6.656-45.568-20.48-60.416z m-58.88 3.584c15.872 0 27.648 4.608 35.84 14.848 8.192 10.24 12.288 24.064 12.288 41.984 0 17.408-4.096 31.744-12.288 41.472-8.192 9.728-20.48 14.848-35.84 14.848s-27.648-5.12-35.84-15.36c-8.192-10.24-12.288-23.552-12.288-40.96 0-17.408 4.096-31.232 12.288-40.96 8.704-10.752 20.48-15.872 35.84-15.872z" fill="#FFFFFF" p-id="2579"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1622511998564" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5405" data-spm-anchor-id="a313x.7781069.0.i4" width="70" height="70" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css">@font-face { font-family: element-icons; src: url("chrome-extension://moombeodfomdpjnpocobemoiaemednkg/fonts/element-icons.woff") format("woff"), url("chrome-extension://moombeodfomdpjnpocobemoiaemednkg/fonts/element-icons.ttf ") format("truetype"); }
|
||||
</style></defs><path d="M87.04 309.76h849.92c45.056 0 81.92 36.864 81.92 81.92v240.64c0 45.056-36.864 81.92-81.92 81.92H87.04c-45.056 0-81.92-36.864-81.92-81.92v-240.64c0-45.056 36.864-81.92 81.92-81.92z" fill="#FFB800" p-id="5406" data-spm-anchor-id="a313x.7781069.0.i3" class=""></path><path d="M174.08 475.136l51.712 165.376 51.712-165.376H174.08z m10.752-91.648H125.44l-46.592 73.728h75.776l30.208-73.728zM276.48 456.704l-30.208-73.728h-40.96l-30.208 73.728H276.48z m-193.536 18.432l51.2 63.488 67.072 82.432-47.104-145.92H82.944z m183.808-91.648L296.96 456.704h76.8l-47.616-73.728H266.752z m-15.36 236.032l89.088-109.056 28.672-35.328h-71.68l-46.08 144.384zM529.92 430.592h-67.584v162.304h30.72V532.992h36.352c39.936 0 59.904-17.408 59.904-51.2s-19.968-51.2-59.392-51.2z m-36.864 27.136h34.816c10.752 0 18.432 2.048 23.552 5.632 4.608 3.584 7.168 9.728 7.168 17.92 0 8.704-2.56 14.848-6.656 18.432-5.12 3.584-13.312 5.632-23.552 5.632h-34.816v-47.616zM733.696 567.296l-2.56-25.6c-1.536-13.824-7.68-23.04-18.432-27.648 6.144-2.56 11.264-7.168 14.848-12.288 4.608-6.656 7.168-14.848 7.168-23.04 0-15.36-5.12-27.648-15.872-36.352-9.728-7.68-23.04-11.264-39.424-11.264h-72.704v162.304h30.72V528.896h38.4c8.704 0 14.336 1.536 18.432 5.12 4.096 3.072 6.144 8.704 7.168 16.896l2.048 19.456c1.024 9.728 3.584 16.384 7.168 22.016l0.512 1.024h34.816l-3.584-4.608c-5.12-5.632-8.192-12.8-8.704-21.504z m-96.256-109.568h38.4c10.24 0 17.408 1.536 21.504 5.12 4.096 3.072 6.144 8.704 6.144 16.384 0 7.168-2.048 12.8-6.144 16.384-5.12 4.096-12.288 5.632-21.504 5.632h-38.4v-43.52zM890.88 452.096c-14.336-15.872-33.792-24.064-58.88-24.064s-44.544 8.192-58.88 24.576c-13.824 15.36-20.48 34.816-20.48 59.904 0 24.576 6.656 44.544 20.48 59.904 14.336 15.872 33.792 24.064 58.88 24.064 24.576 0 44.544-8.192 58.88-24.064 13.824-15.36 20.48-35.328 20.48-59.904 0-25.088-6.656-45.568-20.48-60.416z m-58.88 3.584c15.872 0 27.648 4.608 35.84 14.848 8.192 10.24 12.288 24.064 12.288 41.984 0 17.408-4.096 31.744-12.288 41.472-8.192 9.728-20.48 14.848-35.84 14.848s-27.648-5.12-35.84-15.36c-8.192-10.24-12.288-23.552-12.288-40.96 0-17.408 4.096-31.232 12.288-40.96 8.704-10.752 20.48-15.872 35.84-15.872z" fill="#FFFFFF" p-id="5407" data-spm-anchor-id="a313x.7781069.0.i5" class=""></path></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
+199
-8
@@ -228,14 +228,18 @@ $('.open_two_verify_view').click(function(){
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var three_channel_status = {};
|
||||
(function(){
|
||||
check_two_step(function(res){
|
||||
$('#panel_verification').prop('checked',res.status);
|
||||
});
|
||||
get_three_channel(function(res){
|
||||
three_channel_status = res;
|
||||
$('#channel_auth').val(!res.user_mail.user_name && !res.dingding.dingding ? 'Email is not set':(res.user_mail.user_name? 'Email is set':(res.dingding.dingding? 'dingding is set': '')))
|
||||
});
|
||||
get_login_send(function(rdata){
|
||||
$('#panel_report').val(!rdata.status ? 'Email is not set':(rdata.msg.mail? 'Already set':'Not set'))
|
||||
})
|
||||
})()
|
||||
|
||||
function get_three_channel(callback){
|
||||
@@ -243,6 +247,21 @@ function get_three_channel(callback){
|
||||
if(callback) callback(res);
|
||||
});
|
||||
}
|
||||
function get_login_send(callback){
|
||||
var loadS = bt.load('Getting login information, please wait...')
|
||||
$.post('/config?action=get_login_send',function(res){
|
||||
loadS.close()
|
||||
if(callback) callback(res);
|
||||
});
|
||||
}
|
||||
function login_ipwhite(obj,callback){
|
||||
var loadY = bt.load('Getting IP lists, please wait...')
|
||||
$.post('/config?action=login_ipwhite',obj,function(res){
|
||||
loadY.close()
|
||||
if(!res.status) return layer.msg(res.msg,{icon:res.status?1:2})
|
||||
if(callback) callback(res);
|
||||
});
|
||||
}
|
||||
|
||||
function check_two_step(callback){
|
||||
$.post('/config?action=check_two_step',function(res){
|
||||
@@ -360,6 +379,7 @@ function bindBTName(a,type){
|
||||
p2 = $("#p2").val();
|
||||
var loadT = layer.msg(lan.config.token_get,{icon:16,time:0,shade: [0.3, '#000']});
|
||||
$.post(" /ssl?action=GetToken", "username=" + p1 + "&password=" + p2, function(b){
|
||||
bt.clear_cookie('bt_user_info')
|
||||
layer.close(loadT);
|
||||
layer.msg(b.msg, {icon: b.status?1:2});
|
||||
if(b.status) {
|
||||
@@ -385,6 +405,7 @@ function UnboundBt(){
|
||||
layer.confirm(lan.config.binding_un_msg,{closeBtn:2,icon:3,title:lan.config.binding_un},function(){
|
||||
$.get("/ssl?action=DelToken",function(b){
|
||||
layer.msg(b.msg,{icon:b.status? 1:2})
|
||||
bt.clear_cookie('bt_user_info')
|
||||
if(b.status){
|
||||
window.location.reload();
|
||||
$("input[name='btusername']").val('');
|
||||
@@ -918,7 +939,177 @@ function modify_basic_auth_to() {
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function set_panel_report(){
|
||||
if(!three_channel_status.user_mail.user_name) return layer.msg('Please set up the [ Notification ] first',{icon:2})
|
||||
get_login_send(function(rdata){
|
||||
layer.open({
|
||||
type: 1,
|
||||
area:'700px',
|
||||
title: "Login panel alarm",
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
content: '<div class="bt-form">\
|
||||
<div class="bt-w-main">\
|
||||
<div class="bt-w-menu" style="width: 140px;">\
|
||||
<p class="bgw">Alarm settings</p>\
|
||||
<p>IP whitelist</p>\
|
||||
</div>\
|
||||
<div class="bt-w-con pd15" style="margin-left: 140px;">\
|
||||
<div class="plugin_body">\
|
||||
<div class="conter_box active" >\
|
||||
<div class="bt-form" style="height:500px">\
|
||||
<div class="line">\
|
||||
<span class="set-tit" style="display:inline-block;vertical-align: top;margin: 3px;color:#666" title="Notification email">Send to mailbox</span>\
|
||||
<div class="mail" name="server_input" style="display:inline-block;margin:0px 10px 0px 0px">\
|
||||
<input class="btswitch btswitch-ios" id="mail" type="checkbox" '+(!rdata.status?"":(rdata.msg.mail?"checked":""))+' >\
|
||||
<label class="btswitch-btn" for="mail"></label>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="line" style="max-height:400px;height:auto;overflow:auto">\
|
||||
<div class="divtable">\
|
||||
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0"><thead><tr><th width="75%">login info</th><th width="25%" style="text-align:right">time</th></tr></thead>\
|
||||
<tbody id="server_table"></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="page" id="server_table_page"></div>\
|
||||
</div>\
|
||||
<ul class="mtl0 c7" style="font-size: 13px;position:absolute;bottom:0;padding-right: 40px;">\
|
||||
<li style="list-style:inside disc">xxxxxxxxxxxxxxxxxxx</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
<div class="conter_box" style="display:none;height:500px">\
|
||||
<div class="bt-form">\
|
||||
<div class="line" style="display:inline-block">\
|
||||
<input name="ip_write" class="bt-input-text mr5" type="text" style="width: 220px;" placeholder="Please enter the IP">\
|
||||
<button class="btn btn-success btn-sm add_ip_write" style="padding: 4px 15px">Add</button>\
|
||||
</div>\
|
||||
<div class="line" style="float:right">\
|
||||
<button class="btn btn-default btn-sm clear_all" style="padding: 4px 15px;text-align:right">Clean all</button>\
|
||||
</div>\
|
||||
<div class="line" style="max-height:400px;height:auto;overflow:auto">\
|
||||
<div class="divtable">\
|
||||
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0"><thead><tr><th width="60%">IP</th><th width="40%" style="text-align:right">Opt</th></tr></thead>\
|
||||
<tbody id="ip_write_table"></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<ul class="mtl0 c7" style="font-size: 13px;position:absolute;bottom:0;padding-right: 40px;">\
|
||||
<li style="list-style:inside disc">Only allow to set ipv4 whitelist</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(index,layers){
|
||||
get_log_table();
|
||||
get_ip_write_table()
|
||||
$(".bt-w-menu p").click(function () {
|
||||
var index = $(this).index();
|
||||
$(this).addClass('bgw').siblings().removeClass('bgw');
|
||||
console.log(index,'111');
|
||||
switch(index){
|
||||
case 0:
|
||||
get_log_table();
|
||||
break;
|
||||
case 1:
|
||||
get_ip_write_table()
|
||||
break;
|
||||
}
|
||||
$('.conter_box').eq(index).show().siblings().hide();
|
||||
});
|
||||
//设置告警
|
||||
$('#mail').on('click',function(){
|
||||
var _checked = $(this).prop('checked');
|
||||
if(_checked){
|
||||
$.post('/config?action=set_login_send',{type:'mail'},function(res){
|
||||
layer.msg(res.msg,{icon:res.status?1:2});
|
||||
});
|
||||
}else{
|
||||
$.post('/config?action=clear_login_send',{type:'mail'},function(res){
|
||||
layer.msg(res.msg,{icon:res.status?1:2});
|
||||
});
|
||||
}
|
||||
});
|
||||
//添加
|
||||
$('.add_ip_write').on('click',function(){
|
||||
var _ip = $('[name="ip_write"]').val();
|
||||
if(!bt.check_ip(_ip)) return layer.msg('Please enter the correct IP',{icon:2})
|
||||
login_ipwhite({ip:_ip,type:'add'},function(res){
|
||||
if(res.status) get_ip_write_table()
|
||||
layer.msg(res.msg,{icon:res.status?1:2});
|
||||
})
|
||||
})
|
||||
//删除ip白名单
|
||||
$('#ip_write_table').on('click','.del_ip_write',function(){
|
||||
var _ip = $(this).parents('tr').data().data;
|
||||
login_ipwhite({ip:_ip,type:'del'},function(res){
|
||||
if(res.status) get_ip_write_table()
|
||||
layer.msg(res.msg,{icon:res.status?1:2});
|
||||
})
|
||||
});
|
||||
//清空全部
|
||||
$('.clear_all').on('click',function(){
|
||||
layer.confirm('Whether to clear the IP whitelist', {title:'Tips',btn: ['Confirm','Cancel'],icon:0,closeBtn:2}, function() {
|
||||
login_ipwhite({type:'clear'},function(res){
|
||||
if(res.status) get_ip_write_table()
|
||||
layer.msg(res.msg,{icon:res.status?1:2});
|
||||
})
|
||||
})
|
||||
})
|
||||
//分页操作
|
||||
$('#server_table_page').on('click','a',function(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
var _p = $(this).attr('href').match(/p=([0-9]*)/)[1];
|
||||
get_log_table({p:_p});
|
||||
})
|
||||
},
|
||||
cancel:function(){
|
||||
$('#panel_report').val( $('#mail').prop('checked') ? 'Already set' : 'Not set');
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
function get_log_table(obj){
|
||||
if(!obj) obj = {p:1}
|
||||
var loadT = bt.load('Getting Logs list, please wait')
|
||||
$.post('/config?action=get_login_log',obj,function(res){
|
||||
loadT.close()
|
||||
$('#server_table').empty()
|
||||
if(res.data.length > 0){
|
||||
$.each(res.data,function(index,item){
|
||||
$('#server_table').append($('<tr>\
|
||||
<td>'+ item.log +'</td>\
|
||||
<td style="text-align:right">'+ item.addtime +'</td>\
|
||||
</tr>').data({data:item,index:index}))
|
||||
});
|
||||
}else{
|
||||
$('#server_table').html('<tr><td colspan="2" style="text-align:center">None Data</td></tr>')
|
||||
}
|
||||
$('#server_table_page').html(res.page)
|
||||
});
|
||||
}
|
||||
function get_ip_write_table(){
|
||||
$('#ip_write_table').empty()
|
||||
login_ipwhite({type:'get'},function(res){
|
||||
if(res.msg.length > 0){
|
||||
$.each(res.msg,function(index,item){
|
||||
$('#ip_write_table').append($('<tr>\
|
||||
<td>'+ item +'</td>\
|
||||
<td style="text-align:right">\
|
||||
<a href="javascript:;" class="btlink del_ip_write" >Del</a>\
|
||||
</td>\
|
||||
</tr>').data({data:item,index:index}))
|
||||
});
|
||||
}else{
|
||||
$('#ip_write_table').html('<tr><td colspan="2" style="text-align:center">None Data</td></tr>')
|
||||
}
|
||||
})
|
||||
}
|
||||
function modify_basic_auth() {
|
||||
var loadT = layer.msg(lan.config.setting_basicauth, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
$.post('/config?action=get_basic_auth_stat', {}, function (rdata) {
|
||||
@@ -958,7 +1149,7 @@ function open_three_channel_auth(){
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "600px",
|
||||
title: "Setting up a message channel",
|
||||
title: "Setting up notification",
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
@@ -1096,15 +1287,15 @@ function sender_info_edit(){
|
||||
_port = $('#port_select').val()
|
||||
}
|
||||
if(_email == ''){
|
||||
return layer.msg('Email address cannot be empty!',{icon:2});
|
||||
return layer.msg('Email address cannot be empty!',{icon:2});
|
||||
}else if(_passW == ''){
|
||||
return layer.msg('STMP password cannot be empty!',{icon:2});
|
||||
return layer.msg('STMP password cannot be empty!',{icon:2});
|
||||
}else if(_server == ''){
|
||||
return layer.msg('STMP server address cannot be empty!',{icon:2});
|
||||
return layer.msg('STMP server address cannot be empty!',{icon:2});
|
||||
}else if(_port == ''){
|
||||
return layer.msg('STMP server port cannot be empty!',{icon:2});
|
||||
return layer.msg('STMP server port cannot be empty!',{icon:2});
|
||||
}
|
||||
var loadT = layer.msg('Please wait while generating mailbox channel...', { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
var loadT = layer.msg('The notification is being generated, please wait...', { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
layer.close(index)
|
||||
$.post('/config?action=user_mail_send',{email:_email,stmp_pwd:_passW,hosts:_server,port:_port},function(rdata){
|
||||
layer.close(loadT);
|
||||
|
||||
+1431
-995
File diff suppressed because it is too large
Load Diff
Vendored
+45
-29
File diff suppressed because one or more lines are too long
+794
-325
File diff suppressed because it is too large
Load Diff
Vendored
+5
-1
File diff suppressed because one or more lines are too long
+516
-229
@@ -1,15 +1,63 @@
|
||||
bt.pub.check_install(function (rdata) {
|
||||
if (rdata === false) bt.index.rec_install();
|
||||
})
|
||||
// bt.pub.check_install(function (rdata) {
|
||||
// if (rdata === false) bt.index.rec_install();
|
||||
// })
|
||||
$("select[name='network-io']").change(function(){
|
||||
var net_key = $(this).val();
|
||||
if(net_key == 'all') net_key = '';
|
||||
bt.set_cookie('network_io_key',net_key);
|
||||
});
|
||||
$("select[name='network-io'],select[name='disk-io']").change(function(){
|
||||
var key = $(this).val(),type = $(this).attr('name')
|
||||
if(type == 'network-io'){
|
||||
if(key == 'all') key = '';
|
||||
bt.set_cookie('network_io_key',key);
|
||||
}else{
|
||||
bt.set_cookie('disk_io_key',key);
|
||||
}
|
||||
});
|
||||
$('.tabs-nav span').click(function () {
|
||||
var indexs = $(this).index();
|
||||
$(this).addClass('active').siblings().removeClass('active')
|
||||
$('.tabs-content .tabs-item:eq('+ indexs +')').addClass('tabs-active').siblings().removeClass('tabs-active')
|
||||
$('.tabs-down select:eq('+ indexs +')').removeClass('hide').siblings().addClass('hide')
|
||||
switch(indexs){
|
||||
case 0:
|
||||
index.net.table.resize();
|
||||
break;
|
||||
case 1:
|
||||
index.iostat.table.resize();
|
||||
break;
|
||||
}
|
||||
})
|
||||
var interval_stop = false;
|
||||
var index = {
|
||||
warning_list:[],
|
||||
warning_num:0,
|
||||
warning_list:[],
|
||||
warning_num:0,
|
||||
series_option:{},// 配置项
|
||||
chart_json:{}, // 所有图表echarts对象
|
||||
chart_view:{}, // 磁盘echarts对象
|
||||
disk_view:[], // 释放内存标记
|
||||
chart_result:null,
|
||||
release:false,
|
||||
load_config:[{
|
||||
title: lan.index.run_block,
|
||||
val: 90,
|
||||
color: '#dd2f00'
|
||||
},{
|
||||
title: lan.index.run_slow,
|
||||
val: 80,
|
||||
color: '#ff9900'
|
||||
},{
|
||||
title: lan.index.run_normal,
|
||||
val: 70,
|
||||
color: '#20a53a'
|
||||
},{
|
||||
title: lan.index.run_fluent,
|
||||
val: 30,
|
||||
color: '#20a53a'
|
||||
}],
|
||||
interval: {
|
||||
limit: 10,
|
||||
count: 0,
|
||||
@@ -23,7 +71,7 @@ var index = {
|
||||
return;
|
||||
}
|
||||
_this.count++;
|
||||
if (!interval_stop) index.get_data_info();
|
||||
if (!interval_stop) index.reander_system_info();
|
||||
}, 3000)
|
||||
},
|
||||
reload: function () {
|
||||
@@ -48,8 +96,8 @@ var index = {
|
||||
obj.tData = index.net.data.aData;
|
||||
|
||||
obj.list = [];
|
||||
obj.list.push({ name: lan.index.net_up, data: index.net.data.uData, circle: 'circle', itemStyle: { normal: { color: '#f7b851' } }, areaStyle: { normal: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(255, 140, 0,0.5)' }, { offset: 1, color: 'rgba(255, 140, 0,0.8)' }], false) } }, lineStyle: { normal: { width: 1, color: '#aaa' } } });
|
||||
obj.list.push({ name: lan.index.net_down, data: index.net.data.dData, circle: 'circle', itemStyle: { normal: { color: '#52a9ff' } }, areaStyle: { normal: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(30, 144, 255,0.5)' }, { offset: 1, color: 'rgba(30, 144, 255,0.8)' }], false) } }, lineStyle: { normal: { width: 1, color: '#aaa' } } });
|
||||
obj.list.push({ name: lan.index.net_up, data: index.net.data.uData, circle: 'circle', itemStyle: { normal: { color: '#f7b851' } }, areaStyle: { normal: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(255, 140, 0,1)' }, { offset: 1, color: 'rgba(255, 140, 0,.4)' }], false) } }, lineStyle: { normal: { width: 1, color: '#f7b851' } } });
|
||||
obj.list.push({ name: lan.index.net_down, data: index.net.data.dData, circle: 'circle', itemStyle: { normal: { color: '#52a9ff' } }, areaStyle: { normal: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(30, 144, 255,1)' }, { offset: 1, color: 'rgba(30, 144, 255,.4)' }], false) } }, lineStyle: { normal: { width: 1, color: '#52a9ff' } } });
|
||||
option = bt.control.format_option(obj)
|
||||
|
||||
index.net.table.setOption(option);
|
||||
@@ -71,6 +119,64 @@ var index = {
|
||||
_net.data.aData.push(d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds());
|
||||
}
|
||||
},
|
||||
iostat: {
|
||||
table: null,
|
||||
data: {
|
||||
uData: [],
|
||||
dData: [],
|
||||
aData: [],
|
||||
tipsData:[]
|
||||
},
|
||||
init: function () {
|
||||
//流量图表
|
||||
index.iostat.table = echarts.init(document.getElementById('IoStat'));
|
||||
var obj = {};
|
||||
obj.dataZoom = [];
|
||||
obj.unit = lan.index.unit + ':MB/s';
|
||||
obj.tData = index.iostat.data.aData;
|
||||
obj.formatter = function(config){
|
||||
var _config = config,_tips = "Time:"+ _config[0].axisValue +"<br />",options = {
|
||||
read_bytes: 'Read Bytes',
|
||||
read_count: 'Read Count ',
|
||||
read_merged_count: 'Read Merged Count',
|
||||
read_time: 'Read Wait',
|
||||
write_bytes: 'Write Bytes',
|
||||
write_count: 'Write Count',
|
||||
write_merged_count: 'Write Merged Count',
|
||||
write_time: 'Write Wait',
|
||||
},data = index.iostat.data.tipsData[config[0].dataIndex],list = ['read_count','write_count','read_merged_count','write_merged_count','read_time','write_time',]
|
||||
for(var i=0;i < config.length;i++){
|
||||
if(typeof config[i].data == "undefined") return false
|
||||
_tips += '<span style="display: inline-block;width: 10px;height: 10px;border-radius: 50%;background: '+ config[i].color +';"></span> <span>'+ config[i].seriesName +':'+ (parseFloat(config[i].data)).toFixed(2) + ' MB/s' + '</span><br />'
|
||||
}
|
||||
$.each(list,function(index,item){
|
||||
_tips += '<span style="display: inline-block;width: 10px;height: 10px;"></span> <span style="'+ (item.indexOf('time') > -1?('color:'+ ((data[item] > 100 && data[item] < 1000)?'#ff9900':(data[item] >= 1000?'red':'#20a53a'))):'') +'">'+ options[item] +':' + data[item] + (item.indexOf('time') > -1 ?' ms':' per sec') + '</span><br />'
|
||||
})
|
||||
return _tips;
|
||||
}
|
||||
obj.list = [];
|
||||
obj.list.push({ name: 'Read Bytes', data: index.iostat.data.uData, circle: 'circle', itemStyle: { normal: { color: '#FF4683' } }, areaStyle: { normal: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(255,70,131,1)' }, { offset: 1, color: 'rgba(255,70,131,.4' }], false) } }, lineStyle: { normal: { width: 1, color: '#FF4683' } } });
|
||||
obj.list.push({ name: 'Write Bytes', data: index.iostat.data.dData, circle: 'circle', itemStyle: { normal: { color: '#6CC0CF' } }, areaStyle: { normal: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(108,192,207,1)' }, { offset: 1, color: 'rgba(108,192,207,.4)' }], false) } }, lineStyle: { normal: { width: 1, color: '#6CC0CF' } } });
|
||||
option = bt.control.format_option(obj)
|
||||
index.iostat.table.setOption(option);
|
||||
window.addEventListener("resize", function () {
|
||||
index.iostat.table.resize();
|
||||
});
|
||||
},
|
||||
add: function (read, write,data) {
|
||||
var _disk = this;
|
||||
var limit = 8;
|
||||
var d = new Date()
|
||||
if (_disk.data.uData.length >= limit) _disk.data.uData.splice(0, 1);
|
||||
if (_disk.data.dData.length >= limit) _disk.data.dData.splice(0, 1);
|
||||
if (_disk.data.aData.length >= limit) _disk.data.aData.splice(0, 1);
|
||||
if (_disk.data.tipsData.length >= limit) _disk.data.tipsData.splice(0, 1);
|
||||
_disk.data.uData.push(read);
|
||||
_disk.data.dData.push(write);
|
||||
_disk.data.tipsData.push(data);
|
||||
_disk.data.aData.push(d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds());
|
||||
}
|
||||
},
|
||||
mem: {
|
||||
status: 1,
|
||||
set_status: function (obj, status, val) {
|
||||
@@ -98,121 +204,136 @@ var index = {
|
||||
},
|
||||
get_init: function () {
|
||||
var _this = this;
|
||||
setTimeout(function () { _this.get_disk_list(); }, 10);
|
||||
// setTimeout(function () { _this.get_disk_list(); }, 10);
|
||||
setTimeout(function () { _this.get_warning_list(); }, 20);
|
||||
setTimeout(function () { _this.get_server_info(); }, 30);
|
||||
|
||||
bt.pub.get_user_info(function (rdata) {
|
||||
if (rdata.status) {
|
||||
$(".bind-user").html(rdata.data.username);
|
||||
bt.send('check_user_auth', 'ajax/check_user_auth', {}, function (rd) {
|
||||
if (!rd.status) bt.msg(rd);
|
||||
});
|
||||
bt.weixin.get_user_info(function (rdata) {
|
||||
if (!rdata.status) {
|
||||
bt.msg(rdata);
|
||||
return;
|
||||
}
|
||||
if (JSON.stringify(rdata.msg) != '{}') {
|
||||
var datas = rdata.msg;
|
||||
for (var key in datas) {
|
||||
var item = datas[key];
|
||||
item.nickName
|
||||
$(".bind-weixin a").text(item.nickName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
// setTimeout(function () { _this.get_server_info(); }, 30);
|
||||
_this.reander_system_info(function(rdata){
|
||||
// 负载悬浮事件
|
||||
$('#loadChart').hover(function () {
|
||||
var arry = [
|
||||
[lan.index.avg_load_atlast_onemin,rdata.load.one],
|
||||
[lan.index.avg_load_atlast_fivemin,rdata.load.five],
|
||||
[lan.index.avg_load_atlast_fifteenmin,rdata.load.fifteen]
|
||||
],tips = '';
|
||||
$.each(arry || [],function (index,item){
|
||||
tips += item[0]+':'+ item[1] +'</br>';
|
||||
})
|
||||
$.each(rdata.cpu_times || {},function (key,item){
|
||||
tips += key +':'+ item +'</br>';
|
||||
})
|
||||
// '最近1分钟平均负载:' + rdata.load.one + '</br>最近5分钟平均负载:' + rdata.load.five + '</br>最近15分钟平均负载:' + rdata.load.fifteen + ''
|
||||
layer.tips(tips, this, { time: 0, tips: [1, '#999'] });
|
||||
}, function(){
|
||||
layer.closeAll('tips');
|
||||
})
|
||||
|
||||
// cpu悬浮事件
|
||||
$('#cpuChart').hover(function () {
|
||||
var cpuText = '';
|
||||
for (var i = 1; i < rdata.cpu[2].length + 1; i++) {
|
||||
var cpuUse = parseFloat(rdata.cpu[2][i - 1] == 0 ? 0 : rdata.cpu[2][i - 1]).toFixed(1)
|
||||
if (i % 2 != 0) {
|
||||
cpuText += 'CPU-' + i + ':' + cpuUse + '% | '
|
||||
} else {
|
||||
cpuText += 'CPU-' + i + ':' + cpuUse + '%'
|
||||
cpuText += `\n`
|
||||
}
|
||||
}
|
||||
else {
|
||||
$(".bind-weixin a").attr("href", "javascript:;");
|
||||
$(".bind-weixin a").click(function () {
|
||||
bt.msg({ msg: lan.index.bind_bt_account_first, icon: 2 });
|
||||
|
||||
layer.tips(rdata.cpu[3] + "</br>" + rdata.cpu[5] + " CPU," + (rdata.cpu[4]) + " Physical core, " + rdata.cpu[1]+" Logical core</br>"+ cpuText, this, { time: 0, tips: [1, '#999'] });
|
||||
}, function(){
|
||||
layer.closeAll('tips');
|
||||
})
|
||||
|
||||
$('#memChart').hover(function(){
|
||||
$(this).append('<div class="mem_mask shine_green" title="Click to free RAM"><div class="men_inside_mask"></div><div class="mem-re-con" style="display:block"></div></div>');
|
||||
$(this).find('.mem_mask .mem-re-con').animate({top:'5px'},400);
|
||||
$(this).next().hide();
|
||||
},function(){
|
||||
$(this).find('.mem_mask').remove()
|
||||
$(this).next().show();
|
||||
}).click(function(){
|
||||
var that = $(this);
|
||||
var data = _this.chart_result.mem;
|
||||
bt.show_confirm(lan.index.mem_release_sure, '<font style="color:red;">'+lan.index.mem_release_warn+'</font>', function () {
|
||||
_this.release = true
|
||||
var option = JSON.parse(JSON.stringify(_this.series_option));
|
||||
// 释放中...
|
||||
var count = ''
|
||||
var setInter = setInterval(function(){
|
||||
if(count == '...'){
|
||||
count = '.'
|
||||
}else{
|
||||
count += '.'
|
||||
}
|
||||
option.series[0].detail.formatter = lan.index.memre_ok_0 + count
|
||||
option.series[0].detail.fontSize = 15
|
||||
option.series[0].data[0].value = 0
|
||||
_this.chart_view.mem.setOption(option, true)
|
||||
that.next().hide()
|
||||
},400)
|
||||
// 释放接口请求
|
||||
bt.system.re_memory(function (res) {
|
||||
that.next().show()
|
||||
clearInterval(setInter)
|
||||
option.series[0].detail = $.extend(option.series[0].detail,{
|
||||
formatter:lan.index.memre_ok_1+"\n"+ bt.format_size(data.memRealUsed - res.memRealUsed),
|
||||
lineHeight:18,
|
||||
padding:[5,0]
|
||||
})
|
||||
_this.chart_view.mem.setOption(option,true)
|
||||
setTimeout(function() {
|
||||
_this.release = false;
|
||||
_this.chart_result.mem = res;
|
||||
_this.chart_active('mem');
|
||||
}, 2000);
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 磁盘悬浮事件
|
||||
for(var i = 0; i < rdata.disk.length; i++){
|
||||
var disk = rdata.disk[i],texts = "<strong>"+lan.index.base_info+"</strong></br>"
|
||||
texts += "Partition: " + disk.filesystem + "</br>"
|
||||
texts += "Type: " + disk.type + "</br>"
|
||||
texts += "Mount point: " + disk.path + "</br></br>"
|
||||
texts += "<strong>"+ lan.index.inode_info +":</strong></br>"
|
||||
texts += lan.index.total+": " + disk.inodes[0] + "</br>"
|
||||
texts += lan.index.already_use+": " + disk.inodes[1] + "</br>"
|
||||
texts += lan.index.available+": " + disk.inodes[2] + "</br>"
|
||||
texts += lan.index.inode_percent+": " + disk.inodes[3] + "</br></br>"
|
||||
texts += "<strong>"+lan.index.capacity_info+"</strong></br>"
|
||||
texts += lan.index.capacity+": " + disk.size[0] + "</br>"
|
||||
texts += lan.index.already_use+": " + disk.size[1] + "</br>"
|
||||
texts += lan.index.available+": " + disk.size[2] + "</br>"
|
||||
texts += lan.index.usage_rate+": " + disk.size[3] + "</br>"
|
||||
$("#diskChart" + i).data('title',texts).hover(function () {
|
||||
layer.tips($(this).data('title'), this, { time: 0, tips: [1, '#999'] });
|
||||
}, function(){
|
||||
layer.closeAll('tips');
|
||||
})
|
||||
}
|
||||
_this.get_server_info(rdata);
|
||||
if(rdata.installed === false) bt.index.rec_install();
|
||||
if (rdata.user_info.status) {
|
||||
var rdata_data = rdata.user_info.data;
|
||||
bt.set_cookie('bt_user_info',JSON.stringify(rdata.user_info));
|
||||
$(".bind-user").html(rdata_data.username);
|
||||
}
|
||||
else {
|
||||
$(".bind-weixin a").attr("href", "javascript:;");
|
||||
$(".bind-weixin a").click(function () {
|
||||
bt.msg({ msg: '请先绑定宝塔账号!', icon: 2 });
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
_this.get_data_info(function (loadbox, rdata) {
|
||||
loadbox.find('.cicle').hover(function () {
|
||||
var _this = $(this);
|
||||
var d = _this.parents('ul').data('data').load;
|
||||
layer.tips(lan.index.avg_load_atlast_onemin + d.one + '</br>'+ lan.index.avg_load_atlast_fivemin + d.five + '</br>'+ lan.index.avg_load_atlast_fifteenmin + d.fifteen + '', _this, { time: 0, tips: [1, '#999'] });
|
||||
}, function () {
|
||||
layer.closeAll('tips');
|
||||
})
|
||||
|
||||
$('.cpubox').find('.cicle').hover(function () {
|
||||
var _this = $(this);
|
||||
var d = _this.parents('ul').data('data').cpu;
|
||||
var crs = '';
|
||||
var n1 = 0;
|
||||
for (var i = 0; i < d[2].length; i++) {
|
||||
n1++;
|
||||
crs += 'CPU-' + i + ": " + d[2][i] + '%' + (n1 % 2 == 0?'</br>':' | ');
|
||||
|
||||
}
|
||||
layer.tips(d[3] + "</br>" + d[5] + " CPU, " + d[4] + " Core, " + d[4]+" Thread</br>"+ crs, _this, { time: 0, tips: [1, '#999'] });
|
||||
}, function () {
|
||||
layer.closeAll('tips');
|
||||
});
|
||||
|
||||
$(".mem-release").hover(function () {
|
||||
$(this).addClass("shine_green");
|
||||
if (!($(this).hasClass("mem-action"))) {
|
||||
$(this).find(".mem-re-min").hide();
|
||||
$(this).find(".occupy").css({ "color": "#d2edd8" });
|
||||
$(this).find(".mem-re-con").css({ "display": "block" });
|
||||
$(this).find(".mem-re-con").animate({ "top": "0", opacity: 1 });
|
||||
}
|
||||
$(this).next().hide();
|
||||
}, function () {
|
||||
if (!($(this).hasClass("mem-action"))) {
|
||||
$(this).find(".mem-re-min").show();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
//$(this).find(".mem-re-min").hide();
|
||||
}
|
||||
$(this).removeClass("shine_green");
|
||||
$(this).find(".occupy").css({ "color": "#20a53a" });
|
||||
$(this).find(".mem-re-con").css({ "top": "15px", opacity: 1, "display": "none" });
|
||||
$(this).next().show();
|
||||
//$(this).next().html(bt.get_cookie("mem-before"));
|
||||
}).click(function () {
|
||||
if (($(this).hasClass("mem-action"))) return false;
|
||||
var _this = $(this);
|
||||
bt.show_confirm(lan.index.mem_release_sure, '<font style="color:red;">'+lan.index.mem_release_warn+'</font>', function () {
|
||||
if (!(_this.hasClass("mem-action"))) {
|
||||
_this.next().hide();
|
||||
_this.find('.mem-re-min').hide();
|
||||
var data = _this.parents('ul').data('data').mem;
|
||||
index.mem.set_status(_this, 2); //释放中
|
||||
bt.system.re_memory(function (nData) {
|
||||
index.mem.set_status(_this, lan.index.memre_ok);
|
||||
|
||||
_this.next().show();
|
||||
setTimeout(function () {
|
||||
var t = nData.memFree - data.memFree;
|
||||
var m = lan.index.memre_ok_2;
|
||||
if (t > 0) m = lan.index.memre_ok_1 + "<br>" + t + "MB";
|
||||
index.mem.set_status(_this, m);
|
||||
}, 200);
|
||||
setTimeout(function () {
|
||||
index.mem.set_status(_this, 1, (nData.memRealUsed * 100 / nData.memTotal).toFixed(1));
|
||||
_this.find('.mem-re-min').show();
|
||||
}, 1200);
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
setTimeout(function () { _this.interval.start(); }, 40)
|
||||
setTimeout(function () { index.get_index_list(); }, 50)
|
||||
|
||||
|
||||
setTimeout(function () {
|
||||
_this.net.init();
|
||||
_this.net.init();
|
||||
}, 60);
|
||||
setTimeout(function () {
|
||||
_this.iostat.init()
|
||||
}, 60);
|
||||
|
||||
setTimeout(function () {
|
||||
@@ -231,123 +352,43 @@ var index = {
|
||||
}, false)
|
||||
}, 70)
|
||||
},
|
||||
get_data_info: function (callback) {
|
||||
var _this = $(this);
|
||||
bt.system.get_net(function (net) {
|
||||
get_server_info: function (info) {
|
||||
var memFree = info.memTotal - info.memRealUsed;
|
||||
if (memFree < 64) {
|
||||
$("#messageError").show();
|
||||
$("#messageError").append('<p><span class="glyphicon glyphicon-alert" style="color: #ff4040; margin-right: 10px;">' + lan.index.mem_warning + '</span> </p>')
|
||||
}
|
||||
|
||||
var pub_arr = [{ val: 100, color: '#dd2f00' }, { val: 90, color: '#ff9900' }, { val: 70, color: '#20a53a' }, { val: 30, color: '#20a53a' }];
|
||||
var load_arr = [{ title: lan.index.run_block, val: 100, color: '#dd2f00' }, { title: lan.index.run_slow, val: 90, color: '#ff9900' }, { title: lan.index.run_normal, val: 70, color: '#20a53a' }, { title: lan.index.run_fluent, val: 30, color: '#20a53a' }];
|
||||
var _cpubox = $('.cpubox'), _membox = $('.membox'), _loadbox = $('.loadbox'), _diskbox = $('.diskbox')
|
||||
if (info.isuser > 0) {
|
||||
$("#messageError").show();
|
||||
$("#messageError").append('<p><span class="glyphicon glyphicon-alert" style="color: #ff4040; margin-right: 10px;"></span>' + lan.index.user_warning + '<span class="c7 mr5" title="'+lan.index.safe_problem_cant_ignore+'" style="cursor:no-drop"> ['+lan.index.cant_ignore+']</span><a class="btlink" href="javascript:setUserName();"> ['+lan.index.edit_now+']</a></p>')
|
||||
}
|
||||
|
||||
index.set_val(_cpubox, { usage: net.cpu[0], title: net.cpu[1]+' '+lan.index.cpu_core, items: pub_arr })
|
||||
index.set_val(_membox, { usage: (net.mem.memRealUsed * 100 / net.mem.memTotal).toFixed(1), items: pub_arr, title: net.mem.memRealUsed + '/' + net.mem.memTotal + '(MB)' })
|
||||
bt.set_cookie('memSize', net.mem.memTotal)
|
||||
for (var i = 0; i < _diskbox.length; i++) {
|
||||
index.set_val(_diskbox.eq(i), { usage: net.disk[i].size[3].split('%')[0], title: net.disk[i].size[1]+'/'+net.disk[i].size[0], items: pub_arr })
|
||||
}
|
||||
|
||||
var _lval = Math.round((net.load.one / net.load.max) * 100);
|
||||
if (_lval > 100) _lval = 100;
|
||||
index.set_val(_loadbox, { usage: _lval, items: load_arr })
|
||||
_loadbox.parents('ul').data('data', net);
|
||||
var net_key = bt.get_cookie('network_io_key');
|
||||
if(net_key){
|
||||
console.log(net_key,net.network[net_key])
|
||||
net.up = net.network[net_key].up;
|
||||
net.down = net.network[net_key].down;
|
||||
net.downTotal = net.network[net_key].downTotal;
|
||||
net.upTotal = net.network[net_key].upTotal;
|
||||
net.downPackets = net.network[net_key].downPackets;
|
||||
net.upPackets = net.network[net_key].upPackets;
|
||||
net.downAll = net.network[net_key].downTotal;
|
||||
net.upAll = net.network[net_key].upTotal;
|
||||
}
|
||||
var net_option = '<option value="all">All</option>';
|
||||
$.each(net.network,function(k,v){
|
||||
var act = (k == net_key)?'selected':'';
|
||||
net_option += '<option value="'+k+'" '+act+'>'+k+'</option>';
|
||||
});
|
||||
|
||||
$('select[name="network-io"]').html(net_option);
|
||||
//刷新流量
|
||||
$("#upSpeed").html(net.up + ' KB');
|
||||
$("#downSpeed").html(net.down + ' KB');
|
||||
$("#downAll").html(bt.format_size(net.downTotal));
|
||||
$("#upAll").html(bt.format_size(net.upTotal));
|
||||
index.net.add(net.up, net.down);
|
||||
if (index.net.table) index.net.table.setOption({ xAxis: { data: index.net.data.aData }, series: [{ name: lan.index.net_up, data: index.net.data.uData }, { name: lan.index.net_down, data: index.net.data.dData }] });
|
||||
|
||||
if (callback) callback(_loadbox, net);
|
||||
})
|
||||
},
|
||||
get_server_info: function () {
|
||||
bt.system.get_total(function (info) {
|
||||
var memFree = info.memTotal - info.memRealUsed;
|
||||
if (memFree < 64) {
|
||||
$("#messageError").show();
|
||||
$("#messageError").append('<p><span class="glyphicon glyphicon-alert" style="color: #ff4040; margin-right: 10px;">' + lan.index.mem_warning + '</span> </p>')
|
||||
}
|
||||
|
||||
if (info.isuser > 0) {
|
||||
$("#messageError").show();
|
||||
$("#messageError").append('<p><span class="glyphicon glyphicon-alert" style="color: #ff4040; margin-right: 10px;"></span>' + lan.index.user_warning + '<span class="c7 mr5" title="'+lan.index.safe_problem_cant_ignore+'" style="cursor:no-drop"> ['+lan.index.cant_ignore+']</span><a class="btlink" href="javascript:setUserName();"> ['+lan.index.edit_now+']</a></p>')
|
||||
}
|
||||
|
||||
if (info.isport === true) {
|
||||
$("#messageError").show();
|
||||
$("#messageError").append('<p><span class="glyphicon glyphicon-alert" style="color: #ff4040; margin-right: 10px;"></span>'+lan.index.panel_port_tips+'<span class="c7 mr5" title="'+lan.index.panel_port_tip1+'" style="cursor:no-drop"> ['+lan.index.panel_port_tip2+']</span><a class="btlink" href="/config"> ['+lan.index.panel_port_tip3+']</a></p>')
|
||||
}
|
||||
var _system = info.system;
|
||||
$("#info").html(_system);
|
||||
$("#running").html(info.time);
|
||||
if (_system.indexOf("Windows") != -1) {
|
||||
$(".ico-system").addClass("ico-windows");
|
||||
}
|
||||
else if (_system.indexOf("CentOS") != -1) {
|
||||
$(".ico-system").addClass("ico-centos");
|
||||
}
|
||||
else if (_system.indexOf("Ubuntu") != -1) {
|
||||
$(".ico-system").addClass("ico-ubuntu");
|
||||
}
|
||||
else if (_system.indexOf("Debian") != -1) {
|
||||
$(".ico-system").addClass("ico-debian");
|
||||
}
|
||||
else if (_system.indexOf("Fedora") != -1) {
|
||||
$(".ico-system").addClass("ico-fedora");
|
||||
}
|
||||
else {
|
||||
$(".ico-system").addClass("ico-linux");
|
||||
}
|
||||
})
|
||||
},
|
||||
get_disk_list: function () {
|
||||
bt.system.get_disk_list(function (rdata) {
|
||||
if (rdata) {
|
||||
var data = { table: '#systemInfoList', items: [] };
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
var item = rdata[i];
|
||||
var obj = {};
|
||||
obj.name = item.path;
|
||||
obj.title = item.size[1] + '/' + item.size[0];
|
||||
obj.rate = item.size[3].replace('%', '');
|
||||
obj.free = item.size[2];
|
||||
var arr = [];
|
||||
arr.push({ title: lan.index.inode_info, value: '' })
|
||||
arr.push({ title: lan.index.total, value: item.inodes[0] })
|
||||
arr.push({ title: lan.index.already_use, value: item.inodes[1] })
|
||||
arr.push({ title: lan.index.available, value: item.inodes[2] })
|
||||
arr.push({ title: lan.index.inode_percent, value: item.inodes[3] })
|
||||
arr.push({ title: '<b>Capacity information</b>', value: '' })
|
||||
arr.push({ title: 'Capacity', value: item.size[0] })
|
||||
arr.push({ title: 'Used', value: item.size[1] })
|
||||
arr.push({ title: 'Available', value: item.size[2] })
|
||||
arr.push({ title: 'Usage rate', value: item.size[3] })
|
||||
obj.masks = arr;
|
||||
data.items.push(obj)
|
||||
}
|
||||
index.render_disk(data);
|
||||
}
|
||||
})
|
||||
if (info.isport === true) {
|
||||
$("#messageError").show();
|
||||
$("#messageError").append('<p><span class="glyphicon glyphicon-alert" style="color: #ff4040; margin-right: 10px;"></span>'+lan.index.panel_port_tips+'<span class="c7 mr5" title="'+lan.index.panel_port_tip1+'" style="cursor:no-drop"> ['+lan.index.panel_port_tip2+']</span><a class="btlink" href="/config"> ['+lan.index.panel_port_tip3+']</a></p>')
|
||||
}
|
||||
var _system = info.system;
|
||||
$("#info").html(_system);
|
||||
$("#running").html(info.time);
|
||||
if (_system.indexOf("Windows") != -1) {
|
||||
$(".ico-system").addClass("ico-windows");
|
||||
}
|
||||
else if (_system.indexOf("CentOS") != -1) {
|
||||
$(".ico-system").addClass("ico-centos");
|
||||
}
|
||||
else if (_system.indexOf("Ubuntu") != -1) {
|
||||
$(".ico-system").addClass("ico-ubuntu");
|
||||
}
|
||||
else if (_system.indexOf("Debian") != -1) {
|
||||
$(".ico-system").addClass("ico-debian");
|
||||
}
|
||||
else if (_system.indexOf("Fedora") != -1) {
|
||||
$(".ico-system").addClass("ico-fedora");
|
||||
}
|
||||
else {
|
||||
$(".ico-system").addClass("ico-linux");
|
||||
}
|
||||
},
|
||||
render_disk: function (data) {
|
||||
if (data.items.length > 0) {
|
||||
@@ -391,7 +432,7 @@ var index = {
|
||||
color = '#dd2f00'
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
index.set_val(_li, { usage: item.rate, color: color })
|
||||
_tab.append(_li);
|
||||
}
|
||||
@@ -430,6 +471,252 @@ var index = {
|
||||
if (obj.title) _li.find('h4').text(obj.title);
|
||||
_li.find('.occupy span').html(obj.usage);
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 渲染系统信息
|
||||
* @param callback 回调函数
|
||||
*
|
||||
*/
|
||||
reander_system_info:function(callback){
|
||||
var _this = this;
|
||||
bt.system.get_net(function (res){
|
||||
_this.chart_result = res
|
||||
// 动态添加磁盘,并赋值disk_view
|
||||
if(_this.chart_view.disk == undefined){
|
||||
for (var i = 0; i < res.disk.length; i++) {
|
||||
var diskHtml = "<li class='rank col-xs-6 col-sm-3 col-md-3 col-lg-2 mtb20 circle-box text-center'><div id='diskName" + i +"'></div><div class='chart-li' id='diskChart" + i +"'></div><div id='disk" + i +"'></div></li>";
|
||||
$("#systemInfoList").append(diskHtml);
|
||||
_this.disk_view.push(echarts.init(document.querySelector("#diskChart" + i)));
|
||||
}
|
||||
}
|
||||
|
||||
// 负载
|
||||
var loadCount = Math.round((res.load.one / res.load.max) * 100) > 100 ? 100 : Math.round((res.load.one / res.load.max) * 100);
|
||||
loadCount = loadCount < 0 ? 0 : loadCount;
|
||||
var loadInfo = _this.chart_color_active(loadCount);
|
||||
|
||||
// cpu
|
||||
var cpuCount = res.cpu[0];
|
||||
var cpuInfo = _this.chart_color_active(cpuCount);
|
||||
|
||||
// 内存
|
||||
var memCount = Math.round((res.mem.memRealUsed / res.mem.memTotal) * 1000) / 10; // 返回 memRealUsed 占 memTotal 的百分比
|
||||
var memInfo = _this.chart_color_active(memCount);
|
||||
bt.set_cookie('memSize',res.mem.memTotal)
|
||||
|
||||
// 磁盘
|
||||
var diskList = res.disk;
|
||||
var diskJson = [];
|
||||
for (var i = 0; i < diskList.length; i++) {
|
||||
|
||||
var ratio = diskList[i].size[3];
|
||||
ratio = parseFloat(ratio.substring(0, ratio.lastIndexOf("%")));
|
||||
var diskInfo = _this.chart_color_active(ratio)
|
||||
diskJson.push(diskInfo)
|
||||
|
||||
}
|
||||
|
||||
// chart_json存储最新数据
|
||||
_this.chart_json['load'] = loadInfo;
|
||||
_this.chart_json['cpu'] = cpuInfo;
|
||||
_this.chart_json['mem'] = memInfo;
|
||||
_this.chart_json['disk'] = diskJson
|
||||
// 初始化 || 刷新
|
||||
if(_this.chart_view.disk == undefined) {
|
||||
_this.init_chart_view()
|
||||
} else {
|
||||
_this.set_chart_data()
|
||||
}
|
||||
$('.rank .titles').show()
|
||||
|
||||
var net_key = bt.get_cookie('network_io_key');
|
||||
if(net_key){
|
||||
res.up = res.network[net_key].up;
|
||||
res.down = res.network[net_key].down;
|
||||
res.downTotal = res.network[net_key].downTotal;
|
||||
res.upTotal = res.network[net_key].upTotal;
|
||||
res.downPackets = res.network[net_key].downPackets;
|
||||
res.upPackets = res.network[net_key].upPackets;
|
||||
res.downAll = res.network[net_key].downTotal;
|
||||
res.upAll = res.network[net_key].upTotal;
|
||||
}
|
||||
var net_option = '<option value="all">All</option>';
|
||||
$.each(res.network,function(k,v){
|
||||
var act = (k == net_key)?'selected':'';
|
||||
net_option += '<option value="'+k+'" '+act+'>'+k+'</option>';
|
||||
});
|
||||
|
||||
$('select[name="network-io"]').html(net_option);
|
||||
//刷新流量
|
||||
$("#upSpeed").html(res.up.toFixed(2) + ' KB');
|
||||
$("#downSpeed").html(res.down.toFixed(2) + ' KB');
|
||||
$("#downAll").html(bt.format_size(res.downTotal));
|
||||
$("#upAll").html(bt.format_size(res.upTotal));
|
||||
index.net.add(res.up, res.down);
|
||||
var disk_key = bt.get_cookie('disk_io_key') || 'ALL', disk_io_data = res.iostat[disk_key || 'ALL'],mb = 1048576,ioTime = disk_io_data.write_time>disk_io_data.read_time?disk_io_data.write_time:disk_io_data.read_time
|
||||
$('#readBytes').html(bt.format_size(disk_io_data.read_bytes))
|
||||
$('#writeBytes').html(bt.format_size(disk_io_data.write_bytes))
|
||||
$('#diskIops').html((disk_io_data.read_count + disk_io_data.write_count))
|
||||
$('#diskTime').html(ioTime +' ms').css({'color':ioTime > 100 && ioTime < 1000?'#ff9900':ioTime >= 1000?'red':'#20a53a'})
|
||||
|
||||
index.iostat.add((disk_io_data.read_bytes / mb).toFixed(2), (disk_io_data.write_bytes / mb).toFixed(2),disk_io_data);
|
||||
|
||||
|
||||
var disk_option = '';
|
||||
$.each(res.iostat,function(k,v){
|
||||
disk_option += '<option value="'+k+'" '+ (k == disk_key?'selected':'') +'>'+ (k == 'ALL'?'All':k) +'</option>';
|
||||
});
|
||||
$('select[name="disk-io"]').html(disk_option);
|
||||
|
||||
if (index.net.table) index.net.table.setOption({ xAxis: { data: index.net.data.aData }, series: [{ name: lan.index.net_up, data: index.net.data.uData }, { name: lan.index.net_down, data: index.net.data.dData }] });
|
||||
if (index.iostat.table) index.iostat.table.setOption({ xAxis: { data: index.iostat.data.aData }, series: [{ name: 'Read Bytes', data: index.iostat.data.uData }, { name: 'Write Bytes', data: index.iostat.data.dData }] });
|
||||
if(callback) callback(res)
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @description 渲染画布视图
|
||||
*/
|
||||
init_chart_view:function(){
|
||||
// 所有图表对象装进chart_view
|
||||
this.chart_view['load'] = echarts.init(document.querySelector("#loadChart"))
|
||||
this.chart_view['cpu'] = echarts.init(document.querySelector("#cpuChart"))
|
||||
this.chart_view['mem'] = echarts.init(document.querySelector("#memChart"))
|
||||
this.chart_view['disk'] = this.disk_view
|
||||
|
||||
// 图表配置项
|
||||
this.series_option = {
|
||||
series: [{
|
||||
type: 'gauge',
|
||||
startAngle: 90,
|
||||
endAngle: -270,
|
||||
animationDuration: 1500,
|
||||
animationDurationUpdate: 1000,
|
||||
radius: '99%',
|
||||
pointer: {
|
||||
show: false
|
||||
},
|
||||
progress: {
|
||||
show: true,
|
||||
overlap: false,
|
||||
roundCap: true,
|
||||
clip: false,
|
||||
itemStyle: {
|
||||
borderWidth: 1,
|
||||
borderColor: '#20a53a'
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 7,
|
||||
color: [[0, "rgba(204,204,204,0.5)"], [1, "rgba(204,204,204,0.5)"]]
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
distance: 0,
|
||||
length: 10
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
distance: 50
|
||||
},
|
||||
data: [{
|
||||
value: 0,
|
||||
detail: {
|
||||
offsetCenter: ['0%', '0%']
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#20a53a',
|
||||
borderColor: '#20a53a'
|
||||
},
|
||||
}],
|
||||
detail: {
|
||||
width: 50,
|
||||
height: 15,
|
||||
lineHeight:15,
|
||||
fontSize: 17,
|
||||
color: '#20a53a',
|
||||
formatter: '{value}%',
|
||||
fontWeight:'normal'
|
||||
}
|
||||
}]
|
||||
};
|
||||
this.set_chart_data()
|
||||
},
|
||||
/**
|
||||
* @description 赋值chart的数据
|
||||
*
|
||||
*/
|
||||
set_chart_data:function(){
|
||||
this.chart_active("load")
|
||||
this.chart_active("cpu")
|
||||
if(!this.release){
|
||||
this.chart_active("mem")
|
||||
}
|
||||
for(var i = 0; i < this.chart_view.disk.length; i++){
|
||||
this.series_option.series[0].data[0].value = this.chart_json.disk[i].val
|
||||
this.series_option.series[0].data[0].itemStyle.color = this.chart_json.disk[i].color
|
||||
this.series_option.series[0].data[0].itemStyle.borderColor = this.chart_json.disk[i].color
|
||||
this.series_option.series[0].progress.itemStyle.borderColor = this.chart_json.disk[i].color
|
||||
this.series_option.series[0].detail.color = this.chart_json.disk[i].color
|
||||
this.chart_view.disk[i].setOption(this.series_option, true)
|
||||
$("#disk" + i).text(this.chart_result.disk[i].size[1] + " / " + this.chart_result.disk[i].size[0])
|
||||
$("#diskName" + i).text(this.chart_result.disk[i].path)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description 赋值chart的数据
|
||||
*
|
||||
*/
|
||||
chart_active:function(name){
|
||||
// 图表数据
|
||||
this.series_option.series[0].data[0].value = this.chart_json[name].val
|
||||
this.series_option.series[0].data[0].itemStyle.color = this.chart_json[name].color
|
||||
this.series_option.series[0].data[0].itemStyle.borderColor = this.chart_json[name].color
|
||||
this.series_option.series[0].progress.itemStyle.borderColor = this.chart_json[name].color
|
||||
this.series_option.series[0].detail.color = this.chart_json[name].color
|
||||
|
||||
this.chart_view[name].setOption(this.series_option, true)
|
||||
|
||||
// 文字
|
||||
var val = ""
|
||||
switch (name) {
|
||||
case 'load':
|
||||
val = this.chart_json[name].title
|
||||
break;
|
||||
case 'cpu':
|
||||
val = this.chart_result.cpu[1] + ' '+lan.index.cpu_core
|
||||
break;
|
||||
case 'mem':
|
||||
val = this.chart_result.mem.memRealUsed + " / " + this.chart_result.mem.memTotal + "(MB)"
|
||||
break;
|
||||
}
|
||||
|
||||
$("#" + name).text(val)
|
||||
},
|
||||
/**
|
||||
* @description 赋值chart的颜色
|
||||
*
|
||||
*/
|
||||
chart_color_active:function(number){
|
||||
var activeInfo = {};
|
||||
for (var i = 0; i < this.load_config.length; i++) {
|
||||
if (number >= this.load_config[i].val) {
|
||||
activeInfo = JSON.parse(JSON.stringify(this.load_config[i]));
|
||||
break;
|
||||
} else if (number <= 30) {
|
||||
activeInfo = JSON.parse(JSON.stringify(this.load_config[3]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
activeInfo.val = number;
|
||||
return activeInfo;
|
||||
},
|
||||
|
||||
|
||||
get_index_list: function () {
|
||||
bt.soft.get_index_list(function (rdata) {
|
||||
var con = '';
|
||||
|
||||
@@ -772,7 +772,7 @@ var aceEditor = {
|
||||
$('.ace_dir_tools').on('click','.upper_level',function(){
|
||||
var _paths = $(this).attr('data-menu-path');
|
||||
_this.reader_file_dir_menu({path:_paths,is_empty:true});
|
||||
$('.ace_catalogue_title').html('Directory: '+ _paths).attr('title',_paths);
|
||||
$('.ace_catalogue_title').html('Dir: '+ _paths).attr('title',_paths);
|
||||
});
|
||||
// 新建文件(文件目录主菜单)
|
||||
$('.ace_dir_tools').on('click','.new_folder',function(e){
|
||||
@@ -2031,6 +2031,9 @@ function openEditorView(type, path) {
|
||||
ace.config.set("workerPath", "/static/ace");
|
||||
ace.config.set("themePath", "/static/ace");
|
||||
aceEditor.openEditorView(path);
|
||||
var _left = parseInt( $(layero).css('left')),_top = parseInt( $(layero).css('top'));
|
||||
_left<0?$(layero).css('left',Math.abs(_left)):$(layero).css('left',_left)
|
||||
_top<0?$(layero).css('top',Math.abs(_top)):$(layero).css('top',_top)
|
||||
// $('.aceEditors .layui-layer-min').click(function(e) {
|
||||
// aceEditor.isAceView = false;
|
||||
// setTimeout(function() {
|
||||
@@ -2356,7 +2359,7 @@ function ChangePath(d) {
|
||||
setCookie("SetName", "");
|
||||
var c = layer.open({
|
||||
type: 1,
|
||||
area: "650px",
|
||||
area: "680px",
|
||||
title: lan.bt.dir,
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
@@ -3986,7 +3989,8 @@ var Term = {
|
||||
Term.send(JSON.stringify(Term.ssh_info || {}))
|
||||
// Term.term.FitAddon.fit();
|
||||
// Term.resize();
|
||||
var f_path = $("#fileInputPath").val();
|
||||
// var f_path = $("#fileInputPath").val();
|
||||
var f_path = $("#fileInputPath").attr('data-path');
|
||||
if(f_path){
|
||||
Term.last_cd = "cd " + f_path;
|
||||
Term.send(Term.last_cd + "\n");
|
||||
|
||||
+482
-323
File diff suppressed because it is too large
Load Diff
+295
-65
@@ -61,20 +61,20 @@ var site_table = bt_tools.table({
|
||||
var item = _ssl[_arry[i][0]];
|
||||
_info += _arry[i][1]+':'+ item + (_arry.length-1 != i?'\n':'');
|
||||
}
|
||||
return row.ssl === -1?'<a class="btlink" href="javascript:;" style="color:orange;">Not Set</a>':'<a class="btlink" href="javascript:;" title="'+ _info +'">Expire: '+ row.ssl.endtime +'days</a>';
|
||||
return _ssl === -1?'<a class="btlink" href="javascript:;" style="color:orange;">Not Set</a>': (_ssl.endtime >= 0? '<a class="btlink" href="javascript:;" title="'+ _info +'">Expire: '+ _ssl.endtime +'days</a>':'<a style="color:red" href="javascript:;">Expired</a>');
|
||||
},event:function(row,index,ev,key,that){
|
||||
site.web_edit(row);
|
||||
setTimeout(function(){
|
||||
$('.site-menu p:eq(8)').click();
|
||||
},500);
|
||||
}},
|
||||
{title:lan.site.operate,type:'group',width:95,align:'right',group:[
|
||||
// {
|
||||
// title:'防火墙',
|
||||
// event:function(row,index,ev,key,that){
|
||||
// site.site_waf(row.name);
|
||||
// }
|
||||
// },
|
||||
{title:lan.site.operate,type:'group',width:118,align:'right',group:[
|
||||
{
|
||||
title:'WAF',
|
||||
event:function(row,index,ev,key,that){
|
||||
site.site_waf(row.name);
|
||||
}
|
||||
},
|
||||
{
|
||||
title:lan.site.set,
|
||||
event:function(row,index,ev,key,that){
|
||||
@@ -1822,6 +1822,151 @@ var site = {
|
||||
}
|
||||
},
|
||||
edit: {
|
||||
update_composer: function () {
|
||||
loadT = bt.load()
|
||||
$.post('/files?action=update_composer', {
|
||||
repo: $("select[name='repo']").val()
|
||||
}, function (v_data) {
|
||||
loadT.close();
|
||||
bt.msg(v_data);
|
||||
});
|
||||
},
|
||||
show_composer_log: function () {
|
||||
$.post('/ajax?action=get_lines', {
|
||||
filename: '/tmp/composer.log',
|
||||
num: 30
|
||||
}, function (v_body) {
|
||||
var log_obj = $("#composer-log")
|
||||
if (log_obj.length < 1) return;
|
||||
log_obj.html(v_body.msg);
|
||||
var div = document.getElementById('composer-log')
|
||||
div.scrollTop = div.scrollHeight;
|
||||
if (v_body.msg.indexOf('BT-Exec-Completed') != -1) {
|
||||
//layer.close(site.edit.comp_showlog);
|
||||
layer.msg('Execution complete', {
|
||||
icon: 1
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
site.edit.show_composer_log()
|
||||
}, 1000)
|
||||
});
|
||||
},
|
||||
comp_confirm: 0,
|
||||
comp_showlog: 0,
|
||||
exec_composer: function () {
|
||||
site.edit.comp_confirm = layer.confirm('The impact of Composer execution depends on the composer.json configuration file in this directory. Continue?', {
|
||||
title: 'Execute composer',
|
||||
closeBtn: 2,
|
||||
icon: 3
|
||||
}, function (index) {
|
||||
layer.close(site.edit.comp_confirm);
|
||||
var pdata = {
|
||||
php_version: $("select[name='php_version']").val(),
|
||||
composer_args: $("select[name='composer_args']").val(),
|
||||
repo: $("select[name='repo']").val(),
|
||||
path: $("input[name='composer_path']").val(),
|
||||
user: $("select[name='composer_user']").val()
|
||||
}
|
||||
$.post('/files?action=exec_composer', pdata, function (rdatas) {
|
||||
if (!rdatas.status) {
|
||||
layer.msg(rdatas.msg, {
|
||||
icon: 2
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (rdatas.status === true) {
|
||||
site.edit.comp_showlog = layer.open({
|
||||
area: "800px",
|
||||
type: 1,
|
||||
shift: 5,
|
||||
closeBtn: 2,
|
||||
title: 'Execute Composer in the ['+ pdata['path'] +'] directory. After execution, please close this window after confirming that there is no problem',
|
||||
content: "<pre id='composer-log' style='height: 300px;background-color: #333;color: #fff;margin: 0 0 0;'></pre>"
|
||||
});
|
||||
setTimeout(function () {
|
||||
site.edit.show_composer_log();
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
remove_composer_lock: function (path) {
|
||||
$.post('/files?action=DeleteFile', {
|
||||
path: path + '/composer.lock'
|
||||
}, function (rdata) {
|
||||
bt.msg(rdata);
|
||||
$(".composer-msg").remove();
|
||||
$(".composer-rm").remove();
|
||||
})
|
||||
},
|
||||
set_composer: function (web) {
|
||||
$.post('/files?action=get_composer_version', {
|
||||
path: web.path
|
||||
}, function (v_data) {
|
||||
if (v_data.status === false) {
|
||||
bt.msg(v_data);
|
||||
return;
|
||||
}
|
||||
|
||||
var php_versions = '';
|
||||
for (var i = 0; i < v_data.php_versions.length; i++) {
|
||||
if (v_data.php_versions[i].version == '00') continue;
|
||||
php_versions += '<option value="' + v_data.php_versions[i].version + '">' + v_data.php_versions[i].name + '</option>';
|
||||
}
|
||||
|
||||
var msg = '';
|
||||
if (v_data.comp_lock) {
|
||||
msg += '<span>' + v_data.comp_lock + ' <a class="btlink composer-rm" onclick="site.edit.remove_composer_lock(\'' + web.path + '\')">[Delete]</a></span>'
|
||||
}
|
||||
if (v_data.comp_json !== true) {
|
||||
msg += '<span>' + v_data.comp_json + '</span>'
|
||||
}
|
||||
|
||||
var com_body = '<from class="bt-form" style="padding:10px 0px 0px 0px;;display:inline-block;width:580px">' +
|
||||
'<div class="line"><span style="width: 105px;" class="tname">Version</span><div class="info-r"><input readonly="readonly" style="background-color: #eee;width:180px;" name="composer_version" class="bt-input-text" value="' + v_data.msg + '" /><button onclick="site.edit.update_composer();" style="margin-left: 5px;" class="btn btn-default btn-sm">Update</button></div></div>' +
|
||||
'<div class="line"><span style="width: 105px;" class="tname">PHP</span><div class="info-r">' +
|
||||
'<select class="bt-input-text" name="php_version" style="width:180px;">' +
|
||||
'<option value="auto">Auto</option>' +
|
||||
php_versions +
|
||||
'</select>' +
|
||||
'</div></div>' +
|
||||
'<div class="line"><span style="width: 105px;" class="tname">Parameters</span><div class="info-r">' +
|
||||
'<select class="bt-input-text" name="composer_args" style="width:180px;">' +
|
||||
'<option value="install">Install</option>' +
|
||||
'<option value="update">Update</option>' +
|
||||
'</select>' +
|
||||
'</div></div>' +
|
||||
'<div class="line"><span style="width: 105px;" class="tname">Source</span><div class="info-r">' +
|
||||
'<select class="bt-input-text" name="repo" style="width:180px;">' +
|
||||
'<option value="repos.packagist">Official(packagist.org)</option>' +
|
||||
'</select>' +
|
||||
'</div></div>' +
|
||||
'<div class="line"><span style="width: 105px;" class="tname">User</span><div class="info-r">' +
|
||||
'<select class="bt-input-text" name="composer_user" style="width:180px;">' +
|
||||
'<option value="www">www(recommend)</option>' +
|
||||
'<option value="root">root(not suggested)</option>' +
|
||||
'</select>' +
|
||||
'</div></div>' +
|
||||
'<div class="line"><span style="width: 105px;" class="tname">Dir</span><div class="info-r">' +
|
||||
'<input style="width:275px;" class="bt-input-text" id="composer_path" name="composer_path" type="text" value="' + web.path + '" /><span class="glyphicon glyphicon-folder-open cursor ml5" onclick="bt.select_path(\'composer_path\')"></span>' +
|
||||
'</div></div>' +
|
||||
'<div class="line"><span style="width: 105px;height: 25px;" class="tname"> </span><span class="composer-msg" style="color:red;">' + msg + '</span></div>' +
|
||||
'<div class="line" style="clear:both"><span style="width: 105px;" class="tname"> </span><div class="info-r"><button class="btn btn-success btn-sm" onclick="site.edit.exec_composer()">Execute</button></div></div>' +
|
||||
'</from>' +
|
||||
'<ul class="help-info-text c7">' +
|
||||
'<li>Directory:Website root dir by default, please make sure that the dir contains composer.json</li>' +
|
||||
'<li>User:The default user www, unless your website is run with root privileges, it is not recommended to use the root user to execute composer</li>' +
|
||||
'<li>Source:source of composer</li>' +
|
||||
'<li>Parameters:Install (install dependent package), Update (upgrade dependent package), please select as needed</li>' +
|
||||
'<li>PHP version:The PHP version used to execute composer, it is recommended to try the default, if the installation fails, try to choose another PHP version</li>' +
|
||||
'<li>Composer version:Composer version, you can click [Upgrade Composer] on the right to upgrade Composer to the latest stable version</li>' +
|
||||
'</ul>'
|
||||
$("#webedit-con").html(com_body);
|
||||
});
|
||||
},
|
||||
set_domains: function(web) {
|
||||
var _this = this;
|
||||
var list = [{
|
||||
@@ -1873,7 +2018,7 @@ var site = {
|
||||
return '<a href="http://' + row.name + ':' + row.port + '" target="_blank" class="btlink">'+ row.name +'</a>';
|
||||
}},
|
||||
{fid:'port',title: lan.site.port,width:50,type:'text'},
|
||||
{title:'opt',width:80,type:'group',align:'right',group:[{
|
||||
{title:'OPT',width:80,type:'group',align:'right',group:[{
|
||||
title:'Del',
|
||||
template:function(row,that){
|
||||
return that.data.length === 1?'<span>Inoperable</span>':'Del';
|
||||
@@ -1948,7 +2093,7 @@ var site = {
|
||||
{fid:'port',title:lan.site.port,width:70,type:'text'},
|
||||
{fid:'path',title:lan.site.subdirectories,width:70,type:'text'},
|
||||
{title:'Opt',width:130,type:'group',align:'right',group:[{
|
||||
title:'URL rewirte',
|
||||
title:'URL rewrite',
|
||||
event:function(row,index,ev,key,that){
|
||||
bt.site.get_dir_rewrite({ id: row.id }, function (ret) {
|
||||
if (!ret.status) {
|
||||
@@ -2184,13 +2329,13 @@ var site = {
|
||||
},
|
||||
set_dirguard: function(web) {
|
||||
$('#webedit-con').html('<div id="set_dirguard"></div>');
|
||||
var tab = '<div class="tab-nav mlr20">\
|
||||
var tab = '<div class="tab-nav mb15">\
|
||||
<span class="on">Limit access</span><span class="">Deny access</span>\
|
||||
</div>\
|
||||
<div id="dir_dirguard" class="pd20"></div>\
|
||||
<div id="php_dirguard" class="pd20" style="display:none;"></div>';
|
||||
<div id="dir_dirguard"></div>\
|
||||
<div id="php_dirguard" style="display:none;"></div>';
|
||||
$("#set_dirguard").html(tab);
|
||||
bt_tools.table({
|
||||
var dir_dirguard = bt_tools.table({
|
||||
el:'#dir_dirguard',
|
||||
url:'/site?action=get_dir_auth',
|
||||
param:{id:web.id},
|
||||
@@ -2223,57 +2368,135 @@ var site = {
|
||||
site.edit.template_Dir(web.id,true);
|
||||
}}]
|
||||
},{ // 批量操作
|
||||
type:'batch',
|
||||
positon:['left','bottom'],
|
||||
config:{
|
||||
title:' delete',
|
||||
url:'/site?action=delete_dir_auth_multiple',
|
||||
param:{site_id:web.id},
|
||||
paramId:'name',
|
||||
paramName:'names',
|
||||
theadName:'Name',
|
||||
confirmVerify:false //是否提示验证方式
|
||||
}
|
||||
type: 'batch',
|
||||
positon: ['left', 'bottom'],
|
||||
config: {
|
||||
title: " delete",
|
||||
url: '/site?action=delete_dir_auth',
|
||||
param: function (row) {
|
||||
console.log(row)
|
||||
return {
|
||||
id: web.id,
|
||||
name: row.name
|
||||
}
|
||||
},
|
||||
load: true,
|
||||
callback: function (that) { // 手动执行,data参数包含所有选中的站点
|
||||
bt.show_confirm('Delete limit access','Do you want to delete limit access ?',function(){
|
||||
that.start_batch({}, function (list) {
|
||||
var html = '';
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var item = list[i];
|
||||
html += '<tr><td>' + item.name + '</td><td><div style="float:right;"><span style="color:' + (item.request.status ? '#20a53a' : 'red') + '">' + item.request.msg + '</span></div></td></tr>';
|
||||
}
|
||||
dir_dirguard.$batch_success_table({
|
||||
title: 'Limit access',
|
||||
th: 'Limit access name',
|
||||
html: html
|
||||
});
|
||||
dir_dirguard.$refresh_table_list(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
bt_tools.table({
|
||||
el:'#php_dirguard',
|
||||
url:'/config?action=get_file_deny',
|
||||
param:{website:web.name},
|
||||
dataFilter:function(res){
|
||||
return {data:res};
|
||||
var php_dirguard = bt_tools.table({
|
||||
el: '#php_dirguard',
|
||||
url: '/config?action=get_file_deny',
|
||||
param: {
|
||||
website: web.name
|
||||
},
|
||||
dataFilter: function (res) {
|
||||
return {
|
||||
data: res
|
||||
};
|
||||
},
|
||||
column: [
|
||||
{type:'checkbox',width:20},
|
||||
{
|
||||
fid: 'name',
|
||||
title: lan.site.name,
|
||||
type: 'text'
|
||||
},
|
||||
column:[
|
||||
//{type:'checkbox',width:20},
|
||||
{fid:'name',title:lan.site.name,type:'text'},
|
||||
{fid:'dir',title:'Path',type:'text', template:function(row){
|
||||
return '<span title="' + row.dir + '" style="max-width: 250px;" class="limit-text-length">' + row.dir + '</span>';
|
||||
}},
|
||||
{fid: 'suffix', title: 'Suffix', template:function(row){
|
||||
return '<span title="' + row.suffix + '" style="max-width: 85px;" class="limit-text-length">' + row.suffix + '</span>';
|
||||
}},
|
||||
{title:lan.site.operate,width:110,type:'group',align:'right',group:[{
|
||||
title:lan.site.edit,
|
||||
event:function(row,index,ev,key,that){
|
||||
site.edit.template_php(web.name,row);
|
||||
{
|
||||
fid: 'dir',
|
||||
title: 'Path',
|
||||
type: 'text',
|
||||
template: function (row) {
|
||||
return '<span title="' + row.dir + '" style="max-width: 250px;" class="limit-text-length">' + row.dir + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
fid: 'suffix',
|
||||
title: 'Suffix',
|
||||
template: function (row) {
|
||||
return '<span title="' + row.suffix + '" style="max-width: 85px;" class="limit-text-length">' + row.suffix + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.site.operate,
|
||||
width: 110,
|
||||
type: 'group',
|
||||
align: 'right',
|
||||
group: [{
|
||||
title: lan.site.edit,
|
||||
event: function (row, index, ev, key, that) {
|
||||
site.edit.template_php(web.name, row);
|
||||
}
|
||||
}, {
|
||||
title: lan.site.del,
|
||||
event: function (row, index, ev, key, that) {
|
||||
site.edit.del_php_deny(web.name, row.name, function (res) {
|
||||
if (res.status) that.$delete_table_row(index);
|
||||
bt.msg(res);
|
||||
});
|
||||
}
|
||||
}],
|
||||
}
|
||||
],
|
||||
tootls: [{ // 按钮组
|
||||
type: 'group',
|
||||
positon: ['left', 'top'],
|
||||
list: [{
|
||||
title: 'Add deny access',
|
||||
active: true,
|
||||
event: function (ev) {
|
||||
site.edit.template_php(web.name);
|
||||
}
|
||||
}]
|
||||
}, { // 批量操作
|
||||
type: 'batch',
|
||||
positon: ['left', 'bottom'],
|
||||
config: {
|
||||
title: " delete",
|
||||
url: '/site?action=del_file_deny',
|
||||
param: function (row) {
|
||||
return {
|
||||
website: web.name,
|
||||
deny_name: row.name
|
||||
}
|
||||
},
|
||||
load: true,
|
||||
callback: function (that) { // 手动执行,data参数包含所有选中的站点
|
||||
bt.show_confirm('Delete deny access', 'Do you want to delete deny access?', function () {
|
||||
that.start_batch({}, function (list) {
|
||||
var html = '';
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var item = list[i];
|
||||
html += '<tr><td>' + item.name + '</td><td><div style="float:right;"><span style="color:' + (item.request.status ? '#20a53a' : 'red') + '">' + item.request.msg + '</span></div></td></tr>';
|
||||
}
|
||||
},{
|
||||
title:lan.site.del,
|
||||
event:function(row,index,ev,key,that){
|
||||
site.edit.del_php_deny(web.name,row.name,function(res){
|
||||
if(res.status) that.$delete_table_row(index);
|
||||
bt.msg(res);
|
||||
});
|
||||
}
|
||||
}],
|
||||
}],
|
||||
tootls:[{ // 按钮组
|
||||
type:'group',
|
||||
positon:['left','top'],
|
||||
list:[{title:'Add deny access',active:true, event:function(ev){
|
||||
site.edit.template_php(web.name);
|
||||
}}]
|
||||
}]
|
||||
php_dirguard.$batch_success_table({
|
||||
title: 'Deny access',
|
||||
th: 'Deny access name',
|
||||
html: html
|
||||
});
|
||||
php_dirguard.$refresh_table_list(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
$('#dir_dirguard>.divtable,#php_dirguard>.divtable').css('max-height','340px');
|
||||
$('#dir_dirguard').append("<ul class='help-info-text c7'>\
|
||||
@@ -2282,7 +2505,7 @@ var site = {
|
||||
</ul>");
|
||||
$('#php_dirguard').append("<ul class='help-info-text c7'>\
|
||||
<li>Suffix: Indicates the suffix that is not allowed to access, if there are more than one, separate with'|'.</li>\
|
||||
<li>Path: Quote rules in this directory.</li>\
|
||||
<li>Path: Quote rules in this directory. e.g: /a/ </li>\
|
||||
<li>For Example, if you want to deny http://test.com/a/index.php</li>\
|
||||
<li>Please fill in [ /a/ ]</li>\
|
||||
</ul>");
|
||||
@@ -2883,12 +3106,18 @@ var site = {
|
||||
var helps = [];
|
||||
if (_val_obj.data !== false) {
|
||||
_form.title = lan.site.set + '【' + _val_obj.title + '】' + lan.site.interface;
|
||||
if(_val_obj.help == "How to get API Token"){
|
||||
_val_obj.help = '<a class="btlink" target="_blank" href="https://forum.aapanel.com/d/3375-3375-set-the-clouldflare-apt-token-for-dns-editing-permissions">'+_val_obj.help+"</a>"
|
||||
}
|
||||
helps.push(_val_obj.help);
|
||||
var is_hide = true;
|
||||
for (var i = 0; i < _val_obj.data.length; i++) {
|
||||
_form.list.push({ title: _val_obj.data[i].name, name: _val_obj.data[i].key, value: _val_obj.data[i].value })
|
||||
if (!_val_obj.data[i].value) is_hide = false;
|
||||
}
|
||||
if(_val_obj.title == 'CloudFlare'){
|
||||
_form.list.push({html : '<div class="line"><span class="tname">API-Limit</span><div class="info-r c4"><div class="index-item" style="padding-top:7px"><input class="btswitch btswitch-ios" name="API_Limit" id="API_Limit" type="checkbox" '+(_val_obj.API_Limit?"checked":null)+'><label class="btswitch-btn" for="API_Limit"></label></div></div></div>'});
|
||||
}
|
||||
_form.btns.push({
|
||||
title: lan.site.save,
|
||||
css: 'btn-success',
|
||||
@@ -3490,12 +3719,12 @@ var site = {
|
||||
"</div></div>" +
|
||||
"<div class='line'>" +
|
||||
"<span class='tname' style='width: 100px;'>Path</span>" +
|
||||
"<div class='info-r ml0' style='margin-left: 100px;'><input name='dir' placeholder='Quote rules in this directory' class='bt-input-text mr10' type='text' style='width:270px' value='" + obj.dir + "'>" +
|
||||
"<div class='info-r ml0' style='margin-left: 100px;'><input name='dir' placeholder='Quote rules in this directory. e.g: /a/' class='bt-input-text mr10' type='text' style='width:270px' value='" + obj.dir + "'>" +
|
||||
"</div></div></form>" +
|
||||
"<ul class='help-info-text c7 plr20'>" +
|
||||
"<li>Name:The rule name.</li>" +
|
||||
"<li>Suffix: Indicates the suffix that is not allowed to access, if there are more than one, separate with'|'</li>" +
|
||||
"<li>Path: Quote rules in this directory. </li>" +
|
||||
"<li>Path: Quote rules in this directory. e.g: /a/ </li>" +
|
||||
"<li>For Example, if you want to deny http://test.com/a/index.php</li>" +
|
||||
"<li>Please fill in [ /a/ ]" +
|
||||
"</ul>",
|
||||
@@ -4182,7 +4411,7 @@ var site = {
|
||||
var item = obj;
|
||||
bt.open({
|
||||
type: 1,
|
||||
area: ['757px', '683px'],
|
||||
area: ['780px', '683px'],
|
||||
title: lan.site.website_change + '[' + item.name + '] -- ' + lan.site.addtime + '[' + item.addtime + ']',
|
||||
closeBtn: 2,
|
||||
shift: 0,
|
||||
@@ -4201,6 +4430,7 @@ var site = {
|
||||
{ title: lan.site.site_menu_6, callback: site.edit.set_config },
|
||||
{ title: lan.site.site_menu_7, callback: site.edit.set_ssl },
|
||||
{ title: lan.site.php_ver, callback: site.edit.set_php_version },
|
||||
{ title: 'Composer', callback: site.edit.set_composer },
|
||||
// { title: lan.site.site_menu_9, callback: site.edit.set_tomact },
|
||||
// { title: lan.site.redirect, callback: site.edit.set_301_old },
|
||||
{ title: lan.site.redirect_test, callback: site.edit.set_301 },
|
||||
|
||||
+434
-363
@@ -1,5 +1,9 @@
|
||||
var soft = {
|
||||
is_install: false,
|
||||
trail:0,//是否试用
|
||||
is_setup:false,
|
||||
is_setup_name:"",
|
||||
refresh_data:[],
|
||||
get_list: function(page, type, search) {
|
||||
if (page == undefined || page == 'null' || page == 'undefined') page = 0;
|
||||
if (type == undefined || type == 'null' || type == 'undefined') type = 0;
|
||||
@@ -18,321 +22,326 @@ var soft = {
|
||||
}
|
||||
soft.is_install = false;
|
||||
bt.soft.get_soft_list(page, type, search, function(rdata) {
|
||||
soft.set_soft_tips('#updata_pro_info',type);
|
||||
// if (rdata.pro < 0) {
|
||||
// $("#updata_pro_info").html('');
|
||||
// } else if (rdata.pro === -2) {
|
||||
// $("#updata_pro_info").html('<div class="alert alert-success" style="margin-bottom:15px"><strong>' + lan.soft.pro_expire + '</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="' + lan.soft.renew_pro + '" style="margin-left:8px">' + lan.soft.renew_now + '</button>');
|
||||
// } else if (rdata.pro === -1) {
|
||||
// $("#updata_pro_info").html('<div class="alert alert-success" style="margin-bottom:15px"><strong > ' + lan.soft.upgrade_pro + '</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="' + lan.soft.upgrade_pro_now + '" style="margin-left:8px">' + lan.soft.upgrade_now + '</button>\</div>');
|
||||
// }
|
||||
_this.trail = rdata.trail
|
||||
// if (rdata.pro < 0) {
|
||||
// // $("#updata_pro_info").html('');
|
||||
// } else
|
||||
// if (rdata.pro === -2) {
|
||||
// $("#updata_pro_info").html('<div class="alert alert-success" style="margin-bottom:15px"><strong>' + lan.soft.pro_expire + '</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="' + lan.soft.renew_pro + '" style="margin-left:8px">' + lan.soft.renew_now + '</button>');
|
||||
// } else if (rdata.pro === -1) {
|
||||
// $("#updata_pro_info").html('<div class="alert alert-success" style="margin-bottom:15px"><strong > ' + lan.soft.upgrade_pro + '</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="' + lan.soft.upgrade_pro_now + '" style="margin-left:8px">' + lan.soft.upgrade_now + '</button>\</div>');
|
||||
// }
|
||||
soft.set_soft_tips('#updata_pro_info',type);
|
||||
|
||||
// if (type == 10) {
|
||||
// $("#updata_pro_info").html('<div class="alert alert-danger" style="margin-bottom:15px"><strong>' + lan.soft.bt_developer + '</strong><a class="btn btn-success btn-xs va0" href="https://www.aapanel.com" title="' + lan.soft.get_third_party_apps + '" style="margin-left: 8px" target="_blank">' + lan.soft.get_third_party_apps + '</a><input type="file" style="display:none;" accept=".zip,.tar.gz" id="update_zip" multiple="multiple"><button class="btn btn-success btn-xs" onclick="soft.update_zip_open()" style="margin-left:8px">' + lan.soft.import_plug + '</button></div>')
|
||||
// } else if (type == 11) {
|
||||
// $("#updata_pro_info").html('<div class="alert alert-info" style="margin-bottom:15px"><strong>' + lan.soft.comingsoon + '</strong></div>')
|
||||
// }
|
||||
var tBody = '';
|
||||
rdata.type.unshift({icon: 'icon',id: 0,ps: lan.soft.all,sort: 1,title: lan.soft.all}, {icon: 'icon',id: -1,ps: 'Installed',sort: 1,title: 'Installed'})
|
||||
for (var i = 0; i < rdata.type.length; i++) {
|
||||
var c = '';
|
||||
if (istype == rdata.type[i].id) {
|
||||
c = 'class="on"';
|
||||
}
|
||||
// 注释软件管理的付费插件,第三方插件,一键部署
|
||||
// if (rdata.type[i].id != "11" && rdata.type[i].id != "10" && rdata.type[i].id != "8") {
|
||||
if (rdata.type[i].id != "11") {
|
||||
tBody += '<span typeid="' + rdata.type[i].id + '" ' + c + '>' + rdata.type[i].title + '</span>';
|
||||
}
|
||||
}
|
||||
if (page) bt.set_cookie('p' + type, page);
|
||||
$(".softtype").html(tBody);
|
||||
$(".menu-sub span").click(function() {
|
||||
var _type = $(this).attr('typeid');
|
||||
bt.set_cookie('softType', _type);
|
||||
$(this).addClass("on").siblings().removeClass("on");
|
||||
if (_type !== '11') {
|
||||
soft.get_list(0, _type);
|
||||
} else {
|
||||
soft.get_dep_list(0);
|
||||
}
|
||||
// if (type == 10) {
|
||||
// $("#updata_pro_info").html('<div class="alert alert-danger" style="margin-bottom:15px"><strong>' + lan.soft.bt_developer + '</strong><a class="btn btn-success btn-xs va0" href="https://www.aapanel.com" title="' + lan.soft.get_third_party_apps + '" style="margin-left: 8px" target="_blank">' + lan.soft.get_third_party_apps + '</a><input type="file" style="display:none;" accept=".zip,.tar.gz" id="update_zip" multiple="multiple"><button class="btn btn-success btn-xs" onclick="soft.update_zip_open()" style="margin-left:8px">' + lan.soft.import_plug + '</button></div>')
|
||||
// } else if (type == 11) {
|
||||
// $("#updata_pro_info").html('<div class="alert alert-info" style="margin-bottom:15px"><strong>' + lan.soft.comingsoon + '</strong></div>')
|
||||
// }
|
||||
var tBody = '';
|
||||
rdata.type.unshift({icon: 'icon',id: 0,ps: lan.soft.all,sort: 1,title: lan.soft.all}, {icon: 'icon',id: -1,ps: 'Installed',sort: 1,title: 'Installed'})
|
||||
for (var i = 0; i < rdata.type.length; i++) {
|
||||
var c = '';
|
||||
if (istype == rdata.type[i].id) {
|
||||
c = 'class="on"';
|
||||
}
|
||||
// 注释软件管理的付费插件,第三方插件,一键部署
|
||||
// if (rdata.type[i].id != "11" && rdata.type[i].id != "10" && rdata.type[i].id != "8") {
|
||||
if (rdata.type[i].id != "11") {
|
||||
tBody += '<span typeid="' + rdata.type[i].id + '" ' + c + '>' + rdata.type[i].title + '</span>';
|
||||
}
|
||||
}
|
||||
if (page) bt.set_cookie('p' + type, page);
|
||||
$(".softtype").html(tBody);
|
||||
$(".menu-sub span").click(function() {
|
||||
var _type = $(this).attr('typeid');
|
||||
bt.set_cookie('softType', _type);
|
||||
$(this).addClass("on").siblings().removeClass("on");
|
||||
if (_type !== '11') {
|
||||
soft.get_list(0, _type);
|
||||
} else {
|
||||
soft.get_dep_list(0);
|
||||
}
|
||||
|
||||
})
|
||||
var data = rdata.list.data;
|
||||
$('#softPage').html(rdata.list.page);
|
||||
var phps = ['php-5.2', 'php-5.3', 'php-5.4'];
|
||||
var _tab = bt.render({
|
||||
})
|
||||
var data = rdata.list.data;
|
||||
$('#softPage').html(rdata.list.page);
|
||||
if(data.length>0){
|
||||
for(var i = 0; i < data.length; i++){
|
||||
if(data[i].task =='-1'){
|
||||
soft.is_setup = true;
|
||||
soft.is_setup_name = data[i].name;
|
||||
break;
|
||||
}else{
|
||||
soft.is_setup = false;
|
||||
soft.is_install = false;
|
||||
soft.is_setup_name = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
if(soft.is_setup==true&&soft.is_setup_name != ""){
|
||||
_this.soft_setup_find();
|
||||
}
|
||||
if(soft.refresh_data.length==0){
|
||||
_this.refresh_table(page, type, search, rdata);
|
||||
soft.refresh_data = data;
|
||||
}else
|
||||
if(JSON.stringify(data) !=JSON.stringify(soft.refresh_data)){
|
||||
_this.refresh_table(page, type, search, rdata);
|
||||
soft.refresh_data = data;
|
||||
}
|
||||
bt.set_cookie('load_page', (page+'').split('not_load')[0])
|
||||
bt.set_cookie('load_type', type)
|
||||
bt.set_cookie('load_search', search)
|
||||
if (soft.is_install&& soft.is_setup==false) {
|
||||
setTimeout(function () {
|
||||
soft.get_list(bt.get_cookie('load_page') + 'not_load', bt.get_cookie('load_type'), bt.get_cookie('load_search'));
|
||||
}, 3000);
|
||||
soft.is_install = false;
|
||||
}
|
||||
// if(rdata.recommend){
|
||||
// _this.render_promote_list(rdata.recommend);
|
||||
// }
|
||||
})
|
||||
},
|
||||
// 查找正在安装软件的状态
|
||||
soft_setup_find:function(){
|
||||
var _this = this;
|
||||
if(soft.is_setup==true&&soft.is_setup_name != ""){
|
||||
$.post("plugin?action=get_soft_find",{sName:soft.is_setup_name},function(rdata){
|
||||
if(rdata.task=="-1"){
|
||||
setTimeout(function () {
|
||||
_this.soft_setup_find();
|
||||
}, 3000);
|
||||
}else{
|
||||
soft.is_install=true;
|
||||
setTimeout(function () {
|
||||
soft.get_list(bt.get_cookie('load_page') + 'not_load', bt.get_cookie('load_type'), bt.get_cookie('load_search'));
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
// 刷新列表
|
||||
refresh_table:function(page, type, search, rdata){
|
||||
var _this = this;
|
||||
var phps = ['php-5.2', 'php-5.3', 'php-5.4'];
|
||||
var data = rdata.list.data;
|
||||
var _tab = bt.render({
|
||||
table: '#softList',
|
||||
columns: [{
|
||||
field: 'title',
|
||||
title: lan.soft.app_name,
|
||||
width: 165,
|
||||
templet: function(item) {
|
||||
var fName = item.name,
|
||||
version = item.version;
|
||||
if (bt.contains(item.name, 'php-')) {
|
||||
fName = 'php';
|
||||
version = '';
|
||||
}
|
||||
var click_opt = ' ',
|
||||
sStyle = '';
|
||||
if (item.setup) {
|
||||
sStyle = ' style="cursor:pointer"';
|
||||
if (item.admin) {
|
||||
if (item.endtime >= 0 || item.price == 0) {
|
||||
click_opt += 'onclick="bt.soft.set_lib_config(\'' + item.name + '\',\'' + item.title + '\')" ';
|
||||
}
|
||||
field: 'title',
|
||||
title: lan.soft.app_name,
|
||||
width: 165,
|
||||
templet: function(item) {
|
||||
var fName = item.name,
|
||||
version = item.version;
|
||||
if (bt.contains(item.name, 'php-')) {
|
||||
fName = 'php';
|
||||
version = '';
|
||||
}
|
||||
var click_opt = ' ',
|
||||
sStyle = '';
|
||||
if (item.setup) {
|
||||
sStyle = ' style="cursor:pointer"';
|
||||
if (item.admin) {
|
||||
if (item.endtime >= 0 || item.price == 0) {
|
||||
click_opt += 'onclick="bt.soft.set_lib_config(\'' + item.name + '\',\'' + item.title + '\')" ';
|
||||
}
|
||||
|
||||
} else {
|
||||
click_opt += ' onclick="soft.set_soft_config(\'' + item.name + '\')" ';
|
||||
}
|
||||
} else {
|
||||
click_opt += ' onclick="soft.set_soft_config(\'' + item.name + '\')" ';
|
||||
}
|
||||
var is_php5 = item.name.indexOf('php-5') >= 0,
|
||||
webcache = bt.get_cookie('serverType') == 'openlitespeed' ? true : false,
|
||||
distribution = bt.get_cookie('distribution');
|
||||
if (webcache) {
|
||||
switch (distribution) {
|
||||
case 'centos8':
|
||||
if (is_php5 || item.name == 'php-7.0') {
|
||||
click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
}
|
||||
break;
|
||||
case 'centos7':
|
||||
if (item.name == 'php-5.2') {
|
||||
click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (is_php5) {
|
||||
click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}else if (rdata.apache22 && item.name.indexOf('php-') >= 0 && $.inArray(item.name, phps) == -1){
|
||||
click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
}
|
||||
var is_php5 = item.name.indexOf('php-5') >= 0,
|
||||
webcache = bt.get_cookie('serverType') == 'openlitespeed' ? true : false,
|
||||
distribution = bt.get_cookie('distribution');
|
||||
if (webcache) {
|
||||
switch (distribution) {
|
||||
case 'centos8':
|
||||
if (is_php5 || item.name == 'php-7.0') {
|
||||
click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
}
|
||||
break;
|
||||
case 'centos7':
|
||||
if (item.name == 'php-5.2') {
|
||||
click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (is_php5) {
|
||||
click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
}
|
||||
break;
|
||||
}
|
||||
//if (rdata.apache22 && item.name.indexOf('php-') >= 0 && $.inArray(item.name, phps) == -1) click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
return '<span ' + click_opt + ' ' + sStyle + ' ><img src="/static/img/soft_ico/ico-' + fName + '.png">' + item.title + ' ' + version + '</span>';
|
||||
}else if (rdata.apache22 && item.name.indexOf('php-') >= 0 && $.inArray(item.name, phps) == -1){
|
||||
click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
title: 'Developer',
|
||||
width: 110,
|
||||
templet: function(item) {
|
||||
if (!item.author) return 'official'
|
||||
return item.author;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'ps',
|
||||
title: lan.soft.instructions,
|
||||
templet: function(item) {
|
||||
var ps = item.ps;
|
||||
var is_php = item.name.indexOf('php-') >= 0;
|
||||
//if (rdata.apache22 && item.name.indexOf('php-') >= 0 && $.inArray(item.name, phps) == -1) click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
|
||||
return '<span ' + click_opt + ' ' + sStyle + ' ><img src="/static/img/soft_ico/ico-' + fName + '.png">' + item.title + ' ' + version + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
title: 'Developer',
|
||||
width: 110,
|
||||
templet: function(item) {
|
||||
if (!item.author) return 'official'
|
||||
return item.author;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'ps',
|
||||
title: lan.soft.instructions,
|
||||
templet: function(item) {
|
||||
var ps = item.ps;
|
||||
var is_php = item.name.indexOf('php-') >= 0;
|
||||
|
||||
if (is_php && item.setup) {
|
||||
if (rdata.apache22 && $.inArray(item.name, phps) >= 0) {
|
||||
if (item.fpm) {
|
||||
ps += " <span style='color:red;'>(" + lan.soft.apache22 + ")</span>";
|
||||
}
|
||||
} else if (!rdata.apache22) {
|
||||
if (!item.fpm) {
|
||||
ps += " <span style='color:red;'>(" + lan.soft.apache24 + ")</span>";
|
||||
}
|
||||
if (is_php && item.setup) {
|
||||
if (rdata.apache22 && $.inArray(item.name, phps) >= 0) {
|
||||
if (item.fpm) {
|
||||
ps += " <span style='color:red;'>(" + lan.soft.apache22 + ")</span>";
|
||||
}
|
||||
} else if (!rdata.apache22) {
|
||||
if (!item.fpm) {
|
||||
ps += " <span style='color:red;'>(" + lan.soft.apache24 + ")</span>";
|
||||
}
|
||||
}
|
||||
return '<span>' + ps + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
title: lan.soft.price,
|
||||
width: 92,
|
||||
templet: function(item) {
|
||||
var price = lan.soft.free;
|
||||
if (item.price > 0) {
|
||||
price = '<span style="color:#fc6d26">$' + item.price + '</span>';
|
||||
}
|
||||
return price;
|
||||
return '<span>' + ps + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
title: lan.soft.price,
|
||||
width: 92,
|
||||
templet: function(item) {
|
||||
var price = lan.soft.free;
|
||||
if (item.price > 0) {
|
||||
price = '<span style="color:#fc6d26">$' + item.price + '</span>';
|
||||
}
|
||||
},
|
||||
(type == 10 ? {
|
||||
field: 'sort',
|
||||
width: 80,
|
||||
title: 'Rated',
|
||||
templet: function(item) {
|
||||
return item.sort !== undefined ? ('<a href="javascript:;" onclick="score.open_score_view(' + item.pid + ',\'' + item.title + '\',' + item.count + ')" class="btlink open_sort_view">' + (item.sort <= 0 || item.sort > 5 ? lan.soft.not_rated : item.sort.toFixed(1)) + '</a>') : '--';
|
||||
}
|
||||
} : ''),
|
||||
{
|
||||
field: 'endtime',
|
||||
width: 120,
|
||||
title: lan.soft.expire_time,
|
||||
templet: function(item) {
|
||||
var endtime = '--';
|
||||
if (item.pid > 0) {
|
||||
if (item.endtime > 0) {
|
||||
if (item.type != 10) {
|
||||
endtime = bt.format_data(item.endtime, 'yyyy/MM/dd') ;
|
||||
} else {
|
||||
endtime = bt.format_data(item.endtime, 'yyyy/MM/dd') ;
|
||||
}
|
||||
} else if (item.endtime === 0) {
|
||||
endtime = lan.soft.permanent;
|
||||
} else if (item.endtime === -1) {
|
||||
endtime = lan.soft.not_open;
|
||||
} else if (item.endtime === -2) {
|
||||
if (item.type != 10) {
|
||||
endtime = lan.soft.already_expire ;
|
||||
} else {
|
||||
endtime = lan.soft.already_expire ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return endtime;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'path',
|
||||
width: 40,
|
||||
title: lan.soft.location,
|
||||
templet: function(item) {
|
||||
var path = '';
|
||||
if (item.setup) {
|
||||
path = '<span class="glyphicon glyphicon-folder-open" onclick="openPath(\'' + item.uninsatll_checks + '\')"></span>';
|
||||
}
|
||||
return path;
|
||||
}
|
||||
},
|
||||
(type != 10 ? {
|
||||
field: 'status',
|
||||
width: 40,
|
||||
title: lan.soft.status1,
|
||||
templet: function(item) {
|
||||
var status = '';
|
||||
if (item.setup) {
|
||||
if (item.status) {
|
||||
status = '<span style="color:#20a53a" class="glyphicon glyphicon-play"></span>';
|
||||
} else {
|
||||
status = '<span style="color:red" class="glyphicon glyphicon-pause"></span>';
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
} : ''),
|
||||
{
|
||||
field: 'index',
|
||||
width: 100,
|
||||
title: lan.soft.display_at_homepage,
|
||||
templet: function(item) {
|
||||
var to_index = '';
|
||||
if (item.setup) {
|
||||
var checked = '';
|
||||
if (item.index_display) checked = 'checked';
|
||||
var item_id = item.name.replace(/\./, "");
|
||||
to_index = '<div class="index-item"><input class="btswitch btswitch-ios" id="index_' + item_id + '" type="checkbox" ' + checked + '><label class="btswitch-btn" for="index_' + item_id + '" onclick="bt.soft.to_index(\'' + item.name + '\')"></label></div>';
|
||||
}
|
||||
return to_index;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'opt',
|
||||
width: 190,
|
||||
title: lan.soft.operate,
|
||||
align: 'right',
|
||||
templet: function(item) {
|
||||
var option = '';
|
||||
|
||||
var pay_opt = '';
|
||||
if (item.endtime < 0 && item.pid > 0) {
|
||||
var re_msg = '';
|
||||
var re_status = 0;
|
||||
switch (item.endtime) {
|
||||
case -1:
|
||||
re_msg = lan.soft.buy_now;
|
||||
break;
|
||||
case -2:
|
||||
re_msg = lan.soft.renew_now;
|
||||
re_status = 1;
|
||||
break;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
},
|
||||
(type == 10 ? {
|
||||
field: 'sort',
|
||||
width: 80,
|
||||
title: 'Rated',
|
||||
templet: function(item) {
|
||||
return item.sort !== undefined ? ('<a href="javascript:;" onclick="score.open_score_view(' + item.pid + ',\'' + item.title + '\',' + item.count + ')" class="btlink open_sort_view">' + (item.sort <= 0 || item.sort > 5 ? lan.soft.not_rated : item.sort.toFixed(1)) + '</a>') : '--';
|
||||
}
|
||||
} : ''),
|
||||
{
|
||||
field: 'endtime',
|
||||
width: 120,
|
||||
title: lan.soft.expire_time,
|
||||
templet: function(item) {
|
||||
var endtime = '--';
|
||||
if (item.pid > 0) {
|
||||
if (item.endtime > 0) {
|
||||
if (item.type != 10) {
|
||||
pay_opt = '<a class="btlink" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,plugin:true,renew:item.endtime}) +')\'>' + re_msg + '</a>';
|
||||
endtime = bt.format_data(item.endtime, 'yyyy/MM/dd') ;
|
||||
} else {
|
||||
pay_opt = '<a class="btlink" onclick="bt.soft.re_plugin_pay_other(\'' + item.title + '\',\'' + item.pid + '\',' + re_status + ',' + item.price + ')">' + re_msg + '</a>';
|
||||
endtime = bt.format_data(item.endtime, 'yyyy/MM/dd') ;
|
||||
}
|
||||
} else if (item.endtime === 0) {
|
||||
endtime = lan.soft.permanent;
|
||||
} else if (item.endtime === -1) {
|
||||
endtime = lan.soft.not_open;
|
||||
} else if (item.endtime === -2) {
|
||||
if (item.type != 10) {
|
||||
endtime = lan.soft.already_expire ;
|
||||
} else {
|
||||
endtime = lan.soft.already_expire ;
|
||||
}
|
||||
|
||||
}
|
||||
var is_php = item.name.indexOf('php-') >= 0,
|
||||
is_php5 = item.name.indexOf('php-5') >= 0,
|
||||
webcache = bt.get_cookie('serverType') == 'openlitespeed' ? true : false,
|
||||
distribution = bt.get_cookie('distribution');
|
||||
if (webcache && is_php) {
|
||||
if ((is_php5 || item.name == 'php-7.0') && distribution=='centos8') {
|
||||
}
|
||||
return endtime;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'path',
|
||||
width: 40,
|
||||
title: lan.soft.location,
|
||||
templet: function(item) {
|
||||
var path = '';
|
||||
if (item.setup) {
|
||||
path = '<span class="glyphicon glyphicon-folder-open" onclick="openPath(\'' + item.uninsatll_checks + '\')"></span>';
|
||||
}
|
||||
return path;
|
||||
}
|
||||
},
|
||||
(type != 10 ? {
|
||||
field: 'status',
|
||||
width: 40,
|
||||
title: lan.soft.status1,
|
||||
templet: function(item) {
|
||||
var status = '';
|
||||
if (item.setup) {
|
||||
if (item.status) {
|
||||
status = '<span style="color:#20a53a" class="glyphicon glyphicon-play"></span>';
|
||||
} else {
|
||||
status = '<span style="color:red" class="glyphicon glyphicon-pause"></span>';
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
} : ''),
|
||||
{
|
||||
field: 'index',
|
||||
width: 100,
|
||||
title: lan.soft.display_at_homepage,
|
||||
templet: function(item) {
|
||||
var to_index = '';
|
||||
if (item.setup) {
|
||||
var checked = '';
|
||||
if (item.index_display) checked = 'checked';
|
||||
var item_id = item.name.replace(/\./, "");
|
||||
to_index = '<div class="index-item"><input class="btswitch btswitch-ios" id="index_' + item_id + '" type="checkbox" ' + checked + '><label class="btswitch-btn" for="index_' + item_id + '" onclick="bt.soft.to_index(\'' + item.name + '\')"></label></div>';
|
||||
}
|
||||
return to_index;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'opt',
|
||||
width: 190,
|
||||
title: lan.soft.operate,
|
||||
align: 'right',
|
||||
templet: function(item) {
|
||||
var option = '';
|
||||
|
||||
var pay_opt = '';
|
||||
if (item.endtime < 0 && item.pid > 0) {
|
||||
var re_msg = '';
|
||||
var re_status = 0;
|
||||
switch (item.endtime) {
|
||||
case -1:
|
||||
re_msg = lan.soft.buy_now;
|
||||
break;
|
||||
case -2:
|
||||
re_msg = lan.soft.renew_now;
|
||||
re_status = 1;
|
||||
break;
|
||||
}
|
||||
if (item.type != 10) {
|
||||
pay_opt = '<a class="btlink" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,plugin:true,renew:item.endtime}) +')\'>' + re_msg + '</a>';
|
||||
} else {
|
||||
pay_opt = '<a class="btlink" onclick="bt.soft.re_plugin_pay_other(\'' + item.title + '\',\'' + item.pid + '\',' + re_status + ',' + item.price + ')">' + re_msg + '</a>';
|
||||
}
|
||||
|
||||
}
|
||||
var is_php = item.name.indexOf('php-') >= 0,
|
||||
is_php5 = item.name.indexOf('php-5') >= 0,
|
||||
webcache = bt.get_cookie('serverType') == 'openlitespeed' ? true : false,
|
||||
distribution = bt.get_cookie('distribution');
|
||||
if (webcache && is_php) {
|
||||
if ((is_php5 || item.name == 'php-7.0') && distribution=='centos8') {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
}else if (distribution=='centos7'&&item.name == 'php-5.2') {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
}else{
|
||||
if (distribution!='centos7'&&is_php5) {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
}else if (distribution=='centos7'&&item.name == 'php-5.2') {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
}else{
|
||||
if (distribution!='centos7'&&is_php5) {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
} else {
|
||||
if (item.setup && item.task == '1') {
|
||||
if (pay_opt == '') {
|
||||
if (item.versions.length > 1) {
|
||||
for (var i = 0; i < item.versions.length; i++) {
|
||||
var min_version = item.versions[i]
|
||||
var ret = bt.check_version(item.version, min_version.m_version + '.' + min_version.version);
|
||||
if (ret > 0) {
|
||||
if (ret == 2) option += '<a class="btlink" onclick="bt.soft.update_soft(\'' + item.name + '\',\'' + item.title + '\',\'' + min_version.m_version + '\',\'' + min_version.version + '\',\'' + min_version.update_msg.replace(/\n/g, "_bt_") + '\')" >' + lan.soft.update + '</a> | ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var min_version = item.versions[0];
|
||||
var cloud_version = min_version.m_version + '.' + min_version.version;
|
||||
if (item.version != cloud_version) option += '<a class="btlink" onclick="bt.soft.update_soft(\'' + item.name + '\',\'' + item.title + '\',\'' + min_version.m_version + '\',\'' + min_version.version + '\',\'' + min_version.update_msg.replace(/\n/g, "_bt_") + '\')" >' + lan.soft.update + '</a> | ';
|
||||
}
|
||||
if (item.admin) {
|
||||
option += '<a class="btlink" onclick="bt.soft.set_lib_config(\'' + item.name + '\',\'' + item.title + '\')">' + lan.soft.setup + '</a> | ';
|
||||
} else {
|
||||
option += '<a class="btlink" onclick="soft.set_soft_config(\'' + item.name + '\')">' + lan.soft.setup + '</a> | ';
|
||||
}
|
||||
} else {
|
||||
option = pay_opt + ' | ' + option;
|
||||
}
|
||||
option += '<a class="btlink" onclick="bt.soft.un_install(\'' + item.name + '\')" >' + lan.soft.uninstall + '</a>';
|
||||
} else if (item.task == '-1') {
|
||||
option = '<a class="btlink" onclick="messagebox()" >' + lan.soft.installing + '</a>';
|
||||
soft.is_install = true;
|
||||
} else if (item.task == '0') {
|
||||
option = '<a class="btlink" onclick="messagebox()" >' + lan.soft.wait_install + '</a>';
|
||||
soft.is_install = true;
|
||||
} else if (item.task == '-2') {
|
||||
option = '<a class="btlink" onclick="messagebox()" >Updating</a>';
|
||||
soft.is_install = true;
|
||||
} else {
|
||||
if (pay_opt) {
|
||||
option = pay_opt;
|
||||
} else {
|
||||
option = '<a class="btlink" onclick="bt.soft.install(\'' + item.name + '\')" >' + lan.soft.install + '</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if (rdata.apache22 && is_php && $.inArray(item.name, phps) == -1) {
|
||||
if (item.setup) {
|
||||
option = '<a class="btlink" onclick="bt.soft.un_install(\'' + item.name + '\')" >' + lan.soft.uninstall + '</a>';
|
||||
} else {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
}
|
||||
} else if (rdata.apache24 && item.name == 'php-5.2') {
|
||||
if (item.setup) {
|
||||
option = '<a class="btlink" onclick="bt.soft.un_install(\'' + item.name + '\')" >' + lan.soft.uninstall + '</a>';
|
||||
} else {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
}
|
||||
} else {
|
||||
if (item.setup && item.task == '1') {
|
||||
if (pay_opt == '') {
|
||||
@@ -377,20 +386,68 @@ var soft = {
|
||||
}
|
||||
}
|
||||
}
|
||||
return option;
|
||||
}else {
|
||||
if (rdata.apache22 && is_php && $.inArray(item.name, phps) == -1) {
|
||||
if (item.setup) {
|
||||
option = '<a class="btlink" onclick="bt.soft.un_install(\'' + item.name + '\')" >' + lan.soft.uninstall + '</a>';
|
||||
} else {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
}
|
||||
} else if (rdata.apache24 && item.name == 'php-5.2') {
|
||||
if (item.setup) {
|
||||
option = '<a class="btlink" onclick="bt.soft.un_install(\'' + item.name + '\')" >' + lan.soft.uninstall + '</a>';
|
||||
} else {
|
||||
option = '<span title="\' + lan.soft.ap2_2_not_support + \'">' + lan.soft.not_comp + '</span>';
|
||||
}
|
||||
} else {
|
||||
if (item.setup && item.task == '1') {
|
||||
if (pay_opt == '') {
|
||||
if (item.versions.length > 1) {
|
||||
for (var i = 0; i < item.versions.length; i++) {
|
||||
var min_version = item.versions[i]
|
||||
var ret = bt.check_version(item.version, min_version.m_version + '.' + min_version.version);
|
||||
if (ret > 0) {
|
||||
if (ret == 2) option += '<a class="btlink" onclick="bt.soft.update_soft(\'' + item.name + '\',\'' + item.title + '\',\'' + min_version.m_version + '\',\'' + min_version.version + '\',\'' + min_version.update_msg.replace(/\n/g, "_bt_") + '\')" >' + lan.soft.update + '</a> | ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var min_version = item.versions[0];
|
||||
var cloud_version = min_version.m_version + '.' + min_version.version;
|
||||
if (item.version != cloud_version) option += '<a class="btlink" onclick="bt.soft.update_soft(\'' + item.name + '\',\'' + item.title + '\',\'' + min_version.m_version + '\',\'' + min_version.version + '\',\'' + min_version.update_msg.replace(/\n/g, "_bt_") + '\')" >' + lan.soft.update + '</a> | ';
|
||||
}
|
||||
if (item.admin) {
|
||||
option += '<a class="btlink" onclick="bt.soft.set_lib_config(\'' + item.name + '\',\'' + item.title + '\')">' + lan.soft.setup + '</a> | ';
|
||||
} else {
|
||||
option += '<a class="btlink" onclick="soft.set_soft_config(\'' + item.name + '\')">' + lan.soft.setup + '</a> | ';
|
||||
}
|
||||
} else {
|
||||
option = pay_opt + ' | ' + option;
|
||||
}
|
||||
option += '<a class="btlink" onclick="bt.soft.un_install(\'' + item.name + '\')" >' + lan.soft.uninstall + '</a>';
|
||||
} else if (item.task == '-1') {
|
||||
option = '<a class="btlink" onclick="messagebox()" >' + lan.soft.installing + '</a>';
|
||||
soft.is_install = true;
|
||||
} else if (item.task == '0') {
|
||||
option = '<a class="btlink" onclick="messagebox()" >' + lan.soft.wait_install + '</a>';
|
||||
soft.is_install = true;
|
||||
} else if (item.task == '-2') {
|
||||
option = '<a class="btlink" onclick="messagebox()" >Updating</a>';
|
||||
soft.is_install = true;
|
||||
} else {
|
||||
if (pay_opt) {
|
||||
option = pay_opt;
|
||||
} else {
|
||||
option = '<a class="btlink" onclick="bt.soft.install(\'' + item.name + '\')" >' + lan.soft.install + '</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return option;
|
||||
}
|
||||
],
|
||||
data: data
|
||||
})
|
||||
bt.set_cookie('load_page', (page + '').split('not_load')[0])
|
||||
bt.set_cookie('load_type', type)
|
||||
bt.set_cookie('load_search', search)
|
||||
if (soft.is_install) {
|
||||
setTimeout(function() {
|
||||
soft.get_list(bt.get_cookie('load_page') + 'not_load', bt.get_cookie('load_type'), bt.get_cookie('load_search'));
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
],
|
||||
data: data
|
||||
})
|
||||
},
|
||||
// 渲染列表
|
||||
@@ -441,9 +498,10 @@ var soft = {
|
||||
}else if(item.endtime > 0){ //已购买
|
||||
thtml = '<button type="button" class="btn btn-success btn-xs" onclick="bt.soft.set_lib_config(\''+ item.name +'\',\''+ item.title +'\')">Setting</button>';
|
||||
}else if(item.endtime == -1){ //未购买
|
||||
thtml = '<button type="button" class="btn btn-success btn-xs" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,pulgin:true,renew:item.endtime}) +');\'>Upgrade now</button>';
|
||||
}else if(item.endtime == -2){ //已过期
|
||||
thtml = '<button type="button" class="btn btn-success btn-xs" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,pulgin:true,renew:item.endtime}) +');\'>立即续费</button>';
|
||||
|
||||
thtml = '<button type="button" class="btn btn-success btn-xs" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,pulgin:true,renew:item.endtime}) +');\'>Upgrade now</button>';
|
||||
}else if(item.endtime == -2){ //已过期
|
||||
thtml = '<button type="button" class="btn btn-success btn-xs" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,pulgin:true,renew:item.endtime}) +');\'>立即续费</button>';
|
||||
}
|
||||
}else{
|
||||
thtml = '<button type="button" class="btn btn-success btn-xs" onclick="bt.soft.set_lib_config(\''+ item.name +'\',\''+ item.title +'\')">Setting</button>';
|
||||
@@ -470,11 +528,12 @@ var soft = {
|
||||
}
|
||||
},
|
||||
set_soft_tips:function(el,type){
|
||||
var tips_info = $('<div class="alert" style="margin-bottom:15px"><div class="soft_tips_text"></div><div class="btn-ground" style="display:inline-block;"></div></div>'), explain = tips_info.find('.soft_tips_text'), btn_ground = tips_info.find('.btn-ground');
|
||||
$(el).empty();
|
||||
var tips_info = $('<div class="alert" style="margin-bottom:15px"><div class="soft_tips_text"></div><div class="btn-ground" style="display:inline-block;"></div></div>'), explain = tips_info.find('.soft_tips_text'), btn_ground = tips_info.find('.btn-ground'),_this = this;
|
||||
$(el).empty()
|
||||
type = parseInt(type);
|
||||
if(type != 11) $(el).next('.onekey-menu-sub').remove();
|
||||
if(type == 10){
|
||||
$(el).css('display','block')
|
||||
explain.text('Security Reminder: aaPanel officially conducted a security audit before the third-party plug-in was put on the shelves, but there may be security risks. Please check it out before using it in the production environment.');
|
||||
btn_ground = soft.render_tips_btn(btn_ground,[
|
||||
//{title:'免费入驻',href:'https://www.bt.cn/developer/',rel:'noreferrer noopener',target:'_blank',btn:'免费入驻',class:'btn btn-success btn-xs va0',style:"margin-left:10px;"},
|
||||
@@ -496,15 +555,15 @@ var soft = {
|
||||
]);
|
||||
$(el).append(tips_info.addClass('alert-info'));
|
||||
}else{
|
||||
var ltd = parseInt(bt.get_cookie('ltd_end')),pro = parseInt(bt.get_cookie('pro_end')),todayDate = parseInt(new Date().getTime()/1000),_ltd = null;
|
||||
var ltd = parseInt(bt.get_cookie('ltd_end') || -1),pro = parseInt(bt.get_cookie('pro_end') || -1),todayDate = parseInt(new Date().getTime()/1000),_ltd = null;
|
||||
if((ltd > 0 && (ltd == pro || pro < 0)) || (ltd < 0 && pro >= 0) || (ltd > 0 && pro >= 0)){
|
||||
_ltd = ((ltd > 0 && (ltd == pro || pro < 0)) || (ltd > 0 && pro >= 0))?1:0;
|
||||
explain.html('当前为'+ (_ltd?'Pro':'专业版') +','+ (_ltd?'Pro':'专业版') +'可以免费使用'+ (_ltd?'专业版及企业版插件':'专业版插件') + (!(pro == 0 && ltd < 0)?(',过期时间:'+ (bt.format_data((_ltd?ltd:pro),'yyyy/MM/dd') ) +''+((((_ltd?ltd:pro) - todayDate) <= 15*24*60*60)?(',<span style="color:red">距离过期仅剩'+ Math.round(((_ltd?ltd:pro) - todayDate) / (24*60*60)) +'天</span>'):'')):',过期时间:<span style="color: #fc6d26;font-weight: bold;">永久授权</span>'));
|
||||
explain.html('The '+ (_ltd?'Pro':'Pro') +' edition can use the '+ (_ltd?'专业版及企业版插件':'professional plug-in for free,') + (!(pro == 0 && ltd < 0)?('expiration time: '+ (bt.format_data((_ltd?ltd:pro),'yyyy/MM/dd') ) +''+((((_ltd?ltd:pro) - todayDate) <= 15*24*60*60)?(',<span style="color:red">Only '+ Math.round(((_ltd?ltd:pro) - todayDate) / (24*60*60)) +' days until expiration</span>'):'')):',过期时间:<span style="color: #fc6d26;font-weight: bold;">永久授权</span>'));
|
||||
}else if(ltd == -1 && pro == -1){
|
||||
explain.html('Upgrade to Pro edition, all plugins, free to use!');
|
||||
}else if(pro == 0 && ltd < 0){
|
||||
_ltd = 2;
|
||||
explain.html('当前为专业版,专业版可以免费使用专业版插件,过期时间:永久授权。'+(type == 12?' <span style="color:#af8e48">升级企业版,企业可以免费试用企业版插件及专业版插件。</span>':''));
|
||||
explain.html('The Pro edition can use the professional plug-in for free, expiration time: 永久授权。'+(type == 12?' <span style="color:#af8e48">升级企业版,企业可以免费试用企业版插件及专业版插件。</span>':''));
|
||||
if(type == 12){
|
||||
btn_ground = soft.render_tips_btn(btn_ground,{title:'立即升级',href:'javascript:;',btn:'立即升级','class':'btn btn-success btn-xs va0 ml15','style':"margin-left:10px;",click:bt.soft.updata_ltd});
|
||||
}
|
||||
@@ -514,54 +573,66 @@ var soft = {
|
||||
}
|
||||
var btn_config = {title:null,href:'javascript:;',btn:null,'class':'btn btn-success btn-xs va0 ml15','style':"margin-left:10px;",click:null};
|
||||
var set_btn_style = function(res){
|
||||
if(!res.status || !res){
|
||||
$.extend(btn_config,{title:'立即登录',btn:'立即登录',click:function(){
|
||||
bt.pub.bind_btname(function(){
|
||||
window.location.reload();
|
||||
});
|
||||
}});
|
||||
if(!res.status || !res){
|
||||
fun = function(){
|
||||
bt.pub.bind_btname(function(){
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
$.extend(btn_config,{title:'Login',btn:'Login',click:fun});
|
||||
}else{
|
||||
if(type == 12 && (ltd < 0 && pro >=0)){
|
||||
explain.html('企业版可以免费使用专业版及企业版插件,了解专业版和企业版的区别,请点击<a href="https://www.bt.cn/download/linux.html" target="_blank" class="btlink ml5">查看详情</a>。<a href="https://www.bt.cn/bbs/forum.php?mod=viewthread&tid=50342&page=1&extra=#pid179211" target="_blank" class="btlink ml5">《专业版升级企业版教程》</a>');
|
||||
$(el).append(tips_info.addClass('alert-ltd-success'));
|
||||
return false;
|
||||
}else{
|
||||
if(type == 12 && (ltd < 0 && pro >=0)){
|
||||
explain.html('企业版可以免费使用专业版及企业版插件,了解专业版和企业版的区别,请点击<a href="https://www.bt.cn/download/linux.html" target="_blank" class="btlink ml5">查看详情</a>。<a href="https://www.bt.cn/bbs/forum.php?mod=viewthread&tid=50342&page=1&extra=#pid179211" target="_blank" class="btlink ml5">《专业版升级企业版教程》</a>');
|
||||
$(el).append(tips_info.addClass('alert-ltd-success'));
|
||||
return false;
|
||||
}else{
|
||||
if(_ltd != 2){
|
||||
var fun = '';
|
||||
switch(_ltd){
|
||||
case null:
|
||||
fun = bt.soft.updata_commercial_view
|
||||
break;
|
||||
case 1:
|
||||
fun = bt.soft.updata_ltd
|
||||
break;
|
||||
case 0:
|
||||
fun = bt.soft.updata_pro
|
||||
break;
|
||||
}
|
||||
$.extend(btn_config,{title:_ltd == null?'Upgrade now':'立即续费',btn:_ltd == null?'Upgrade now':'立即续费',click:fun})
|
||||
}
|
||||
}
|
||||
if(pro < 0){
|
||||
fun = bt.soft.updata_pro
|
||||
}else{
|
||||
fun = bt.soft.renew_pro
|
||||
}
|
||||
$.extend(btn_config,{title:_ltd == null?'Upgrade now':'Renew Now',btn:_ltd == null?'Upgrade now':'Renew Now',click:fun})
|
||||
}
|
||||
if(_ltd != 2){
|
||||
if(!(pro == 0 && ltd < 0)){
|
||||
btn_ground = soft.render_tips_btn(btn_ground,btn_config);
|
||||
}
|
||||
}
|
||||
if(_ltd != 2){
|
||||
if(!(pro == 0 && ltd < 0)){
|
||||
btn_ground = soft.render_tips_btn(btn_ground,btn_config);
|
||||
}
|
||||
$(el).append(tips_info.addClass(_ltd == 1?'alert-ltd-success':'alert-success'));
|
||||
}
|
||||
$(el).append(tips_info.addClass(_ltd == 1?'alert-ltd-success':'alert-success'));
|
||||
if(_this.trail){
|
||||
setTimeout(function (){
|
||||
$('.btn-ground').after('<span class="pro_trail" style="font-weight: 700;margin-left:25px;">Try the Pro edition for free for 15 days</span>')
|
||||
var trail = $('<a href="javascript:;" class="btn btn-success btn-xs va0 ml15" style="margin-left:10px;">Click to try</a>');
|
||||
trail.click((!res.status || !res)?fun:function(){
|
||||
var loadT = bt.load()
|
||||
bt.confirm({
|
||||
title:"Pro Edition",
|
||||
msg:"Get 15-day Pro edition free, get it now?"
|
||||
},function (){
|
||||
bt.send('free_trial','auth/free_trial',{},function(res){
|
||||
loadT.close()
|
||||
bt.msg(res)
|
||||
setTimeout(function () { window.location.reload() },2000)
|
||||
})
|
||||
})
|
||||
})
|
||||
$('.pro_trail').after(trail)
|
||||
},100)
|
||||
}
|
||||
}
|
||||
var bt_user_info = bt.get_cookie('bt_user_info');
|
||||
if(!bt_user_info){
|
||||
bt.pub.get_user_info(function(res){
|
||||
if(!res.status){
|
||||
set_btn_style(false);
|
||||
return false;
|
||||
}
|
||||
bt.set_cookie('bt_user_info',JSON.stringify(res),300000);
|
||||
set_btn_style(res);
|
||||
});
|
||||
bt.pub.get_user_info(function(res){
|
||||
if(!res.status){
|
||||
set_btn_style(false);
|
||||
return false;
|
||||
}
|
||||
bt.set_cookie('bt_user_info',JSON.stringify(res),300000);
|
||||
set_btn_style(res);
|
||||
});
|
||||
}else{
|
||||
set_btn_style(JSON.parse(bt.get_cookie('bt_user_info')));
|
||||
set_btn_style(JSON.parse(bt.get_cookie('bt_user_info')));
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2791,9 +2862,9 @@ var soft = {
|
||||
}
|
||||
})
|
||||
setTimeout(function() {
|
||||
if ($(".bt-soft-menu .bgw").text() === "Installation extension") {
|
||||
soft.get_tab_contents('set_php_config', obj);
|
||||
}
|
||||
if ($(".bt-soft-menu .bgw").index() === 1) {
|
||||
soft.get_tab_contents('set_php_config', obj);
|
||||
}
|
||||
}, 3000)
|
||||
})
|
||||
break;
|
||||
@@ -3851,8 +3922,8 @@ function onekeyCodeSite(codename, versions, title, enable_functions) {
|
||||
<div class="line"><span class="tname">Note</span>\
|
||||
<div class="info-r c4"><input id="Wbeizhu" class="bt-input-text" name="ps" placeholder="Website note" style="width:398px" type="text"> </div>\
|
||||
</div>\
|
||||
<div class="line"><span class="tname">Root Directory</span>\
|
||||
<div class="info-r c4"><input id="inputPath" class="bt-input-text mr5" name="path" value="' + default_path + '" placeholder="Website root directory" style="width:398px" type="text"><span class="glyphicon glyphicon-folder-open cursor" onclick="ChangePath(\'inputPath\')"></span> </div>\
|
||||
<div class="line"><span class="tname">Document Root</span>\
|
||||
<div class="info-r c4"><input id="inputPath" class="bt-input-text mr5" name="path" value="' + default_path + '" placeholder="Website document root" style="width:398px" type="text"><span class="glyphicon glyphicon-folder-open cursor" onclick="ChangePath(\'inputPath\')"></span> </div>\
|
||||
</div>\
|
||||
<div class="line"><span class="tname">Database</span>\
|
||||
<div class="info-r c4">\
|
||||
|
||||
+115
-43
@@ -34,29 +34,23 @@ Terms.prototype = {
|
||||
},
|
||||
//服务器消息事件
|
||||
on_message: function (ws_event){
|
||||
result = ws_event.data;
|
||||
result= ws_event.data;
|
||||
if(!result) return;
|
||||
// if (result === "\rServer connection failed!\r" || result == "\rWrong user name or password!\r") {
|
||||
// this.close();
|
||||
// return;
|
||||
// }
|
||||
that = this;
|
||||
if ((result.indexOf("@127.0.0.1:") != -1 || result.indexOf("@localhost:") != -1) && result.indexOf('Authentication failed') != -1) {
|
||||
this.term.write(result);
|
||||
that.term.write(result);
|
||||
host_trem.localhost_login_form(result);
|
||||
this.close();
|
||||
that.close();
|
||||
return;
|
||||
}
|
||||
if(result.length > 1 && this.last_body === false){
|
||||
this.last_body = true;
|
||||
if(result.length > 1 && that.last_body === false){
|
||||
that.last_body = true;
|
||||
}
|
||||
this.term.write(result);
|
||||
this.set_term_icon(1);
|
||||
if (result == '\r\nLog out\r\n' || result == 'Log out\r\n' || result == '\r\nlogout\r\n' || result == 'logout\r\n') {
|
||||
// setTimeout(function () {
|
||||
// layer.close(Term.term_box);
|
||||
// }, 500);
|
||||
this.close();
|
||||
this.bws = null;
|
||||
that.term.write(result);
|
||||
that.set_term_icon(1);
|
||||
if (result == '\r\n登出\r\n' || result == '登出\r\n' || result == '\r\nlogout\r\n' || result == 'logout\r\n') {
|
||||
that.close();
|
||||
that.bws = null;
|
||||
|
||||
}
|
||||
},
|
||||
@@ -130,7 +124,6 @@ Terms.prototype = {
|
||||
if(this.bws){
|
||||
size['resize'] = 1;
|
||||
this.send(JSON.stringify(size));
|
||||
this.term
|
||||
}
|
||||
|
||||
},
|
||||
@@ -175,10 +168,10 @@ var host_trem = {
|
||||
username:'root',
|
||||
password:'',
|
||||
pkey: '',
|
||||
ps: ''
|
||||
ps: ''
|
||||
},
|
||||
init:function(){
|
||||
var that = this,isMousemove = true;
|
||||
var that = this;
|
||||
Object.defineProperty(host_trem,'is_full',{
|
||||
get:function(val){
|
||||
return val;
|
||||
@@ -207,23 +200,13 @@ var host_trem = {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//本地存储
|
||||
var _tool_status = localStorage.getItem("tool_status");
|
||||
_tool_host_height = localStorage.getItem("hostHeight"),
|
||||
_tool_commonly_height = localStorage.getItem("commonlyHeight");
|
||||
if(_tool_commonly_height <= 100 )_tool_commonly_height=100;
|
||||
$(window).resize(function(ev){
|
||||
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight,host_commonly = win_height - 185;
|
||||
if(that.isFullScreen()){
|
||||
$('.main-content .safe').height(win_height);
|
||||
$('#term_box_view,.term_tootls').height(win_height);
|
||||
$('.tootls_host_list').height((win_height - 80) * .75);
|
||||
$('.tootls_commonly_list').height((win_height - 80) * .25);
|
||||
}else{
|
||||
$('.main-content .safe').height(win_height - 105);
|
||||
$('#term_box_view,.term_tootls').height(win_height - 105);
|
||||
$('.tootls_host_list').height(host_commonly * .75);
|
||||
$('.tootls_commonly_list').height(host_commonly * .25);
|
||||
}
|
||||
var id = $('.term_item_tab .active').data('id');
|
||||
var item_term = that.host_term[id].term;
|
||||
item_term.FitAddon.fit();
|
||||
that.host_term[id].resize({cols:item_term.cols, rows:item_term.rows});
|
||||
that.on_resize(that);
|
||||
});
|
||||
$('.tab_tootls').on('click','.glyphicon-resize-full',function(){
|
||||
$(this).removeClass('glyphicon-resize-full').addClass('glyphicon-resize-small').attr('title','Exit full Screen');
|
||||
@@ -240,8 +223,13 @@ var host_trem = {
|
||||
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight,host_commonly = win_height - 185;
|
||||
$('.main-content .safe').height(win_height - 105);
|
||||
$('#term_box_view,.term_tootls').height(win_height - 105);
|
||||
$('.tootls_host_list').height(host_commonly * .75);
|
||||
$('.tootls_commonly_list').height(host_commonly * .25);
|
||||
if(_tool_host_height !=0&&_tool_commonly_height !=0){
|
||||
$(".tootls_host_list").css("height",_tool_host_height+"px"),
|
||||
$(".tootls_commonly_list").css("height", _tool_commonly_height+"px");
|
||||
}else{
|
||||
$('.tootls_host_list').height(host_commonly * .75);
|
||||
$('.tootls_commonly_list').height(host_commonly * .25);
|
||||
}
|
||||
that.open_term_view();
|
||||
});
|
||||
|
||||
@@ -266,8 +254,72 @@ var host_trem = {
|
||||
item.term.FitAddon.fit();
|
||||
item.resize({cols:item.term.cols, rows:item.term.rows});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
//通过本地存储获取显示设置
|
||||
if(_tool_status==0){
|
||||
$(".term-tool-button").empty();
|
||||
$(".term-tool-button").append('<span class="glyphicon glyphicon-menu-right"></span>').addClass("tool-hide").removeClass("tool-show");
|
||||
$(".term_box").css("margin-right","260px");
|
||||
$(".term_tootls").css("display","block");
|
||||
if(_tool_host_height !=0&&_tool_commonly_height !=0){
|
||||
$(".tootls_host_list").css("height",_tool_host_height+"px"),
|
||||
$(".tootls_commonly_list").css("height", _tool_commonly_height+"px");
|
||||
}
|
||||
}else{
|
||||
$(".term-tool-button").empty();
|
||||
$(".term-tool-button").append('<span class="glyphicon glyphicon-menu-left"></span>').addClass("tool-show").removeClass("tool-hide");
|
||||
$(".term_box").css("margin-right","0px");
|
||||
$(".term_tootls").css("display","none");
|
||||
}
|
||||
|
||||
//终端工具栏显示
|
||||
$('.term_content_tab').on('click','.tool-show',function(){
|
||||
$(this).empty();
|
||||
$(this).append('<span class="glyphicon glyphicon-menu-right"></span>').addClass("tool-hide").removeClass("tool-show");
|
||||
$(".term_box").css("margin-right","260px");
|
||||
$(".term_tootls").css("display","block");
|
||||
localStorage.setItem("tool_status",0);
|
||||
that.on_resize(that);
|
||||
});
|
||||
|
||||
//终端工具栏隐藏
|
||||
$('.term_content_tab').on('click','.tool-hide',function(){
|
||||
$(this).empty();
|
||||
$(this).append('<span class="glyphicon glyphicon-menu-left"></span>').addClass("tool-show").removeClass("tool-hide");
|
||||
$(".term_box").css("margin-right","0px");
|
||||
$(".term_tootls").css("display","none");
|
||||
localStorage.setItem("tool_status",1);
|
||||
that.on_resize(that);
|
||||
});
|
||||
|
||||
$(".term-move-border").on('mousedown', function (e) {
|
||||
var hostbox_height = parseInt($(".tootls_host_list").css("height")),
|
||||
commonlybox_height = parseInt($(".tootls_commonly_list").css("height")),
|
||||
max_height = hostbox_height + commonlybox_height+38,
|
||||
move_y = e.clientY;
|
||||
$(document).on('mousemove', function (ev) {
|
||||
var offsetY = ev.clientY - move_y,
|
||||
_host = hostbox_height+offsetY;
|
||||
_commonly = commonlybox_height-offsetY;
|
||||
if(_host <= 300){
|
||||
_host = 300;_commonly = max_height-_host-38;
|
||||
}else
|
||||
if(_commonly <= 100){
|
||||
_commonly = 100;_host = max_height-_commonly-38;
|
||||
}
|
||||
$(".tootls_host_list").css("height",_host+"px"),$(".tootls_commonly_list").css("height",_commonly+"px");
|
||||
});
|
||||
$(document).on('mouseup', function (ev) {
|
||||
var _host_height = parseInt($(".tootls_host_list").css("height")),
|
||||
_commonly_height = parseInt($(".tootls_commonly_list").css("height"));
|
||||
localStorage.setItem("hostHeight",_host_height);
|
||||
localStorage.setItem("commonlyHeight",_commonly_height);
|
||||
$(this).unbind('mousemove mouseup');
|
||||
});
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$('.term_item_tab').on('click','.icon-trem-close',function(){
|
||||
var id = $(this).parent().data('id');
|
||||
that.remove_term_view(id);
|
||||
@@ -379,7 +431,7 @@ var host_trem = {
|
||||
// $('.tootls_host_list').on('mouseup','li',function(e){
|
||||
// if(e.button == 0){
|
||||
// if(clientX == e.clientX && clientY == e.clientY){
|
||||
|
||||
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
@@ -458,7 +510,26 @@ var host_trem = {
|
||||
}
|
||||
this.is_full = false;
|
||||
},
|
||||
|
||||
|
||||
on_resize:function(that){
|
||||
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight,host_commonly = win_height - 185;
|
||||
if(that.isFullScreen()){
|
||||
$('.main-content .safe').height(win_height);
|
||||
$('#term_box_view,.term_tootls').height(win_height);
|
||||
$('.tootls_host_list').height((win_height - 80) * .75);
|
||||
$('.tootls_commonly_list').height((win_height - 80) * .25);
|
||||
}else{
|
||||
$('.main-content .safe').height(win_height - 105);
|
||||
$('#term_box_view,.term_tootls').height(win_height - 105);
|
||||
$('.tootls_host_list').height(host_commonly * .75);
|
||||
$('.tootls_commonly_list').height(host_commonly * .25);
|
||||
}
|
||||
var id = $('.term_item_tab .active').data('id');
|
||||
var item_term = that.host_term[id].term;
|
||||
item_term.FitAddon.fit();
|
||||
that.host_term[id].resize({cols:item_term.cols, rows:item_term.rows});
|
||||
},
|
||||
|
||||
/**
|
||||
* @name 本地服务器登录表单
|
||||
* @author chudong<2020-08-10>
|
||||
@@ -686,7 +757,7 @@ var host_trem = {
|
||||
break;
|
||||
}
|
||||
});
|
||||
if(!obj.form.host){
|
||||
if(!obj.form.sort){
|
||||
delete form.sort;
|
||||
that.create_host(form,function(res){
|
||||
if(res.status){
|
||||
@@ -698,7 +769,8 @@ var host_trem = {
|
||||
}
|
||||
});
|
||||
}else{
|
||||
form.new_host = obj.form.host;
|
||||
form.new_host = form.host;
|
||||
form.host = obj.form.host;
|
||||
that.modify_host(form,function(res){
|
||||
if(res.status){
|
||||
layer.close(indexs)
|
||||
|
||||
+1428
-1366
File diff suppressed because it is too large
Load Diff
Vendored
+3
-3
File diff suppressed because one or more lines are too long
@@ -45,9 +45,9 @@ var lan = {
|
||||
"memre_ok_0":"Releasing",
|
||||
"memre_ok_1":"Released",
|
||||
"memre_ok_2":"Already the best",
|
||||
"mem_warning":"Currently available physical memory is less than 64M, which may cause MySQL to automatically stop, site 502 and other errors, please try to free the memory!",
|
||||
"mem_warning":"Currently available physical RAM is less than 64M, which may cause MySQL to automatically stop, site 502 and other errors, please try to free the memory!",
|
||||
"user_warning":"Current panel user is admin, which may bring risks to the panel!!",
|
||||
"cpu_core":"Core",
|
||||
"cpu_core":"Core(s)",
|
||||
"interfacespeed":"Interface speed",
|
||||
"package_num":"Package number",
|
||||
"interface_net":"Interface traffic in real time",
|
||||
@@ -107,14 +107,14 @@ var lan = {
|
||||
"rep_panel_title":"Repair panel",
|
||||
"rep_panel_the":"Verifying module...",
|
||||
"rep_panel_ok":"Repair completed, please press Ctrl+F5 to refresh the cache!",
|
||||
"bind_bt_account_first":"Please bind your BT account first!",
|
||||
"bind_bt_account_first":"Please bind your aaPanel account first!",
|
||||
"avg_load_atlast_onemin":"Average load in the last 1 minute: ",
|
||||
"avg_load_atlast_fivemin":"Average load in the last 5 minutes: ",
|
||||
"avg_load_atlast_fifteenmin":"Average load in the last 15 minutes: ",
|
||||
"mem_release_sure":"Are you sure to to free the memory?",
|
||||
"mem_release_warn":"If your site is in a state of heavy access, freeing up memory can have unpredictable consequences. Are you sure you want to free memory now?",
|
||||
"mem_release_warn":"If your site is in a state of heavy access, freeing up RAM can have unpredictable consequences. Are you sure you want to free RAM now?",
|
||||
"update":"Update",
|
||||
"find_bug_reward":"Find bugs, get BT coins",
|
||||
"find_bug_reward":"Find bugs, get aaPanel coins",
|
||||
"run_block":"Running blocked",
|
||||
"run_slow":"Running slowly",
|
||||
"run_normal":"Running normally",
|
||||
@@ -124,7 +124,7 @@ var lan = {
|
||||
"edit_now":"Modify now",
|
||||
"inode_info":"Inode info",
|
||||
"total":"Total",
|
||||
"already_use":"Already used",
|
||||
"already_use":"Used",
|
||||
"available":"Available",
|
||||
"inode_percent":"Inode usage",
|
||||
"test_version":"Beta",
|
||||
@@ -164,7 +164,11 @@ var lan = {
|
||||
"panel_port_tips":"The current panel uses the default port [8888], which has security risks. Please modify the panel port in the panel settings!",
|
||||
"panel_port_tip1":"This security issue cannot be ignored, please handle it as soon as possible.",
|
||||
"panel_port_tip2":"Not negligible",
|
||||
"panel_port_tip3":"Change now"
|
||||
"panel_port_tip3":"Change now",
|
||||
"base_info": "basic information",
|
||||
"capacity_info":"Capacity information",
|
||||
"capacity":"Capacity",
|
||||
"usage_rate":"Usage rate"
|
||||
},
|
||||
"config":{
|
||||
"modify_time":"Modified time",
|
||||
@@ -173,13 +177,13 @@ var lan = {
|
||||
"close_panel_title":"Disable Panel",
|
||||
"config_save":"Saving configuration...",
|
||||
"config_sync":"Syncing time...",
|
||||
"config_user_binding":"Binding your BT account",
|
||||
"config_user_edit":"Change BT account",
|
||||
"config_user_binding":"Binding your aaPanel account",
|
||||
"config_user_edit":"Change aaPanel account",
|
||||
"binding":"Bind",
|
||||
"token_get":"Getting token...",
|
||||
"user_bt":"Username",
|
||||
"pass_bt":"Password",
|
||||
"binding_un_msg":"Are you sure to unbind BT account?",
|
||||
"binding_un_msg":"Are you sure to unbind aaPanel account?",
|
||||
"binding_un_title":"Unbind",
|
||||
"binding_un":"unbind",
|
||||
"ssl_close_msg":"You will have to use http protocol to access the panel after turning off SSL, continue?",
|
||||
@@ -217,13 +221,13 @@ var lan = {
|
||||
"confirm_unbind":"Are you sure to cancel the current binding?",
|
||||
"cancel":"Cancel",
|
||||
"bind_success":"Successfully bound",
|
||||
"open_small_app":"Open the BT panel Mini Program",
|
||||
"open_small_app":"Open the aaPanel panel Mini Program",
|
||||
"qrcore_of_small_app":"QR code of Mini Program",
|
||||
"scan_qrcore_with_small_app":"Use BT Mini Program to scan the current QR code to bind the panel",
|
||||
"scan_qrcore_with_small_app":"Use aaPanel Mobile to scan the current QR code to bind the panel",
|
||||
"return_bind_list":"Return to the panel binding list",
|
||||
"read_bind_list":"View binding list",
|
||||
"bind_wechat":"Bind WeChat",
|
||||
"no_bind_bt_account":"BT account NOT bound",
|
||||
"no_bind_bt_account":"aaPanel account NOT bound",
|
||||
"get_api":"Getting API info...",
|
||||
"set_api":"Configuration panel API",
|
||||
"api":"API",
|
||||
@@ -299,8 +303,8 @@ var lan = {
|
||||
"TZZ5":"Friday",
|
||||
"TZZ6":"Saturday",
|
||||
"TZZ7":"Sunday",
|
||||
"mem_ps":"Free memory of PHP/MySQL/Pure-FTPd/Apache/Nginx, recommended to be executed every midnight!",
|
||||
"mem":"Free memory",
|
||||
"mem_ps":"Free RAM of PHP/MySQL/Pure-FTPd/Apache/Nginx, recommended to be executed every midnight!",
|
||||
"mem":"Free RAM",
|
||||
"log_empty":"Current log is empty",
|
||||
"microsoft_yahei":"Microsoft Yahei",
|
||||
"crontab_stop":"Disable the cron job",
|
||||
@@ -313,7 +317,7 @@ var lan = {
|
||||
"db_bak":"Backup database",
|
||||
"log_split":"Log cutting",
|
||||
"dir_bak":"Directory backup",
|
||||
"mem_release":"Free memory",
|
||||
"mem_release":"Free RAM",
|
||||
"get_url":"Get URL",
|
||||
"hourly":"Hourly",
|
||||
"daily":"Daily",
|
||||
@@ -335,7 +339,7 @@ var lan = {
|
||||
"copies":"copies",
|
||||
"shell_content":"Script content",
|
||||
"tips":"Tips",
|
||||
"tips_content":"Free memory of PHP/MySQL/Pure-FTPd/Apache/Nginx, recommended to be executed every midnight!",
|
||||
"tips_content":"Free RAM of PHP/MySQL/Pure-FTPd/Apache/Nginx, recommended to be executed every midnight!",
|
||||
"edit_save":"Save changes",
|
||||
"saving":"Saving changes, please wait...",
|
||||
"crontab_stop_will":"The cron job will not continue to run after suspended. Are you sure to suspend this cron job?",
|
||||
@@ -384,10 +388,10 @@ var lan = {
|
||||
"bt_default_port":"Default port of aaPanel",
|
||||
"site_default_port":"Default port of WebSite",
|
||||
"del":"Del",
|
||||
"number":"Number",
|
||||
"behavior":"Behavior",
|
||||
"number":"ID",
|
||||
"behavior":"Rule",
|
||||
"status":"Status",
|
||||
"add_time":"Time added",
|
||||
"add_time":"Added date",
|
||||
"instructions":"Instructions",
|
||||
"operate":"Operation",
|
||||
"operate_type":"Operation type",
|
||||
@@ -418,7 +422,7 @@ var lan = {
|
||||
"comp":"Computer",
|
||||
"filename":"File name",
|
||||
"etime":"Modification time",
|
||||
"access":"pPermission",
|
||||
"access":"Permission",
|
||||
"own":"Owner",
|
||||
"adddir":"Add directory",
|
||||
"editdir": "Edit directory",
|
||||
@@ -521,7 +525,7 @@ var lan = {
|
||||
"install_apache24":"Selected Apache 2.4, PHP will run in php-fpm mode!",
|
||||
"insatll_s22":"Apache 2.2 NOT support",
|
||||
"insatll_s24":"Apache 2.4 NOT support",
|
||||
"insatll_mem":"Your memory is less than {1}, NOT recommended to install MySQL-{2}",
|
||||
"insatll_mem":"Your RAM is less than {1}, NOT recommended to install MySQL-{2}",
|
||||
"install_to":"Adding to installer...",
|
||||
"install_ok":"Request of installation added to installer",
|
||||
"task_add":"Added to queue",
|
||||
@@ -578,7 +582,7 @@ var lan = {
|
||||
"check_same_name_file":"Checking if the file with the same name exists, please wait...",
|
||||
"recycle_bin_re":"Recover",
|
||||
"recycle_bin_del":"Delete Permanently",
|
||||
"recycle_bin_on":"Turn on recycle bin feature",
|
||||
"recycle_bin_on":"File recycle bin",
|
||||
"recycle_bin_on_db":"Database recycle bin",
|
||||
"recycle_bin_ps":"Warning: Removed files cannot be restored if recycle bin feature is turned off!",
|
||||
"recycle_bin_close":"Empty recycle bin",
|
||||
@@ -633,7 +637,7 @@ var lan = {
|
||||
"shell":"Terminal",
|
||||
"paste":"Paste",
|
||||
"paste_all":"Paste all",
|
||||
"path_root":"Root directory",
|
||||
"path_root":"Document Root",
|
||||
"all":"Batch",
|
||||
"set_auth":"Set permission",
|
||||
"up_title":"Upload Files",
|
||||
@@ -677,7 +681,7 @@ var lan = {
|
||||
"calc_click":"Click to calculate",
|
||||
"ps_php":"PS: PHP configuration file (Anti-crossing-directory)!",
|
||||
"ps_ap":"PS: Apache user configuration file (Rewrite rules)",
|
||||
"ps_swap":"PS: BT default swap virtual memory file",
|
||||
"ps_swap":"PS: aaPanel default swap virtual RAM file",
|
||||
"last_edit_time":"Last modified",
|
||||
"will_cover_this_file":"about to overwrite the following file(s)",
|
||||
"file_name_cant_empty":"File name cannot be empty!",
|
||||
@@ -707,10 +711,10 @@ var lan = {
|
||||
"add_pass":"Password",
|
||||
"add_pass_tips":"Please enter FTP password",
|
||||
"add_pass_rep":"Random password",
|
||||
"add_path":"Root directory",
|
||||
"add_path":"Home",
|
||||
"add_path_tips":"Please enter or select FTP directory",
|
||||
"add_path_rep":"Select directory",
|
||||
"add_path_title":"Root directory of user, which will automatically create directory of the same name",
|
||||
"add_path_title":"Document root of user, which will automatically create directory of the same name",
|
||||
"add_path_ps":"Directory that FTP points to",
|
||||
"add_ps":"Note",
|
||||
"add_ps_title":"Note info (Less than 255 characters)",
|
||||
@@ -834,7 +838,7 @@ var lan = {
|
||||
"status":"Current status",
|
||||
"restart":"Restart",
|
||||
"reload":"Reload",
|
||||
"mysql_mem_err":"Server memory is less than 1G. It is not recommended to use MySQL 5.5 or later.</li><li>If the database stops automatically, try to increase swap with Linux Toolbox or increase server memory",
|
||||
"mysql_mem_err":"Server RAM is less than 1G. It is not recommended to use MySQL 5.5 or later.</li><li>If the database stops automatically, try to increase swap with Linux Toolbox or increase server memory",
|
||||
"concurrency_m":"Custom",
|
||||
"concurrency":"Concurrency",
|
||||
"concurrency_type":"Concurrency plan",
|
||||
@@ -959,7 +963,7 @@ var lan = {
|
||||
"lib_uninstall_the":"Uninstalling, please wait...",
|
||||
"mysql_set_msg":"Optimization plan",
|
||||
"mysql_set_select":"Select",
|
||||
"mysql_set_maxmem":"Max memory usage",
|
||||
"mysql_set_maxmem":"Max RAM usage",
|
||||
"mysql_set_key_buffer_size":"Buffer size for indexing",
|
||||
"mysql_set_query_cache_size":"Query cache, set to 0 for not enabled",
|
||||
"mysql_set_tmp_table_size":"Temporary table cache size",
|
||||
@@ -976,7 +980,7 @@ var lan = {
|
||||
"mysql_set_max_connections":"Max connections",
|
||||
"mysql_set_restart":"Restart mysqld service",
|
||||
"mysql_set_conn":"Num of connections",
|
||||
"mysql_set_err":"ERROR, memory allocation is too high!<p style='color:red;'>Physical memory: {1}MB<br> Maximum memory: {2}MB<br>Possible result: mysqld service unstable, even unable to start!</p>",
|
||||
"mysql_set_err":"ERROR, RAM allocation is too high!<p style='color:red;'>Physical memory: {1}MB<br> Maximum memory: {2}MB<br>Possible result: mysqld service unstable, even unable to start!</p>",
|
||||
"mysql_status_title1":"Launch Time",
|
||||
"mysql_status_title2":" Total Connections",
|
||||
"mysql_status_title3":"Output",
|
||||
@@ -1091,7 +1095,7 @@ var lan = {
|
||||
"run_days":"Running days",
|
||||
"curr_listen_port":"Currently listened port",
|
||||
"connected_clients":"Connected clients",
|
||||
"used_memory_rss":"Total system memory currently used by Redis",
|
||||
"used_memory_rss":"Total system RAM currently used by Redis",
|
||||
"used_memory":"The peak of memory allocated by Redis in history",
|
||||
"mem_fragmentation_ratio":"Memory fragment ratio",
|
||||
"total_connections_received":"Total connections received since started",
|
||||
@@ -1107,7 +1111,7 @@ var lan = {
|
||||
"size":"Size",
|
||||
"author":"Author",
|
||||
"source":"Source",
|
||||
"third_party_apps_tips1":"This is a plugin developed by a third party, BT can not verify its reliability!",
|
||||
"third_party_apps_tips1":"This is a plugin developed by a third party, aaPanel can not verify its reliability!",
|
||||
"third_party_apps_tips2":"The installation process may take a few minutes, please be patient!",
|
||||
"third_party_apps_tips3":"If this plugin already exists, it will be replaced!",
|
||||
"cancel":"Cancel",
|
||||
@@ -1156,13 +1160,13 @@ var lan = {
|
||||
"success_txt":"Successfully created site",
|
||||
"php_ver":"PHP version",
|
||||
"site_add":"Add site",
|
||||
"domain":"Domain",
|
||||
"domain":"Domain name",
|
||||
"port":"Port",
|
||||
"note":"Note",
|
||||
"note_ph":"Site note",
|
||||
"web_root_dir":"Web root directory",
|
||||
"web_root_dir":"Web document root",
|
||||
"web_dir":"Web directory",
|
||||
"root_dir":"Root directory",
|
||||
"root_dir":"Document Root",
|
||||
"yes":"Create",
|
||||
"no":"Cancel",
|
||||
"ftp_set":"FTP settings",
|
||||
@@ -1178,8 +1182,8 @@ var lan = {
|
||||
"default_doc_help":"Default indexes, one per line, priority top-to-bottom.",
|
||||
"site_stop_txt":"Unable to access when you turn off site, are you sure to continue?",
|
||||
"site_start_txt":"About to turn on this site, are you sure to continue?",
|
||||
"site_del_info":"Whether to delete corresponding FTP, database and root directory",
|
||||
"all_del_info":"Delete site and root directory at the same time",
|
||||
"site_del_info":"Whether to delete corresponding FTP, database and document root",
|
||||
"all_del_info":"Delete site and document root at the same time",
|
||||
"all_del_site":"Batch delete sites",
|
||||
"del_err":"Failed to delete the following sites",
|
||||
"click_access":"Click to access",
|
||||
@@ -1212,7 +1216,7 @@ var lan = {
|
||||
"site_menu_1":"Subdirectory binding",
|
||||
"site_menu_2":"Site directory",
|
||||
"site_menu_3":"Traffic control",
|
||||
"site_menu_4":"URL rewirte",
|
||||
"site_menu_4":"URL rewrite",
|
||||
"site_menu_5":"Default indexes",
|
||||
"site_menu_6":"Config",
|
||||
"site_menu_7":"SSL",
|
||||
@@ -1259,7 +1263,7 @@ var lan = {
|
||||
"limit_net_13":"Limit of single IP accessing max concurrency",
|
||||
"limit_net_14":"Traffic control",
|
||||
"limit_net_15":"Limit the max traffic limit per request (unit: KB)",
|
||||
"subdirectories":"SubDir",
|
||||
"subdirectories":"Subdir",
|
||||
"url_rewrite_alter":"Are you sure to create a independent URL rewrite rule for this subdirectory?",
|
||||
"rule_cov_tool":"Rewrite rule converter",
|
||||
"a_c_n":"Apache to Nginx",
|
||||
@@ -1290,7 +1294,7 @@ var lan = {
|
||||
"enable_301":"Enable 301",
|
||||
"to301_help_1":"If choose entire site, please do NOT set the target URL to the domain in the same site.",
|
||||
"to301_help_2":"After cancelling the 301 redirect, you need to clear your browser cache to see the results",
|
||||
"bt_ssl":"BT SSL",
|
||||
"bt_ssl":"aaPanel SSL",
|
||||
"lets_ssl":"Let's Encrypt free certificate",
|
||||
"other":"Other",
|
||||
"other_ssl":"Other certificate",
|
||||
@@ -1301,20 +1305,20 @@ var lan = {
|
||||
"ssl_key":"Private key (KEY)",
|
||||
"ssl_crt":"Certificate (CRT/PEM)",
|
||||
"ssl_close":"Disable SSL",
|
||||
"bt_bind_no":"Not bound to BT account, please register and bind. After binding BT account (non-forum account), you can deploy SSL with one click",
|
||||
"bt_user":"BT Account",
|
||||
"bt_bind_no":"Not bound to aaPanel account, please register and bind. After binding aaPanel account (non-forum account), you can deploy SSL with one click",
|
||||
"bt_user":"aaPanel Account",
|
||||
"bt_user_first":"Account",
|
||||
"login":"Login",
|
||||
"bt_reg":"Register BT account",
|
||||
"bt_ssl_help_1":"BT SSL certificate is issued by TrustAsia, requires real name identification",
|
||||
"bt_ssl_help_2":"If you have BT account, please log in and bind it",
|
||||
"bt_ssl_help_3":"BT SSL applys certificate TrustAsia DV SSL CA - G5. Original price: 1900 RMB/year, but free for aaPanel users!",
|
||||
"bt_reg":"Register aaPanel account",
|
||||
"bt_ssl_help_1":"aaPanel SSL certificate is issued by TrustAsia, requires real name identification",
|
||||
"bt_ssl_help_2":"If you have aaPanel account, please log in and bind it",
|
||||
"bt_ssl_help_3":"aaPanel SSL applys certificate TrustAsia DV SSL CA - G5. Original price: 1900 RMB/year, but free for aaPanel users!",
|
||||
"bt_ssl_help_4":"Free reissue after one year of maturity.",
|
||||
"btapply":"Apply",
|
||||
"endtime":"Expired date",
|
||||
"status":"Status",
|
||||
"bt_ssl_help_5":"Please check domain resolution before applying, unresolved domain leads to audit failure.",
|
||||
"bt_ssl_help_6":"BT SSL certificate is the free version of TrustAsia DV SSL CA - G5 certificate, which only supports a single domain.",
|
||||
"bt_ssl_help_6":"aaPanel SSL certificate is the free version of TrustAsia DV SSL CA - G5 certificate, which only supports a single domain.",
|
||||
"bt_ssl_help_7":"Valid for 1 year, renewal is not supported, reapplication is required after expiration.",
|
||||
"bt_ssl_help_8":"Let's Encrypt free certificate, valid for 3 months, supports wildcard domain. Auto-renew by default.",
|
||||
"bt_ssl_help_9":"If your site uses CDN or 301 redirect, you will not be able to apply for and renew certificate through file verification.",
|
||||
@@ -1375,7 +1379,7 @@ var lan = {
|
||||
"del_site": "Delete site",
|
||||
"site_classification": "Site category",
|
||||
"all_classification": "All category",
|
||||
"firewalld_nonactivated_tips": "{1} Firewall is NOT activated yet.<br>Please go to"<a href='/soft' class='btlink'>Software Store > Paid plugins > {2} Firewall</a>"<br>to activate and install it.",
|
||||
"firewalld_nonactivated_tips": "{1} WAF is not activated yet.<br>Please go to"<a href='/soft' class='btlink'>APP Store > Professional > {2} WAF</a>"<br>to activate and install it.",
|
||||
"firewalld_nonactivated": "Firewall NOT activated",
|
||||
"download": "Download",
|
||||
"submit": "Submit",
|
||||
@@ -1415,16 +1419,16 @@ var lan = {
|
||||
"video": "Video",
|
||||
"not_resolve_domain": "You applied for a certificate for the domain [{1}], but the program detected that you did not bind and resolve its root domain [{2}] to the site, which would cause the certificate failed to be issued!",
|
||||
"ssl_tips1": "Before applying, please make sure the domain name has been resolved. If it is not resolved, the audit will fail (including the root domain).",
|
||||
"ssl_tips2": "BT SSL applys for the free version of TrustAsia DV SSL CA - G5 certificate, which only supports single domain name application.",
|
||||
"ssl_tips2": "aaPanel SSL applys for the free version of TrustAsia DV SSL CA - G5 certificate, which only supports single domain name application.",
|
||||
"ssl_tips3": "Valid for 1 year, renewal is not supported, reapplication is required after expiration",
|
||||
"ssl_tips4": "It is recommended to use a domain name with a secondary domain name of www to apply for a certificate, so that the system will give away the top-level domain name as an optional name by default",
|
||||
"ssl_tips5": "When you do not specify a SSL default site, if you use HTTPS to access a site that does not have SSL enabled, you will directly access a site that has SSL enabled",
|
||||
"ssl_tips6": "99% of users can easily deploy themselves, if you don't understand, <a class='btlink' href='https://www.bt.cn/yunwei' target='_blank'>BT provides certificate deployment service 50 yuan Once</a>",
|
||||
"ssl_tips6": "99% of users can easily deploy themselves, if you don't understand, <a class='btlink' href='https://www.bt.cn/yunwei' target='_blank'>aaPanel provides certificate deployment service 50 yuan Once</a>",
|
||||
"checking_mode": "Verification mode",
|
||||
"file_check": "File verification",
|
||||
"dns_check_tips1": "In DNS validation, we provide three automated DNS API, and provide manual mode",
|
||||
"dns_check_tips2": "The certificate can be renewed automatically by using the DNS API. In manual mode, the certificate needs to be reapplied after the certificate expires",
|
||||
"dns_check_tips3": "Before using the [BT DNS Cloud Resolution] API, you need to confirm that the domain DNS for which you want to apply for SSL certificate is [Cloud Resolution]",
|
||||
"dns_check_tips3": "Before using the [aaPanel DNS Cloud Resolution] API, you need to confirm that the domain DNS for which you want to apply for SSL certificate is [Cloud Resolution]",
|
||||
"dns_check_tips4": "Before using the [DNSPod/ Ali Cloud DNS] API, you need to set the API key of the corresponding interface in the pop-up window",
|
||||
"dns_check_tips5": "Check in advance (identify problems in advance)",
|
||||
"check_dns": "DNS verification",
|
||||
@@ -1440,7 +1444,7 @@ var lan = {
|
||||
"txt": "TXT record value",
|
||||
"dns_resolve_tips1": "It takes a while to resolve the domain, so after all resolution operations completed, please wait at least 3 minutes before clicking the Verify button",
|
||||
"dns_resolve_tips2": "Domain resolution can be manually verified by the CMD command: nslookup-q=txt _ acme-challenge.bt.cn",
|
||||
"dns_resolve_tips3": "If you are using the BT Cloud Resolution plugin, Ali Cloud DNS,DNSPod as a DNS, you can set auto-resolution with the DNS API",
|
||||
"dns_resolve_tips3": "If you are using the aaPanel Cloud Resolution plugin, Ali Cloud DNS,DNSPod as a DNS, you can set auto-resolution with the DNS API",
|
||||
"dns_resolve_tips4": "It takes a while to resolve the domain, so after all resolution operations completed, please wait a minute before clicking the Verify button",
|
||||
"ssl_dir": "Certificate holder",
|
||||
"brand": "Brand",
|
||||
@@ -1542,9 +1546,9 @@ var lan = {
|
||||
"batch_selected":"Selected",
|
||||
"batch_text":"Batch ",
|
||||
"add_site":{
|
||||
"domain":"domain",
|
||||
"domain":"Domain name",
|
||||
"description":"Description",
|
||||
"root":"Root directory",
|
||||
"root":"Website Path",
|
||||
"ftp":"FTP",
|
||||
"database":"Database",
|
||||
"program":"Program type",
|
||||
@@ -1561,9 +1565,9 @@ var lan = {
|
||||
"database_ph":"Create Database account",
|
||||
"database_password":"Database Password",
|
||||
"bath_code_ph":"domain|1|0|0|0\ndomain|1|0|0|0\ndomain|1|0|0|0",
|
||||
"bath_tips1":"Batch format: Domain|Root directory|FTP|Database|PHP version",
|
||||
"bath_tips1":"Batch format: Domain|Document Root|FTP|Database|PHP version",
|
||||
"bath_tips2":"<span style='padding-top:5px;display:inline-block;'>Domain format: domains use , spilt</span>",
|
||||
"bath_tips3":"Root directory: Input 1 is automatic creation, or enter a specific directory",
|
||||
"bath_tips3":"Document Root: Input 1 is automatic creation, or enter a specific directory",
|
||||
"bath_tips4":"FTP format: Input 1 is automatic creation, input 0 is not creat",
|
||||
"bath_tips5":"Database format: Input 1 is automatic creation, input 0 is not creat",
|
||||
"bath_tips6":"PHP version: Input 0 is static, or input the specific version of PHP, eq,56、71、74",
|
||||
@@ -1660,7 +1664,7 @@ var lan = {
|
||||
"login_expire":"Your login status has expired, please log in again!",
|
||||
"session_expire":"Session expired",
|
||||
"logout":"Log out",
|
||||
"bt_terminal":"BT terminal",
|
||||
"bt_terminal":"aaPanel terminal",
|
||||
"paste_comm_this":"Please paste the command here...",
|
||||
"send":"Send",
|
||||
"turnoff":"Close",
|
||||
@@ -1716,7 +1720,7 @@ var lan = {
|
||||
"plug_err":"Plugin class name, or plugin method name missing!",
|
||||
"request_err":"An error occurred in the request process!",
|
||||
"already_install":"Installed",
|
||||
"rootdir":"Root directory",
|
||||
"rootdir":"Document Root",
|
||||
"back":"Back",
|
||||
"flush":"Refresh",
|
||||
"set_account":"Account setup",
|
||||
@@ -1796,9 +1800,9 @@ var lan = {
|
||||
"server":"Server",
|
||||
"cp_success":"Successfully copied",
|
||||
"cp_fail":"Failed to copy, browser is not compatible!",
|
||||
"bind_bt_account":"Bind Account registered",
|
||||
"bind_bt_account":"Bind aaPanel account",
|
||||
"mobile_phone":"Mobile phone",
|
||||
"mobile_phone_or_email":"Mobile phone or Email",
|
||||
"mobile_phone_or_email":"Your Email address",
|
||||
"pass":"Password",
|
||||
"rootpass":"Root password",
|
||||
"login":"Log in",
|
||||
@@ -1813,9 +1817,9 @@ var lan = {
|
||||
"confirm":"OK",
|
||||
"cancel":"Cancel",
|
||||
"unbind":"Unbind",
|
||||
"open_bt_small_app":"Open the BT panel mini program",
|
||||
"open_bt_small_app":"Open the aaPanel panel mini program",
|
||||
"app_qr_core":"Mini program QR code",
|
||||
"scan_qr_core":"Use BT Mini Programs to scan the current QR code and bind to the panel",
|
||||
"scan_qr_core":"Use aaPanel Mobile to scan the current QR code and bind to the panel",
|
||||
"return_bind_list":"Return to panel binding list",
|
||||
"read_bind_list":"View binding list",
|
||||
"bind_wechat":"Bind WeChat",
|
||||
@@ -1924,7 +1928,7 @@ var lan = {
|
||||
"domain":"Domain",
|
||||
"domian_tips":"A domain per line, the default port is 80<br>Wildcard domain format: *.domain.com<br>To add another port, the format is www.domain.com:88",
|
||||
"site_ps":"Site note",
|
||||
"root_dir":"Root directory",
|
||||
"root_dir":"Document Root",
|
||||
"dont_create":"Not create",
|
||||
"create":"Create",
|
||||
"set_ftp":"FTP settings",
|
||||
@@ -1948,7 +1952,8 @@ var lan = {
|
||||
"cancel":"Cancel",
|
||||
"connect":"Connecting..",
|
||||
"wait_task":"Waiting the task to execute",
|
||||
"cancel_task":"Cancelling task..."
|
||||
"cancel_task":"Cancelling task...",
|
||||
"task_queue":"Task queue"
|
||||
},
|
||||
"install":{
|
||||
"passwd_cant_empty":"Username or password cannot be empty!",
|
||||
@@ -1956,9 +1961,9 @@ var lan = {
|
||||
"setting_up":"Processing..."
|
||||
},
|
||||
"login":{
|
||||
"qr_core_login":"BT Mini Program QR code login",
|
||||
"qr_core_login":"aaPanel Mobile QR code login",
|
||||
"open":"Open",
|
||||
"bt_small_p":"BT Mini Program",
|
||||
"bt_small_p":"aaPanel Mobile",
|
||||
"scan_login":"Scan to log in",
|
||||
"scan_more_safety":"QR code login is more secure",
|
||||
"scan_success":"Successfully scanned QR code, please wait...",
|
||||
@@ -2092,7 +2097,7 @@ var lan = {
|
||||
"mem":"Memory",
|
||||
"status":"Status",
|
||||
"operate":"Operate",
|
||||
"py_tips1":"By default, the manager uses the pip to install the module in requirements.txt in the root directory. If there are other modules to be installed, please manually enter the virtual environment to install",
|
||||
"py_tips1":"By default, the manager uses the pip to install the module in requirements.txt in the Document Root. If there are other modules to be installed, please manually enter the virtual environment to install",
|
||||
"py_tips2":"Method to enter the virtual environment:",
|
||||
"py_tips3":"Enter on the CLI",
|
||||
"py_tips4":"Source project path/project name_venv/bin/activate",
|
||||
@@ -2182,7 +2187,7 @@ var lan = {
|
||||
"save_conf_now":"Saving configuration info, please wait...",
|
||||
"choose_file":"Please select a file",
|
||||
"input_newfile_name":"Please enter a new file name",
|
||||
"rootdir":"Root directory",
|
||||
"rootdir":"Document Root",
|
||||
"create_newfile":"Creating new file, please wait...",
|
||||
"get_file_list":"Getting file list, please wait...",
|
||||
"plug_err":"The plugin class name, or plugin method name is missing!",
|
||||
@@ -2303,7 +2308,7 @@ var lan = {
|
||||
"get_file_list":"Getting file list...",
|
||||
"del":"Del",
|
||||
"download":"Download",
|
||||
"roodir":"Root directory",
|
||||
"roodir":"Document Root",
|
||||
"back":"Back",
|
||||
"flush":"Refresh",
|
||||
"set_account":"Account setting",
|
||||
@@ -2345,7 +2350,7 @@ var lan = {
|
||||
"set_time_zone":"Time zone setting",
|
||||
"sys_pass":"System password",
|
||||
"set_ip":"IP settings",
|
||||
"mem_disk":"Memory disk",
|
||||
"mem_disk":"RAM disk",
|
||||
"m_dns":"Primary DNS",
|
||||
"b_dns":"Alternate DNS",
|
||||
"test":"Test",
|
||||
@@ -2357,7 +2362,7 @@ var lan = {
|
||||
"no_use":"Available:",
|
||||
"add_swap":"Add Swap",
|
||||
"confirm":"Confirm",
|
||||
"swap_tips1":"Swap is virtual memory under Linux, set the appropriate swap to increase server stability",
|
||||
"swap_tips1":"Swap is virtual RAM under Linux, set the appropriate swap to increase server stability",
|
||||
"swap_tips2":"It is recommended that the swap capacity be about 1.5 times the real memory capacity. If your server memory is larger than 4GB, you can set a fixed value of 1-2GB",
|
||||
"swap_tips3":"The swap file is saved by default in /www/swap. Make sure the disk space is enough before setting",
|
||||
"swap_tips4":"If you don't need swap, set the capacity to 0.",
|
||||
@@ -2382,8 +2387,8 @@ var lan = {
|
||||
"space":"Capacity",
|
||||
"used":"Used",
|
||||
"mem_disk_tips1":"The ramdisk has a read/write speed that is unmatched by physical disks, but can only be used to save temporary data!",
|
||||
"mem_disk_tips2":"The memory disk directly mounts part of the physical memory as a disk. Please arrange the mount capacity according to the current server memory usage!",
|
||||
"mem_disk_tips3":"After restarting the server or unloading the memory disk, the data saved in the memory disk will be cleared!",
|
||||
"mem_disk_tips2":"The RAM disk directly mounts part of the physical RAM as a disk. Please arrange the mount capacity according to the current server RAM usage!",
|
||||
"mem_disk_tips3":"After restarting the server or unloading the RAM disk, the data saved in the RAM disk will be cleared!",
|
||||
"only_supp_centos":"Currently only CentOS is supported!",
|
||||
"init_netcard":"Initialize the NIC",
|
||||
"cancel":"Cancel",
|
||||
@@ -2394,8 +2399,8 @@ var lan = {
|
||||
"del_netcard_confirm":"Are you sure you want to remove [{1}] from the NIC configuration?",
|
||||
"del_ip":"Delete IP address",
|
||||
"deleting":"Deleting...",
|
||||
"umount_mem_disk":"Unmount the memory disk",
|
||||
"umount_tips1":"After uninstalling the memory disk, the target mount directory will be cleared.</p>Are you sure you want to uninstall the mount directory [{1}]?",
|
||||
"umount_mem_disk":"Unmount the RAM disk",
|
||||
"umount_tips1":"After uninstalling the RAM disk, the target mount directory will be cleared.</p>Are you sure you want to uninstall the mount directory [{1}]?",
|
||||
"umountting":"Uninstalling...",
|
||||
"change_pass_now":"Changing password...",
|
||||
"setting_time_zone":"Setting time zone...",
|
||||
@@ -2441,7 +2446,7 @@ var lan = {
|
||||
"redis_status_tips1": "Number of days in operation",
|
||||
"redis_status_tips2": "current listening port",
|
||||
"redis_status_tips3": "Number of connected clients",
|
||||
"redis_status_tips4": "The total amount of system memory currently occupied by Redis",
|
||||
"redis_status_tips4": "The total amount of system RAM currently occupied by Redis",
|
||||
"redis_status_tips5": "The peak of Redis history allocation memory",
|
||||
"redis_status_tips6": "memory fragmentation ratio",
|
||||
"redis_status_tips7": "The total number of clients connected since the run",
|
||||
@@ -2535,8 +2540,8 @@ var lan = {
|
||||
"domain_tips":"A domain per line, the default port is 80<br>Wildcard domain format: *.domain.com<br>To add another port, the format is www.domain.com:88",
|
||||
"remark":"Remark",
|
||||
"web_note":"Website note",
|
||||
"root_dir":"Root directory",
|
||||
"web_root_dir":"Website root directory",
|
||||
"root_dir":"Document root",
|
||||
"web_root_dir":"Website Document Root",
|
||||
"db":"Database",
|
||||
"username_dbname":"Username/Database name",
|
||||
"src_code":"Source code",
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
"PLUG_MAM": "Plugin manager",
|
||||
"SET_PLUG": "Set plugin ['{1}'] AS!",
|
||||
"INSTALL_THIRD_PARDY_PLUG": "Installed third-party plugin [{1}]",
|
||||
"SITE_DIR_NOT_EXIST_RECREATE": "Site [{1}], root directory [{2}] does NOT exist, recreated!",
|
||||
"SITE_DIR_NOT_EXIST_RECREATE": "Site [{1}], document root [{2}] does NOT exist, recreated!",
|
||||
"SITE_STOP_ANTI_STEALING_LINK": "Hotlink Protection for site [{1}] disabled!",
|
||||
"SITE_START_ANTI_STEALING_LINK": "Hotlink Protection for site [{1}] enabled!",
|
||||
"SET_PHP_CLI":"Set the PHP-CLI version to: {1}",
|
||||
@@ -170,5 +170,7 @@
|
||||
"REMOVE_PARA": "Remove custom compilation parameters: {1}:{2}",
|
||||
"SET_SOFTWARE_COMPILATION": "Setup software: Custom compilation parameters for {1} are configured as: {2}",
|
||||
"SET_FILE_NOTES": "Set the file name [{1}], notes: {2}",
|
||||
"CLEAR_FILE_NOTES": "Clear file notes [{1}]"
|
||||
"CLEAR_FILE_NOTES": "Clear file notes [{1}]",
|
||||
"CREATE_SOFTLINK": "Create softlink: {1} -> {2}",
|
||||
"EXEC_COMPOSER": "Execute composer [{1}] in the directory: [{2}],"
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
"SITE_STOP_SUCCESS":"Site stopped",
|
||||
"SITE_NETLIMIT_ERR":"Site Traffic Control only supports Nginx Web Server!",
|
||||
"SITE_NETLIMIT_CLOSE_SUCCESS":"Site Traffic Control has been turned off!",
|
||||
"SITE_ADD_BINDING":"Domain and Name of Subdirectory cannot be empty!",
|
||||
"SITE_ADD_BINDING":"Domain and name of subdirectory cannot be empty!",
|
||||
"SITE_INDEX_ERR_FORMAT":"Default Document Format is invalid, e.g., index.html",
|
||||
"SITE_INDEX_ERR_EMPTY":"Default Document cannot be empty!",
|
||||
"SITE_PATH_ERR_RE":"Same as original directory, no need to change!",
|
||||
@@ -783,7 +783,7 @@
|
||||
"REDIS_CONF_TIPS4": "Max num of connections",
|
||||
"REDIS_CONF_TIPS5": "Number of databases",
|
||||
"REDIS_CONF_TIPS6": "redis password, leaving blank means no password is set",
|
||||
"REDIS_CONF_TIPS7": "MB, max memory usage, 0 means no limit",
|
||||
"REDIS_CONF_TIPS7": "MB, max RAM usage, 0 means no limit",
|
||||
"RDB_ERR": "Please enter an integer for the RDB parameter",
|
||||
"SYS_DB_CANT_DEL": "System database, cannot be deleted",
|
||||
"SAVE_CONF": "Configuration has been saved",
|
||||
@@ -926,7 +926,7 @@
|
||||
"ACME_USE_TIPS": "Required parameters: --domain list of domain names, multiple separated by commas!",
|
||||
"ACME_USE_TIPS1": "Please specify the domain name to apply for a certificate",
|
||||
"ACME_USE_TIPS2": "Please specify verification type",
|
||||
"ACME_USE_TIPS3": "Please specify the website root directory",
|
||||
"ACME_USE_TIPS3": "Please specify the website document root",
|
||||
"ACME_USE_TIPS4": "Please specify DNSAPI",
|
||||
"ACME_USE_TIPS5": "Please specify DNSAPI key",
|
||||
"ACME_USE_TIPS6": "Please specify DNSAPI secret",
|
||||
@@ -936,7 +936,7 @@
|
||||
"ACME_USE_TIPS10": "Please enter the index of the order to be revoked in the --index parameter",
|
||||
"ACME_USE_TIPS11": "Please specify the domain name for which you want to apply for a certificate in the --domain parameter, multiple separated by commas (,)",
|
||||
"ACME_USE_TIPS12": "Please specify the correct authentication type in the --type parameter, supporting dns and http",
|
||||
"ACME_USE_TIPS13": "Please specify the website root directory in the --path parameter!",
|
||||
"ACME_USE_TIPS13": "Please specify the website document root in the --path parameter!",
|
||||
"ACME_USE_TIPS14": "The specified site root does not exist, please check: {1}",
|
||||
"ACME_USE_TIPS15": "When applying using dnsapi, specify the dnsapi key in the --dns_key parameter!",
|
||||
"ACME_USE_TIPS16": "When applying using dnsapi, specify the secret of dnsapi in the --dns_secret parameter!",
|
||||
@@ -1042,14 +1042,14 @@
|
||||
"BACKUP_DIR_NOT_EXIST": "The specified directory {1} does not exist!",
|
||||
"BACKUP_UPLOADING": "Uploading to {1}, please wait ...",
|
||||
"BACKUP_UPLOAD_SUCCESS": "Successfully uploaded to {1}",
|
||||
"BACKUP_UPLOAD_FAILED": "Error: File upload failed, skip this backup!",
|
||||
"BACKUP_UPLOAD_FAILED": "File upload failed, skip this backup!",
|
||||
"BACKUP_DEL": "User settings do not retain local backups, deleted {1}",
|
||||
"BACKUP_CLEAN_ERR": "Failed to clean expired backup, error: {1}",
|
||||
"BACKUP_KEEP": "Keep the latest number of backups: {1} copies",
|
||||
"BACKUP_CLEAN": "Expired backup files have been cleaned from disk: {1}",
|
||||
"BACKUP_CLEAN_REMOVE": "Expired backup files have been cleaned from {1}: {2}",
|
||||
"BACKUP_SITE": "Backup site: {1}",
|
||||
"WEBSITE_DIR": "Website root directory: {1}",
|
||||
"WEBSITE_DIR": "Website document root: {1}",
|
||||
"BACKUP_DIR": "Backup directory: {1}",
|
||||
"DIR_SIZE": "Directory size: {1}",
|
||||
"BACKUP_EXCLUSION": "Exclusion setting: {1}",
|
||||
@@ -1108,7 +1108,7 @@
|
||||
"MYSQL_ROOT_PASSWD_EMTPY_ERR": "Root password cannot be empty",
|
||||
"DB_PASSWD_EMPTY_ERR": "Database [{1}] password cannot be empty",
|
||||
"NGINX_NOT_INSTALL": "Nginx is not install",
|
||||
"CREATE_SITE_DIR_ERR": "Failed to create site root directory, {1}",
|
||||
"CREATE_SITE_DIR_ERR": "Failed to create site document root, {1}",
|
||||
"CHOOSE_DOMAIN": "Please choose a domain name",
|
||||
"CHOOSE_PORT": "Please choose a port",
|
||||
"CERT_ERR": "Certificate error, please paste the correct PEM format certificate!",
|
||||
@@ -1123,7 +1123,7 @@
|
||||
"COMPLIANT_NAME_ERR": "Non-compliant names can only be numbers, letters, underscores",
|
||||
"PARA_NOT_EXIST": "The specified custom compilation parameters do not exist!",
|
||||
"WRONG_PARAMETER": "Wrong parameter",
|
||||
"UPLOAD_DIR_ERR": "Cannot upload files to the system root directory!",
|
||||
"UPLOAD_DIR_ERR": "Cannot upload files to the system document root!",
|
||||
"RECYCLE_BIN_ERR": "This is the recycle bin directory, please press the [Recycle Bin] button in the upper right corner to open",
|
||||
"DIR_ERR": "This is not a directory",
|
||||
"FILE_EXIST_ERR": "The target file name already exists!",
|
||||
@@ -1219,5 +1219,21 @@
|
||||
"File_END_WITH": "It is not recommended to use \".\" at the end of the file because there may be security risks",
|
||||
"DIR_END_WITH1": "It is not recommended to use \".\" at the end of the directory, because there may be safety risks",
|
||||
"API_DISABLED": "API has been disabled",
|
||||
"UNBOUND_USER": "Unbound user"
|
||||
"UNBOUND_USER": "Unbound user",
|
||||
"FILE_NAME_ERR": "No special characters can be included in the file name!",
|
||||
"SOFTLINK_FILE_EXIST": "The softlink file name already exists, please use another file name or delete it!",
|
||||
"SOFTLINK_FILE_PATH": "The softlink file name must be an absolute path (full path)",
|
||||
"SOFTLINK_CREATE_ERR": "Softlink file creation failed",
|
||||
"SOFTLINK_CREATE_SUCCESS": "The softlink file was created successfully",
|
||||
"COMPOSER_CONF_NOT_EXIST": "[Composer.json] configuration file is not found in the specified directory!",
|
||||
"COMPOSERLOGCK_EXIST": "[Composer.lock] file exists in the specified directory, please delete it before executing",
|
||||
"KEEP_LOCAL": "Local backup has been kept",
|
||||
"DB_CONN_ERR": "The database connection is abnormal. Please check whether the root user authority or database configuration parameters are correct.",
|
||||
"BACKUP_TASK_TITLE": "{1}-{2} The task was executed successfully",
|
||||
"NOTIFICATION_SENT": "Notification has been sent",
|
||||
"NOTIFICATION_ERR": "Failed to send notification",
|
||||
"BACKUP_MSG": "Backup to {1}, a total of {3} {2}, and failures {4}.",
|
||||
"BACKUP_MSG1": "Backup failed {1}/total {2} sites",
|
||||
"NOTIFICATION": "Notification"
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"V3":"Check update",
|
||||
"S1":"System:",
|
||||
"S2":"Loading: ",
|
||||
"S3":"Time of running uninterrupted: ",
|
||||
"S3":"Time of running",
|
||||
"S4":" Loading",
|
||||
"S5":"Restart server",
|
||||
"S6":"Restart panel",
|
||||
@@ -23,8 +23,8 @@
|
||||
"T2":"Connection Manager",
|
||||
"T3":"Task Manager",
|
||||
"P1":"CPU usage",
|
||||
"P2":"Memory usage",
|
||||
"P3":"Click to free memory",
|
||||
"P2":"RAM usage",
|
||||
"P3":"Click to free RAM",
|
||||
"P4":"Software",
|
||||
"NET1":"Network traffic",
|
||||
"NET2":"Upload speed",
|
||||
@@ -52,7 +52,7 @@
|
||||
"H1":"Dashboard",
|
||||
"H2":"Site Manager",
|
||||
"SEARCH":"Site search",
|
||||
"PS":"After the website is created, the file owner will be set to [www], You can add your backup plan in ",
|
||||
"PS":"After the website is created, the file owner will be set to [www], you can add your backup plan in ",
|
||||
"BTN1":"Add site",
|
||||
"BTN2":"Default page",
|
||||
"BTN3":"Default WebSite",
|
||||
@@ -82,7 +82,7 @@
|
||||
"TH1":"User",
|
||||
"TH2":"Password",
|
||||
"TH3":"Status",
|
||||
"TH4":"Root directory",
|
||||
"TH4":"Document Root",
|
||||
"TH5":"Notes",
|
||||
"TH6":"Action",
|
||||
"JS1":"Pls install Prue-Ftpd first!",
|
||||
@@ -221,20 +221,20 @@
|
||||
"H2":"Cron Job",
|
||||
"H3":"Add Cron Job",
|
||||
"H4":"Task List",
|
||||
"PS":"Type of task: shell script, backup site, backup database, cut log, free memory, access URL",
|
||||
"PS":"Type of task: shell script, backup site, backup database, cut log, free RAM, access URL",
|
||||
"PS1":"When adding a backup task, you should run it manually and check if the backup package is complete",
|
||||
"PS2":"Insufficient disk space, database password error, network instability, etc. may result in incomplete data backup",
|
||||
"PS3":"Support file or directory exclusion when backing up sites and directories. Please upgrade the plug-ins that need to be excluded to the latest version",
|
||||
"T1":"Type of Task",
|
||||
"T2":"Name of Task",
|
||||
"T3":"Period",
|
||||
"T4":"Script Content",
|
||||
"T3":"Execution cycle",
|
||||
"T4":"Script content",
|
||||
"T5":"Add Task",
|
||||
"TT1":"Shell Script",
|
||||
"TT2":"Backup Site",
|
||||
"TT3":"Backup Database",
|
||||
"TT4":"Cut Log",
|
||||
"TT5":"Free Memory",
|
||||
"TT5":"Free RAM",
|
||||
"TT6":"Access URL",
|
||||
"TZ1":"Daily",
|
||||
"TZ2":"N Days",
|
||||
@@ -368,10 +368,10 @@
|
||||
"N13":"Forget Password>>",
|
||||
"JS1":"Error, please try again!",
|
||||
"JS2":"Loading...",
|
||||
"QR_CORE_LOGIN":"QR Code login with BT mini program",
|
||||
"QR_CORE_LOGIN":"Login with aaPanel Mobile",
|
||||
"OPEN":"Open",
|
||||
"BT_SMALL_P":"BT Mini Program",
|
||||
"SCAN_LOGIN":"Scan to log in",
|
||||
"BT_SMALL_P":"aaPanel Mobile",
|
||||
"SCAN_LOGIN":"Scan with ",
|
||||
"SCAN_SUCCESS":"Scanned successfully, please wait...",
|
||||
"SAFE_LOGGING_NOW":"Securely logging in, please wait...",
|
||||
"SCAN_MORE_SAFETY":"QR code login is more secure",
|
||||
|
||||
@@ -45,7 +45,7 @@ var lan = {
|
||||
"memre_ok_0": "Releasing",
|
||||
"memre_ok_1": "Released",
|
||||
"memre_ok_2": "Already the best",
|
||||
"mem_warning": "Memory is less than 64M, It may make MySQL automatically shut down, or 502 Error, Please Release Memory!",
|
||||
"mem_warning": "RAM is less than 64M, It may make MySQL automatically shut down, or 502 Error, Please Release Memory!",
|
||||
"user_warning": "Current user is admin, this could pose a security risk to the Panel!",
|
||||
"cpu_core": "Core",
|
||||
"interfacespeed": "Interface Speed",
|
||||
@@ -112,7 +112,7 @@ var lan = {
|
||||
"avg_load_atlast_fivemin": "Average load in the last 5 minute:",
|
||||
"avg_load_atlast_fifteenmin": "Average load in the last 15 minute:",
|
||||
"mem_release_sure": "Really want to free the memory?",
|
||||
"mem_release_warn": "If your site is in a state of heavy access, freeing up memory can have unpredictable consequences. Are you sure you want to free memory now?",
|
||||
"mem_release_warn": "If your site is in a state of heavy access, freeing up RAM can have unpredictable consequences. Are you sure you want to free RAM now?",
|
||||
"update": "Update",
|
||||
"find_bug_reward": "找Bug奖宝塔币",
|
||||
"run_block": "Running blocking",
|
||||
@@ -271,7 +271,7 @@ var lan = {
|
||||
"hour": "Hour",
|
||||
"minute": "Minute",
|
||||
"sun": "Day",
|
||||
"sbody": "Script Content",
|
||||
"sbody": "Script content",
|
||||
"log_site": "Cut Site Log",
|
||||
"url_address": "URL address",
|
||||
"backup_to": "Backup to",
|
||||
@@ -285,7 +285,7 @@ var lan = {
|
||||
"TZZ5": "Friday",
|
||||
"TZZ6": "Saturday",
|
||||
"TZZ7": "Sunday",
|
||||
"mem_ps": "Release Memory of PHP、MYSQL、PURE-FTPD、APACHE、NGINX, suggestion: Execute this task at midnight every day!",
|
||||
"mem_ps": "Release RAM of PHP、MYSQL、PURE-FTPD、APACHE、NGINX, suggestion: Execute this task at midnight every day!",
|
||||
"mem": "Release Memory",
|
||||
"log_empty": "Current log is empty",
|
||||
"microsoft_yahei": "微软雅黑",
|
||||
@@ -299,7 +299,7 @@ var lan = {
|
||||
"db_bak": "Backup database",
|
||||
"log_split": "Log cutting",
|
||||
"dir_bak": "Backup directory",
|
||||
"mem_release": "Free memory",
|
||||
"mem_release": "Free RAN",
|
||||
"get_url": "Access URL",
|
||||
"hourly": "per hour",
|
||||
"daily": "every day",
|
||||
@@ -321,7 +321,7 @@ var lan = {
|
||||
"copies": "Share",
|
||||
"shell_content": "Script content",
|
||||
"tips": "prompt",
|
||||
"tips_content": "Free memory usage of PHP, MYSQL, PURE-FTPD, APACHE, NGINX, it is recommended to execute in the middle of the night!",
|
||||
"tips_content": "Free RAM usage of PHP, MYSQL, PURE-FTPD, APACHE, NGINX, it is recommended to execute in the middle of the night!",
|
||||
"edit_save": "Save edit",
|
||||
"saving": "Editing content is being saved, please wait",
|
||||
"crontab_stop_will": "After the scheduled task is suspended, it will not be able to continue running. Do you really want to disable this scheduled task?",
|
||||
@@ -500,7 +500,7 @@ var lan = {
|
||||
"install_apache24": "Selected Apache2.4, PHP will run in php-fpm mode!",
|
||||
"insatll_s22": "Apache2.2 NOT supported",
|
||||
"insatll_s24": "Apache2.4 NOT supported",
|
||||
"insatll_mem": "Your Memory is less than {1}, NOT recommeded to install MySQL-{2}",
|
||||
"insatll_mem": "Your RAM is less than {1}, NOT recommeded to install MySQL-{2}",
|
||||
"install_to": "Adding to installer...",
|
||||
"install_ok": "Requestment of installing added to installer",
|
||||
"task_add": "Added to queue",
|
||||
@@ -582,7 +582,7 @@ var lan = {
|
||||
"shell": "Terminal",
|
||||
"paste": "Paste",
|
||||
"paste_all": "Paste all",
|
||||
"path_root": "Root directory",
|
||||
"path_root": "Document Root",
|
||||
"all": "Batch",
|
||||
"set_auth": "Set permission",
|
||||
"up_title": "Upload",
|
||||
@@ -653,10 +653,10 @@ var lan = {
|
||||
"add_pass": "Password",
|
||||
"add_pass_tips": "Pls enter FTP password",
|
||||
"add_pass_rep": "Random password",
|
||||
"add_path": "Root directory",
|
||||
"add_path": "Document Root",
|
||||
"add_path_tips": "Pls enter or select FTP directory",
|
||||
"add_path_rep": "Select directory",
|
||||
"add_path_title": "Root directory of user, automatically create directory of the same name",
|
||||
"add_path_title": "Document root of user, automatically create directory of the same name",
|
||||
"add_path_ps": "Directory that FTP points to",
|
||||
"add_ps": "Note",
|
||||
"add_ps_title": "Note information (Less than 255 characters)",
|
||||
@@ -780,7 +780,7 @@ var lan = {
|
||||
"status": "Current status",
|
||||
"restart": "Restart",
|
||||
"reload": "Rload",
|
||||
"mysql_mem_err": "Memory is less than 1G, MySQL version higher than5.5 version is NOT recommended.</li><li>If database automatically stop frequently, please try to use linux tools to increase SWAP or upgrade server memory",
|
||||
"mysql_mem_err": "RAM is less than 1G, MySQL version higher than5.5 version is NOT recommended.</li><li>If database automatically stop frequently, please try to use linux tools to increase SWAP or upgrade server memory",
|
||||
"concurrency_m": "Custom",
|
||||
"concurrency": "Concurrency",
|
||||
"concurrency_type": "Concurrency plan",
|
||||
@@ -904,7 +904,7 @@ var lan = {
|
||||
"lib_uninstall_the": "Uninstalling, please wait...",
|
||||
"mysql_set_msg": "Optimization plan",
|
||||
"mysql_set_select": "Select",
|
||||
"mysql_set_maxmem": "Max memory usage",
|
||||
"mysql_set_maxmem": "Max RAM usage",
|
||||
"mysql_set_key_buffer_size": "Buffer size for indexing",
|
||||
"mysql_set_query_cache_size": "Query cache, set to 0 if not enabled",
|
||||
"mysql_set_tmp_table_size": "Temporary table cache size",
|
||||
@@ -921,7 +921,7 @@ var lan = {
|
||||
"mysql_set_max_connections": "Max connections",
|
||||
"mysql_set_restart": "Restart mysqld service",
|
||||
"mysql_set_conn": "Num of connections",
|
||||
"mysql_set_err": "Error, memory allocation is too high!<p style='color:red;'>Physical memory: {1}MB<br> Maximum memory: {2}MB<br>Possible result: Causing mysqld service unstable, even unable to start!</p>",
|
||||
"mysql_set_err": "Error, RAM allocation is too high!<p style='color:red;'>Physical memory: {1}MB<br> Maximum memory: {2}MB<br>Possible result: Causing mysqld service unstable, even unable to start!</p>",
|
||||
"mysql_status_title1": "Launch time",
|
||||
"mysql_status_title2": " Total connections",
|
||||
"mysql_status_title3": "Output",
|
||||
@@ -1092,9 +1092,9 @@ var lan = {
|
||||
"port": "Port",
|
||||
"note": "Note",
|
||||
"note_ph": "Site note",
|
||||
"web_root_dir": "Web root directory",
|
||||
"web_root_dir": "Web document root",
|
||||
"web_dir": "Web directory",
|
||||
"root_dir": "Root directory",
|
||||
"root_dir": "Document root",
|
||||
"yes": "Create",
|
||||
"no": "Cancel",
|
||||
"ftp_set": "FTP setting",
|
||||
@@ -1110,8 +1110,8 @@ var lan = {
|
||||
"default_doc_help": "Default indexes, one per line, priority top-to-bottom.",
|
||||
"site_stop_txt": "Unable to access when you turn off site, are you sure to continue?",
|
||||
"site_start_txt": "Ready to turn on this site, are you sure to continue?",
|
||||
"site_del_info": "Whether to delete corresponding FTP, database and root directory",
|
||||
"all_del_info": "Delete site and root directory at the same time",
|
||||
"site_del_info": "Whether to delete corresponding FTP, database and document root",
|
||||
"all_del_info": "Delete site and document root at the same time",
|
||||
"all_del_site": "Batch delete sites",
|
||||
"del_err": "Failed to delete the following sites",
|
||||
"click_access": "Click to access",
|
||||
@@ -1554,7 +1554,7 @@ var lan = {
|
||||
"plug_err": "The plugin class name, or the plugin method name is missing!",
|
||||
"request_err": "The request process found an error!",
|
||||
"already_install": "Installed",
|
||||
"rootdir": "root directory",
|
||||
"rootdir": "document root",
|
||||
"back": "back",
|
||||
"flush": "refresh",
|
||||
"set_account": "Account Settings",
|
||||
@@ -1705,7 +1705,7 @@ var lan = {
|
||||
"domain": "Domain name",
|
||||
"domian_tips": "Fill a domain name per line, the default is 80 port<br>General resolution add method *.domain.com<br>If the port format is www.domain.com:88",
|
||||
"site_ps": "Website Notes",
|
||||
"root_dir": "Root directory",
|
||||
"root_dir": "Document root",
|
||||
"dont_create": "Do not create",
|
||||
"create": "Create",
|
||||
"set_ftp": "FTP settings",
|
||||
@@ -1872,7 +1872,7 @@ var lan = {
|
||||
"mem": "memory",
|
||||
"status": "Status",
|
||||
"operate": "Operation",
|
||||
"py_tips1": "The manager uses the module in the root directory requirements.txt of the pip installation project by default. If there are other modules to be installed, please manually enter the virtual environment installation",
|
||||
"py_tips1": "The manager uses the module in the document root requirements.txt of the pip installation project by default. If there are other modules to be installed, please manually enter the virtual environment installation",
|
||||
"py_tips2": "Enter the virtual environment method:",
|
||||
"py_tips3": "Enter at command line",
|
||||
"py_tips4": "source project path / project name _venv/bin/activate",
|
||||
@@ -1962,7 +1962,7 @@ var lan = {
|
||||
"save_conf_now": "Saving configuration information, please wait...",
|
||||
"choose_file": "Please select a file",
|
||||
"input_newfile_name": "Please enter a new file name",
|
||||
"rootdir": "root directory",
|
||||
"rootdir": "document root",
|
||||
"create_newfile": "New file is being created, please wait...",
|
||||
"get_file_list": "Getting a list of files, please wait...",
|
||||
"plug_err": "The plugin class name, or the plugin method name is missing!",
|
||||
@@ -2083,7 +2083,7 @@ var lan = {
|
||||
"get_file_list": "Getting a list of files...",
|
||||
"del": "Del",
|
||||
"download": "Download",
|
||||
"roodir": "root directory",
|
||||
"roodir": "document root",
|
||||
"back": "Back",
|
||||
"flush": "Refresh",
|
||||
"set_account": "Account Settings",
|
||||
@@ -2125,7 +2125,7 @@ var lan = {
|
||||
"set_time_zone": "Time zone setting",
|
||||
"sys_pass": "system password",
|
||||
"set_ip": "IP settings",
|
||||
"mem_disk": "memory disk",
|
||||
"mem_disk": "RAM disk",
|
||||
"m_dns": "Primary DNS",
|
||||
"b_dns": "Alternate DNS",
|
||||
"test": "test",
|
||||
@@ -2137,8 +2137,8 @@ var lan = {
|
||||
"no_use": "Available:",
|
||||
"add_swap": "Add Swap",
|
||||
"confirm": "OK",
|
||||
"swap_tips1": "swap is virtual memory under Linux, setting the appropriate swap can increase server stability",
|
||||
"swap_tips2": "The recommended swap capacity is about 1.5 times the real memory capacity. If your server memory is larger than 4GB, you can set a fixed value of 1-2GB",
|
||||
"swap_tips1": "swap is virtual RAM under Linux, setting the appropriate swap can increase server stability",
|
||||
"swap_tips2": "The recommended swap capacity is about 1.5 times the real RAM capacity. If your server RAM is larger than 4GB, you can set a fixed value of 1-2GB",
|
||||
"swap_tips3": "The swap file is saved by default at /www/swap. Make sure the disk space is sufficient before setting it.",
|
||||
"swap_tips4": "If you don't need swap, set the capacity to 0",
|
||||
"swap_tips5": "This feature is not available for OVZ Virtual Architecture machines",
|
||||
@@ -2162,7 +2162,7 @@ var lan = {
|
||||
"sapce": "capacity",
|
||||
"used": "used",
|
||||
"mem_disk_tips1": "The ramdisk has a read/write speed that is unmatched by the physical disk, but can only be used to save temporary data!",
|
||||
"mem_disk_tips2": "The memory disk is directly mounted as part of the physical memory, please arrange the storage capacity according to the current server memory usage!",
|
||||
"mem_disk_tips2": "The RAM disk is directly mounted as part of the physical memory, please arrange the storage capacity according to the current server RAM usage!",
|
||||
"mem_disk_tips3": "After restarting the server, or unloading the ramdisk, the data saved in the ramdisk will be emptied!",
|
||||
"only_supp_centos": "Centre only supports Centos!",
|
||||
"init_netcard": "Initialize the network card",
|
||||
@@ -2174,7 +2174,7 @@ var lan = {
|
||||
"del_netcard_confirm": "Are you sure you want to remove [{1}] from the NIC configuration?",
|
||||
"del_ip": "delete IP address",
|
||||
"deleting": "Deleting...",
|
||||
"umount_mem_disk": "Unload memory disk",
|
||||
"umount_mem_disk": "Unload RAM disk",
|
||||
"umount_tips1": "After unloading the ramdisk, the target mount directory will be emptied</p> Are you sure you want to uninstall the mount directory [{1}]?",
|
||||
"umountting": "Unloading...",
|
||||
"change_pass_now": "Modifying password...",
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
"PLUG_MAM": "Plugin manager",
|
||||
"SET_PLUG": "Set plugin ['{1}'] AS!",
|
||||
"INSTALL_THIRD_PARDY_PLUG": "Installed third-party plugin [{1}]",
|
||||
"SITE_DIR_NOT_EXIST_RECREATE": "Site [{1}], root directory [{2}] does NOT exist, recreated!",
|
||||
"SITE_DIR_NOT_EXIST_RECREATE": "Site [{1}], document root [{2}] does NOT exist, recreated!",
|
||||
"SITE_STOP_ANTI_STEALING_LINK": "Hotlink Protection for site [{1}] disabled!",
|
||||
"SITE_START_ANTI_STEALING_LINK": "Hotlink Protection for site [{1}] enabled!"
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
"SITE_STOP_SUCCESS":"Site stopped",
|
||||
"SITE_NETLIMIT_ERR":"Site Traffic Control only supports Nginx Web Server!",
|
||||
"SITE_NETLIMIT_CLOSE_SUCCESS":"Site Traffic Control has been turned off!",
|
||||
"SITE_ADD_BINDING":"Domain and Name of Subdirectory cannot be empty!",
|
||||
"SITE_ADD_BINDING":"Domain and Name of subdirectory cannot be empty!",
|
||||
"SITE_INDEX_ERR_FORMAT":"Default Document Format is invalid, e.g., index.html",
|
||||
"SITE_INDEX_ERR_EMPTY":"Default Document cannot be empty!",
|
||||
"SITE_PATH_ERR_RE":"Same as original directory, no need to change!",
|
||||
@@ -414,7 +414,7 @@
|
||||
"UNINSTALL_FIRST": "Please uninstall [{1}] first",
|
||||
"DEP_PAGE": "Depends on the following software, please install [{1}] first",
|
||||
"MINIMUM_CPU_REQUIRED": "At least [{1}] CPU cores are required to install",
|
||||
"MINIMUM_MEM_REQUIRED": "At least [{1}MB] memory is required to install",
|
||||
"MINIMUM_MEM_REQUIRED": "At least [{1}MB] RAM is required to install",
|
||||
"ALL": "All",
|
||||
"ONLY_SUP_SYS": "Only the [{1}] system is supported",
|
||||
"CHECK_FILE_HASH": "File hash verification failed, stop installation!",
|
||||
@@ -762,7 +762,7 @@
|
||||
"DNS_CANT_USE":"Current DNS is NOT available",
|
||||
"DISK_SPACE_NOT_ENOUGH":"Failed, disk space is not enough, currently available space:",
|
||||
"USERNAME_CANT_EMPTY":"Username cannot be empty",
|
||||
"MEM_DISK_SET_ERR":"Max capacity of the memory disk cannot exceed 50% of physical memory!",
|
||||
"MEM_DISK_SET_ERR":"Max capacity of the RAM disk cannot exceed 50% of physical memory!",
|
||||
"INPUT_ABSOLUTE_PATH":"Please input an absolute path",
|
||||
"DIR_EXIST_ERR":"Directory already has files, please change another directory",
|
||||
"INPUT_ARGS_ERR":"Please input correct parameters",
|
||||
@@ -781,7 +781,7 @@
|
||||
"REDIS_CONF_TIPS4": "Max num of connections",
|
||||
"REDIS_CONF_TIPS5": "Number of databases",
|
||||
"REDIS_CONF_TIPS6": "redis password, leaving blank means no password is set",
|
||||
"REDIS_CONF_TIPS7": "MB, max memory usage, 0 means no limit",
|
||||
"REDIS_CONF_TIPS7": "MB, max RAM usage, 0 means no limit",
|
||||
"RDB_ERR": "Please enter an integer for the RDB parameter",
|
||||
"SYS_DB_CANT_DEL": "System database, cannot be deleted",
|
||||
"SAVE_CONF": "Configuration has been saved",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"T2":"Connection Manager",
|
||||
"T3":"Task Manager",
|
||||
"P1":"CPU Usage",
|
||||
"P2":"Memory Usage",
|
||||
"P2":"RAM Usage",
|
||||
"P3":"Release Memory",
|
||||
"P4":"Software",
|
||||
"NET1":"Network Traffic",
|
||||
@@ -80,7 +80,7 @@
|
||||
"TH1":"User",
|
||||
"TH2":"Password",
|
||||
"TH3":"Status",
|
||||
"TH4":"Root Directory",
|
||||
"TH4":"Document Root",
|
||||
"TH5":"Notes",
|
||||
"TH6":"Action",
|
||||
"JS1":"Pls Install Prue-Ftpd first!",
|
||||
@@ -143,7 +143,7 @@
|
||||
"CY2":"Suggested range of port: 8888 - 65535",
|
||||
"CY3":"Binding a Domain to bind Panel;Warning:If a domain is bound to Panel, you'll have to access panel with Domain ONLY!",
|
||||
"CY4":"Set Authorized Access IP,Using (,) to split multiple IP;Warning:If Authorized IP is set, ONLY the PC with Authorized IP can access the Panel!",
|
||||
"CY5":"New Created Site will be saved to Subdirectory by default!",
|
||||
"CY5":"New Created Site will be saved to subdirectory by default!",
|
||||
"CY6":"Directory of Site and Database Backup!",
|
||||
"CY7":"Defualt IP is Internet IP. If you need use local virtual machine to test, please input Intranet IP of virtual machine!",
|
||||
"CY8":"Sync",
|
||||
@@ -219,7 +219,7 @@
|
||||
"T1":"Task type",
|
||||
"T2":"Name of Task",
|
||||
"T3":"Period",
|
||||
"T4":"Script Content",
|
||||
"T4":"Script content",
|
||||
"T5":"Add Task",
|
||||
"TT1":"Shell Script",
|
||||
"TT2":"Backup Site",
|
||||
|
||||
@@ -111,12 +111,19 @@
|
||||
<span class="set-info c7" style="margin-left: 25px;">{{data['lan']['BASICAUTH_TIPS1']}}</span>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="Message channel">Message channel</span>
|
||||
<span class="set-tit text-right" title="Notification">Notification</span>
|
||||
<div class="btn_tips">
|
||||
<input id="channel_auth" name="channel_auth" class="inputtxt bt-input-text disable" type="text" value="" disabled>
|
||||
<span class="modify btn btn-xs btn-success channel_auth" style="margin-left: -38px;" onclick="open_three_channel_auth()">Set</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="Login panel alarm">Login panel alarm</span>
|
||||
<div class="btn_tips">
|
||||
<input id="panel_report" name="panel_report" class="inputtxt bt-input-text disable" type="text" value="" disabled>
|
||||
<span class="modify btn btn-xs btn-success panel_report" onclick="set_panel_report()">Set</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT3']}}">{{data['lan']['CT3']}}</span>
|
||||
<input name="domain" class="inputtxt bt-input-text" type="text" value="{{data['panel']['domain']}}">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<button type="submit" class="path_btn"><i class="iconfont icon-search"></i></button>
|
||||
<div class="file_search_config">
|
||||
<div id="search_all" class="file_search_checked"></div>
|
||||
<label for="search_all">Include SubDir</label>
|
||||
<label for="search_all">Include subdir</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,6 +55,7 @@
|
||||
<ul class="nav_down_list" data-menu="newFileType">
|
||||
<li data-type="newBlankDir"><i class="file_menu_icon create_file_icon"></i><span>New directory</span></li>
|
||||
<li data-type="newBlankFile"><i class="file_new_icon"></i><span>New blank file</span></li>
|
||||
<li data-type="newBlankFile"><i class="file_new_icon soft_link_file_icon"></i><span>Softlink</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -78,13 +78,6 @@
|
||||
<div class="position f14 c9 pull-left">
|
||||
<a class="plr10 c4" href="/">{{data['lan']['H1']}}</a>/<span class="plr10 c4">{{data['lan']['H2']}}</span>
|
||||
</div>
|
||||
<div class="search pull-right">
|
||||
<form target="hid" onsubmit='firewall.get_log_list(1,$("#SearchValue").prop("value"))'>
|
||||
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="{{data['lan']['SEARCH']}}" />
|
||||
<button type="button" class="ser-sub pull-left" onclick='firewall.get_log_list(1,$("#SearchValue").prop("value"))'></button>
|
||||
</form>
|
||||
<iframe name='hid' id="hid" style="display:none"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<div class="safe container-fluid bgw mtb15 pd15">
|
||||
<div class="mr50 pull-left">
|
||||
@@ -149,10 +142,17 @@
|
||||
<div class="white-black-ip bgw mtb15">
|
||||
<div class="black-ip">
|
||||
<div class="def-log">
|
||||
<div class="title c6 plr15">
|
||||
<h3 class="f16">{{data['lan']['H4']}}</h3>
|
||||
<a class="btn btn-default btn-sm va0" onclick="bt.firewall.clear_logs(function(){firewall.get_log_list()});">{{data['lan']['BTN5']}}</a>
|
||||
<span class="btn btn-default btn-sm" style="position: absolute;right: 30px;margin-top: 10px;" onclick="firewall.get_panel_error_logs()">{{data['lan']['PANEL_LOG']}}</span>
|
||||
<div class="tootls_group" style="height: 40px;">
|
||||
<div class="pull-right">
|
||||
<div class="bt_search" style="margin-top: 10px;margin-right: 15px;">
|
||||
<input type="text" style="width:260px" class="search_input" placeholder="Please enter a keyword search log"><span onclick="firewall.on_search()" class="glyphicon glyphicon-search" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title c6 plr15">
|
||||
<h3 class="f16">{{data['lan']['H4']}}</h3>
|
||||
<a class="btn btn-default btn-sm va0" onclick="bt.firewall.clear_logs(function(){firewall.get_log_list()});">{{data['lan']['BTN5']}}</a>
|
||||
<span class="btn btn-default btn-sm" style="margin-top: 10px;" onclick="firewall.get_panel_error_logs()">{{data['lan']['PANEL_LOG']}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divtable pd15">
|
||||
<div class="tablescroll">
|
||||
@@ -175,7 +175,10 @@
|
||||
|
||||
var firewall = {
|
||||
ssl_scanning_list: [], //扫描列表
|
||||
get_init:function(){
|
||||
on_search:function(){
|
||||
firewall.get_log_list(1,$('.search_input').val());
|
||||
},
|
||||
get_init:function(){
|
||||
firewall.flush_init();
|
||||
firewall.get_list();
|
||||
firewall.get_log_list();
|
||||
|
||||
@@ -1,6 +1,73 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<style>
|
||||
.chart-box{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.rank{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 16.5%;
|
||||
color: #999;
|
||||
line-height: 30px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.chart-li{
|
||||
width: 105px;
|
||||
height: 105px;
|
||||
position: relative;
|
||||
}
|
||||
.chart-li canvas{
|
||||
cursor: pointer;
|
||||
}
|
||||
.mem_mask{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: rgba(220,220,220,.1);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mem_mask .men_inside_mask{
|
||||
position: absolute;
|
||||
left: 7px;
|
||||
top: 7px;
|
||||
bottom: 7px;
|
||||
right: 7px;
|
||||
background: rgba(255,255,255,0.8);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.info-status{
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.outerCircle{
|
||||
width: 105px;
|
||||
height: 105px;
|
||||
text-align: center;
|
||||
background-color: #e5e5e5;
|
||||
border-radius: 50%;
|
||||
padding: 7px;
|
||||
}
|
||||
.outerCircle .innerCircle{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: 91px;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
font-size: 17px;
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
||||
<div class="main-content">
|
||||
<div class="index-pos-box bgw">
|
||||
<div class="position f12 c6 pull-left" style="background:none;padding-left:15px">
|
||||
@@ -16,7 +83,8 @@
|
||||
<span class="ico-system">{{data['lan']['S1']}}</span><span id="info" style="margin-left:10px;"> {{data['lan']['S2']}}</span>  {{data['lan']['S3']}} <span id="running">{{data['lan']['S4']}}</span>
|
||||
</div>
|
||||
<span class="pull-right f12 c6" style="line-height:52px; margin-right:15px">
|
||||
<!--{{data['pd']|safe}}--> <span id="btversion" style="margin-right:10px">{{session['version']}}</span>
|
||||
{{data['pd']|safe}}
|
||||
<span id="btversion" style="margin-right:10px">{{session['version']}}</span>
|
||||
<span id="toUpdate"><a class="btlink" href="javascript:index.check_update();">{{data['lan']['UPDATE']}}</a></span>
|
||||
<span style="margin:0 10px"><a class="btlink" href="javascript:index.re_panel();">{{data['lan']['FIX']}}</a></span>
|
||||
<span style="margin-right:10px"><a class="btlink" href="javascript:index.re_server();">{{data['lan']['RESTART']}}</a></span>
|
||||
@@ -31,7 +99,7 @@
|
||||
<h3 class="c6 f16 pull-left">{{data['lan']['STATUS']}}</h3>
|
||||
</div>
|
||||
<div class="server-circle">
|
||||
<ul class="row" id="systemInfoList">
|
||||
<!-- <ul class="row" id="systemInfoList">
|
||||
<li class="col-xs-6 col-sm-3 col-md-3 col-lg-2 mtb20 circle-box text-center loadbox">
|
||||
<h3 class="c9 f15">{{data['lan']['LOAD_STATUS']}}<a href="https://forum.aapanel.com/d/1265-what-does-the-data-in-load-status-represent" target="_blank" class="bt-ico-ask" style="cursor: pointer;">?</a></h3>
|
||||
<div class="cicle">
|
||||
@@ -73,7 +141,33 @@
|
||||
</div>
|
||||
<h4 class="c9 f15">{{data['lan']['S2']}}</h4>
|
||||
</li>
|
||||
</ul>
|
||||
</ul> -->
|
||||
<ul class="row" id="systemInfoList">
|
||||
<li class="rank col-xs-6 col-sm-3 col-md-3 col-lg-2 mtb20 circle-box text-center">
|
||||
<div class="titles">
|
||||
<span>{{data['lan']['LOAD_STATUS']}}</span>
|
||||
<a href="https://forum.aapanel.com/d/1265-what-does-the-data-in-load-status-represent" target="_blank" class="bt-ico-ask" style="cursor: pointer;">?</a>
|
||||
</div>
|
||||
<div id="loadChart" class="chart-li">
|
||||
<div class="outerCircle"><div class="innerCircle">0%</div></div>
|
||||
</div>
|
||||
<div id="load" class="info-status">{{data['lan']['S2']}}</div>
|
||||
</li>
|
||||
<li class="rank col-xs-6 col-sm-3 col-md-3 col-lg-2 mtb20 circle-box text-center">
|
||||
<div class="titles">{{data['lan']['P1']}}</div>
|
||||
<div id="cpuChart" class="chart-li">
|
||||
<div class="outerCircle"><div class="innerCircle">0%</div></div>
|
||||
</div>
|
||||
<div id="cpu" class="info-status">{{data['lan']['S2']}}</div>
|
||||
</li>
|
||||
<li class="rank col-xs-6 col-sm-3 col-md-3 col-lg-2 mtb20 circle-box text-center">
|
||||
<div class="titles">{{data['lan']['P2']}}</div>
|
||||
<div id="memChart" class="chart-li">
|
||||
<div class="outerCircle"><div class="innerCircle">0%</div></div>
|
||||
</div>
|
||||
<div id="mem" class="info-status">{{data['lan']['S2']}}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="system-info bgw clearfix mtb15">
|
||||
@@ -115,20 +209,39 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-12 col-md-6 pull-left pd0">
|
||||
<div class="pl7">
|
||||
<div class="bgw" style="height:491px">
|
||||
<div class="title c6 f16 plr15">{{data['lan']['FLOW']}}<span class="pull-right"><select class="bt-input-text" name="network-io" style="font-size: 12px;"></select></span></div>
|
||||
<div class="bw-info">
|
||||
<div class="pl7">
|
||||
<div class="bgw" style="height:283.5px">
|
||||
<div class="title c6 f16 plr15 tabs-nav">
|
||||
<span class="active">{{data['lan']['FLOW']}}</span>
|
||||
<span>Disk IO</span>
|
||||
<div class="tabs-down">
|
||||
<select class="bt-input-text" name="network-io" style="font-size: 12px;"></select>
|
||||
<select class="bt-input-text hide" name="disk-io" style="font-size: 12px;"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
<div class="tabs-active tabs-item">
|
||||
<div class="bw-info">
|
||||
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-up"></span>{{data['lan']['UPLOAD']}}</p><a id="upSpeed">{{data['lan']['S2']}}</a></div>
|
||||
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-down"></span>{{data['lan']['DOWNLOAD']}}</p><a id="downSpeed">{{data['lan']['S2']}}</a></div>
|
||||
<div class="col-sm-6 col-md-3"><p class="c9">{{data['lan']['TOTAL_TX']}}</p><a id="upAll">{{data['lan']['S2']}}</a></div>
|
||||
<div class="col-sm-6 col-md-3"><p class="c9">{{data['lan']['TOTAL_RX']}}</p><a id="downAll">{{data['lan']['S2']}}</a></div>
|
||||
</div>
|
||||
<div id="NetImg" style="width:100%;height: 370px;"></div>
|
||||
</div>
|
||||
<div id="NetImg" style="width:100%;height:370px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-item">
|
||||
<div class="bw-info">
|
||||
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-read"></span>Read</p><a id="readBytes">{{data['lan']['S2']}}</a></div>
|
||||
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-write"></span>Write</p><a id="writeBytes">{{data['lan']['S2']}}</a></div>
|
||||
<div class="col-sm-6 col-md-3"><p class="c9">TPS</p><a id="diskIops">{{data['lan']['S2']}}</a></div>
|
||||
<div class="col-sm-6 col-md-3"><p class="c9">IO Wait</p><a id="diskTime">{{data['lan']['S2']}}</a></div>
|
||||
</div>
|
||||
<div id="IoStat" style="width:100%;height: 370px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -143,7 +256,7 @@
|
||||
<script type="text/javascript" src="/static/js/soft.js?version_20191219={{g['version']}}"></script>
|
||||
<script type="text/javascript" src="/static/ace/ace.js?date={{g.version}}"></script>
|
||||
<script type="text/javascript">
|
||||
$(".btpro").click(function(){
|
||||
$(".btpro span").click(function(){
|
||||
layer.confirm(lan.index.change_free, { icon: 3, btn: [lan.index.ubind], closeBtn: 2, title: lan.index.confirm_cancel }, function () {
|
||||
$.post('/ssl?action=DelToken', {}, function (rdata) {
|
||||
layer.msg(rdata.msg);
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
<div class="footer bgw">{{session['brand']}}{{session['product']}} ©2014-{{session['yaer']}} {{session['brand']}} (bt.cn)
|
||||
<!--<a style="margin-left:20px;color:#20a53a;" href="http://www.bt.cn/bbs" target="_blank">求助|建议请上宝塔论坛</a>-->
|
||||
<a style="margin-left:20px;color:#20a53a;" href="http://forum.aapanel.com" target="_blank">{{session['bt_help']}}</a>
|
||||
<a style="margin-left:20px;color:#20a53a;" href="https://doc.aapanel.com/web/#/3?page_id=117" target="_blank">User manual</a>
|
||||
<a style="margin-left:20px;color:#20a53a;" href="https://doc.aapanel.com/web/#/3?page_id=117" target="_blank">Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{g.cdn_url}}/js/jquery-1.10.2.min.js"></script>
|
||||
|
||||
@@ -1,539 +1,323 @@
|
||||
<!doctype html>
|
||||
<html lang="zh">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/favicon.ico" type="image/x-icon" />
|
||||
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
|
||||
<title>{{g.title}}</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/site.css?date={{g.version}}">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/login.css?date={{g.version}}">
|
||||
<script type="text/javascript">
|
||||
function IEVersion() {
|
||||
// 取得浏览器的userAgent字符串
|
||||
var userAgent = navigator.userAgent;
|
||||
// 判断是否为小于IE11的浏览器
|
||||
var isLessIE11 = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1;
|
||||
// 判断是否为IE的Edge浏览器
|
||||
var isEdge = userAgent.indexOf('Edge') > -1 && !isLessIE11;
|
||||
// 判断是否为IE11浏览器
|
||||
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
|
||||
if (isLessIE11) {
|
||||
var IEReg = new RegExp('MSIE (\\d+\\.\\d+);');
|
||||
// 正则表达式匹配浏览器的userAgent字符串中MSIE后的数字部分,,这一步不可省略!!!
|
||||
IEReg.test(userAgent);
|
||||
// 取正则表达式中第一个小括号里匹配到的值
|
||||
var IEVersionNum = parseFloat(RegExp['$1']);
|
||||
if (IEVersionNum === 7) {// IE7
|
||||
return 7
|
||||
} else if (IEVersionNum === 8) {// IE8
|
||||
return 8
|
||||
} else if (IEVersionNum === 9) {// IE9
|
||||
return 9
|
||||
} else if (IEVersionNum === 10) { // IE10
|
||||
return 10
|
||||
} else {// IE版本<7
|
||||
return 6
|
||||
}
|
||||
} else if (isEdge) { // edge
|
||||
|
||||
return 'edge'
|
||||
} else if (isIE11) {// IE11
|
||||
return 11
|
||||
} else {// 不是ie浏览器
|
||||
return -1
|
||||
}
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="icon" href="/static/favicon.ico" type="image/x-icon" />
|
||||
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
|
||||
<title>{{g.title}}</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/site.css?date={{g.version}}">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/login.css?date={{g.version}}">
|
||||
<script type="text/javascript">
|
||||
function IEVersion() {
|
||||
// 取得浏览器的userAgent字符串
|
||||
var userAgent = navigator.userAgent;
|
||||
// 判断是否为小于IE11的浏览器
|
||||
var isLessIE11 = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1;
|
||||
// 判断是否为IE的Edge浏览器
|
||||
var isEdge = userAgent.indexOf('Edge') > -1 && !isLessIE11;
|
||||
// 判断是否为IE11浏览器
|
||||
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
|
||||
if (isLessIE11) {
|
||||
var IEReg = new RegExp('MSIE (\\d+\\.\\d+);');
|
||||
// 正则表达式匹配浏览器的userAgent字符串中MSIE后的数字部分,,这一步不可省略!!!
|
||||
IEReg.test(userAgent);
|
||||
// 取正则表达式中第一个小括号里匹配到的值
|
||||
var IEVersionNum = parseFloat(RegExp['$1']);
|
||||
if (IEVersionNum === 7) { // IE7
|
||||
return 7
|
||||
} else if (IEVersionNum === 8) { // IE8
|
||||
return 8
|
||||
} else if (IEVersionNum === 9) { // IE9
|
||||
return 9
|
||||
} else if (IEVersionNum === 10) { // IE10
|
||||
return 10
|
||||
} else { // IE版本<7
|
||||
return 6
|
||||
}
|
||||
if(IEVersion() > -1 && IEVersion() < 9){
|
||||
window.location.href = '/tips';
|
||||
}
|
||||
</script>
|
||||
} else if (isEdge) { // edge
|
||||
|
||||
return 'edge'
|
||||
} else if (isIE11) { // IE11
|
||||
return 11
|
||||
} else { // 不是ie浏览器
|
||||
return -1
|
||||
}
|
||||
}
|
||||
if (IEVersion() > -1 && IEVersion() < 9) {
|
||||
window.location.href = '/tips';
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="login">
|
||||
<div class="account">
|
||||
<form class="loginform" method="post" action="/login" onsubmit="return false;">
|
||||
<div class="rlogo">{{g.title}}</div>
|
||||
<div class="line"><input class="inputtxt" value="" name="username" datatype="*" nullmsg="{{data['lan']['N1']}}" errormsg="{{data['lan']['N2']}}" placeholder="{{data['lan']['N3']}}" type="text"><div class="Validform_checktip"></div></div>
|
||||
<div class="line"><input class="inputtxt" name="password" value="" datatype="*" nullmsg="{{data['lan']['N4']}}" errormsg="{{data['lan']['N5']}}" placeholder="{{data['lan']['N6']}}" type="password"><div class="Validform_checktip"></div></div>
|
||||
<div style="color: red;position: relative;top: -14px;" id="errorStr"></div>
|
||||
<div class="line yzm" style="top: -5px;
|
||||
{% if not session['code'] %}
|
||||
display:none;
|
||||
{% endif %}
|
||||
">
|
||||
<input type="text" class="inputtxt" name="code" nullmsg="{{data['lan']['N7']}}" errormsg="{{data['lan']['N8']}}" datatype="*" placeholder="{{data['lan']['N9']}}">
|
||||
<div class="Validform_checktip"></div>
|
||||
<img width="100" height="40" class="passcode" onClick="this.src=this.src.split('?')[0] + '?'+new Date().getTime()" src="/code" style="border: 1px solid #ccc; float: right;" title="{{data['lan']['N10']}}">
|
||||
</div>
|
||||
<div class="login_btn"><input id="login-button" value="{{data['lan']['N11']}}" type="submit"></div>
|
||||
<p class="pwinfo" style="display:none">{{data['lan']['N12']}}</p>
|
||||
{% if data['hosts'] != '[]' %}
|
||||
<a class="static-cdn">
|
||||
<span class="span-tname">Acceleration node</span>
|
||||
<select name="cdn_url" id="static_cdn">
|
||||
<option value="localhost">Counting...</option>
|
||||
</select>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="resetpw" href="https://forum.aapanel.com/d/16-how-to-reset-password-for-aapanel-linux-6-x" target="_blank">{{data['lan']['N13']}}</a>
|
||||
</form>
|
||||
</div>
|
||||
<div class="scanCode" style="display: none;">
|
||||
<div class="titles"><span>{{data['lan']['QR_CORE_LOGIN']}}</span></div>
|
||||
<div class="qrCode" id="qrcode"></div>
|
||||
<div class="scanTip">
|
||||
<div class="list_scan">
|
||||
<img src="/static/img/sCan.png" />
|
||||
<span>
|
||||
{{data['lan']['OPEN']}}
|
||||
<a href="javascript:;" class="btlink">
|
||||
{{data['lan']['BT_SMALL_P']}}
|
||||
<div class="weChatSamll"><img src="https://app.bt.cn/static/app.png"><em></em></div>
|
||||
</a>
|
||||
</span>
|
||||
<span>{{data['lan']['SCAN_LOGIN']}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="entrance" style="display: none;">
|
||||
<div class="bg_img"></div>
|
||||
<div class="tips">
|
||||
<span><img src="/static/img/safety_ico.png"><span>{{data['lan']['SCAN_MORE_SAFETY']}}</span></span>
|
||||
<em></em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main">
|
||||
<div class="login">
|
||||
<div class="account">
|
||||
<form class="loginform" method="post" action="/login" onsubmit="return false;">
|
||||
<div class="rlogo">{{g.title}}</div>
|
||||
<div class="line"><input class="inputtxt" value="" name="username" datatype="*"
|
||||
nullmsg="{{data['lan']['N1']}}" errormsg="{{data['lan']['N2']}}" placeholder="{{data['lan']['N3']}}"
|
||||
type="text">
|
||||
<div class="Validform_checktip"></div>
|
||||
</div>
|
||||
<div class="line"><input class="inputtxt" name="password" value="" datatype="*"
|
||||
nullmsg="{{data['lan']['N4']}}" errormsg="{{data['lan']['N5']}}" placeholder="{{data['lan']['N6']}}"
|
||||
type="password">
|
||||
<div class="Validform_checktip"></div>
|
||||
</div>
|
||||
<div style="color: red;position: relative;top: -14px;" id="errorStr"></div>
|
||||
<div class="line yzm" style="top: -5px;{% if not session['code'] %}display:none;{% endif %}">
|
||||
<input type="text" class="inputtxt" name="code" nullmsg="{{data['lan']['N7']}}"
|
||||
errormsg="{{data['lan']['N8']}}" datatype="*" placeholder="{{data['lan']['N9']}}">
|
||||
<div class="Validform_checktip"></div>
|
||||
<img width="100" height="40" class="passcode"
|
||||
onClick="this.src=this.src.split('?')[0] + '?'+new Date().getTime()" src="/code"
|
||||
style="border: 1px solid #ccc; float: right;" title="{{data['lan']['N10']}}">
|
||||
</div>
|
||||
<div class="login_btn"><input id="login-button" value="{{data['lan']['N11']}}" type="submit"></div>
|
||||
<p class="pwinfo" style="display:none">{{data['lan']['N12']}}</p>
|
||||
{% if data['hosts'] != '[]' %}
|
||||
<a class="static-cdn">
|
||||
<span class="span-tname">Acceleration node</span>
|
||||
<select name="cdn_url" id="static_cdn">
|
||||
<option value="localhost">Counting...</option>
|
||||
</select>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="resetpw" href="https://forum.aapanel.com/d/16-how-to-reset-password-for-aapanel-linux-6-x"
|
||||
target="_blank">{{data['lan']['N13']}}</a>
|
||||
</form>
|
||||
</div>
|
||||
<div class="scanCode" style="display: none;">
|
||||
<div class="titles"><span>{{data['lan']['QR_CORE_LOGIN']}}</span></div>
|
||||
<div class="qrCode" id="qrcode"></div>
|
||||
<div class="scanTip">
|
||||
<div class="list_scan">
|
||||
<img src="/static/img/sCan.png" - />
|
||||
<span>{{data['lan']['SCAN_LOGIN']}}</span>
|
||||
<span><a href="https://forum.aapanel.com/d/3527-aapanel-mobile" class="btlink"
|
||||
target="_blank">{{data['lan']['BT_SMALL_P']}}</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="entrance" style="display: none;">
|
||||
<div class="bg_img"></div>
|
||||
<div class="tips">
|
||||
<span><img src="/static/img/safety_ico.png"><span>{{data['lan']['SCAN_MORE_SAFETY']}}</span></span>
|
||||
<em></em>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <script type="text/javascript" src="/static/js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="/static/language/zh-cn.js"></script>
|
||||
<script type="text/javascript" src="/static/layer/layer.js"></script>
|
||||
<script type="text/javascript" src="/static/js/jquery.qrcode.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/Validform_v5.3.2_min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/md5.js"></script>
|
||||
<script type="text/javascript">
|
||||
function Wreset() {
|
||||
var w = $(window).width();
|
||||
var yzmw = $(".login .line").width() - 140;
|
||||
if ($(".yzm").is(":visible") && w > 640) {
|
||||
$(".login").css({ "height": "365px", "margin-top": "-230px" });
|
||||
}
|
||||
else {
|
||||
$(".login").removeAttr("style")
|
||||
}
|
||||
$(".login .yzm .inputtxt").width(yzmw);
|
||||
</div>
|
||||
<script type="text/javascript" src="/static/js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="/static/language/zh-cn.js"></script>
|
||||
<script type="text/javascript" src="/static/layer/layer.js"></script>
|
||||
<script type="text/javascript" src="/static/js/jquery.qrcode.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/Validform_v5.3.2_min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/md5.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
function Wreset() {
|
||||
var w = $(window).width();
|
||||
var yzmw = $(".login .line").width() - 140;
|
||||
if ($(".yzm").is(":visible") && w > 640) {
|
||||
$(".login").css({
|
||||
"height": "365px",
|
||||
"margin-top": "-230px"
|
||||
});
|
||||
} else {
|
||||
$(".login").removeAttr("style")
|
||||
}
|
||||
$(function () {
|
||||
Wreset();
|
||||
var setTime = '';
|
||||
function controlTime() {
|
||||
$.get('/public?name=app&fun=is_scan_ok', function (res) {
|
||||
if (res.status) {
|
||||
layer.msg("{{data['lan']['SCAN_SUCCESS']}}", { icon: 1 });
|
||||
clearInterval(setTime);
|
||||
loginAdmin(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
function loginAdmin(key) {
|
||||
$.get('/public?name=app&fun=set_login', { secret_key: key }, function (res) {
|
||||
layer.msg(res.msg, { icon: res.status ? 1 : 2 })
|
||||
if (res.status) {
|
||||
layer.msg("{{data['lan']['SAFE_LOGGING_NOW']}}", { time: 0, shade: [0.4, '#fff'], icon: 16 });
|
||||
setTimeout(function () {
|
||||
location.href = '/';
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
$('.bg_img').click(function (event) {
|
||||
if ($(this).hasClass('pc')) {
|
||||
$(this).removeClass('pc');
|
||||
$('.scanCode').hide().prev().show();
|
||||
clearInterval(setTime);
|
||||
$('.tips>span>span').html("{{data['lan']['SCAN_MORE_SAFETY']}}");
|
||||
} else {
|
||||
$(this).addClass('pc');
|
||||
$('.account').hide().next().show();
|
||||
$('.tips>span>span').html("{{data['lan']['USER_LOGIN']}}");
|
||||
setTime = window.setInterval(controlTime, 2000);
|
||||
}
|
||||
});
|
||||
})
|
||||
window.onresize = function () {
|
||||
Wreset();
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$(".loginform").Validform({
|
||||
tiptype: function (msg, o, cssctl) {
|
||||
if (!o.obj.is("form")) {
|
||||
var objtip = o.obj.siblings(".Validform_checktip");
|
||||
cssctl(objtip, o.type);
|
||||
objtip.text(msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
$(".login .yzm .inputtxt").width(yzmw);
|
||||
}
|
||||
Wreset();
|
||||
var setTime = '';
|
||||
$.get('/public?name=app&fun=login_qrcode', function (res) {
|
||||
$('#qrcode').qrcode({
|
||||
render: "canvas",
|
||||
width: 150,
|
||||
height: 150,
|
||||
background: "#fefefe",
|
||||
foreground: "#333",
|
||||
text: res.status ? res.msg : 'https://aapanel.com/download/app.html'
|
||||
});
|
||||
$('.entrance').show();
|
||||
}).error(function (res, textStatus, errorThrown) {
|
||||
if (res.status == 404) {
|
||||
$('.entrance').hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('#login-button').click(function () {
|
||||
var username = $("input[name='username']").val();
|
||||
var password = $("input[name='password']").val();
|
||||
var code = $("input[name='code']").val();
|
||||
if (username == '' || password == '') {
|
||||
layer.msg("{{data['lan']['FORM_ERR']}}", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
function controlTime() {
|
||||
$.get('/public?name=app&fun=is_scan_ok', function (res) {
|
||||
if (res.status) {
|
||||
layer.msg('Scanning code succeeded, waiting...', {
|
||||
icon: 1
|
||||
});
|
||||
clearInterval(setTime);
|
||||
loginAdmin(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var data = { username: username, password: md5(md5(password) + '' + '_bt.cn'), code: code }
|
||||
var loadT = layer.msg("{{data['lan']['JS2']}}", { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
$.post('/login', data, function (rdata) {
|
||||
if(rdata == '1'){
|
||||
layer.close(loadT);
|
||||
layer.open({
|
||||
type:1,
|
||||
title:false,
|
||||
area: ['350px', '285px'],
|
||||
content:'<div class="verification_view">\
|
||||
function loginAdmin(key) {
|
||||
$.get('/public?name=app&fun=set_login', {
|
||||
secret_key: key
|
||||
}, function (res) {
|
||||
layer.msg(res.msg, {
|
||||
icon: res.status ? 1 : 2
|
||||
})
|
||||
if (res.status) {
|
||||
layer.msg('Secure login in progress,waiting...', {
|
||||
time: 0,
|
||||
shade: [0.4, '#fff'],
|
||||
icon: 16
|
||||
});
|
||||
setTimeout(function () {
|
||||
location.href = '/';
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
$(".loginform").Validform({
|
||||
tiptype: function (msg, o, cssctl) {
|
||||
if (!o.obj.is("form")) {
|
||||
var objtip = o.obj.siblings(".Validform_checktip");
|
||||
cssctl(objtip, o.type);
|
||||
objtip.text(msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
$('.bg_img').click(function (event) {
|
||||
if ($(this).hasClass('pc')) {
|
||||
$(this).removeClass('pc');
|
||||
$('.scanCode').hide().prev().show();
|
||||
clearInterval(setTime);
|
||||
$('.tips>span').html('<img src="/static/img/scan_ico.png"><span>Login with aaPanel mobile</span>');
|
||||
} else {
|
||||
$(this).addClass('pc');
|
||||
$('.account').hide().next().show();
|
||||
$('.tips>span').html('<img src="/static/img/safety_ico.png"><span>Switch account login</span>')
|
||||
setTime = window.setInterval(controlTime, 2000);
|
||||
}
|
||||
});
|
||||
$('#login-button').click(function () {
|
||||
var username = $("input[name='username']").val().trim();
|
||||
var password = $("input[name='password']").val().trim();
|
||||
var code = $("input[name='code']").val().trim();
|
||||
|
||||
if (username == '' || password == '') {
|
||||
layer.msg("{{data['lan']['JS1']}}", {
|
||||
icon: 2
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var data = {
|
||||
username: md5(username),
|
||||
password: md5(md5(password) + '' + '_bt.cn'),
|
||||
code: code,
|
||||
cdn_url: $("#static_cdn").val()
|
||||
}
|
||||
var loadT = layer.msg("{{data['lan']['JS2']}}", {
|
||||
icon: 16,
|
||||
time: 0,
|
||||
shade: [0.3, '#000']
|
||||
});
|
||||
$.post('/login', data, function (rdata) {
|
||||
if (rdata == '1') {
|
||||
layer.close(loadT);
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: false,
|
||||
area: ['350px', '265px'],
|
||||
content: '<div class="verification_view">\
|
||||
<div class="v_title">Google authentication</div>\
|
||||
<div class="v_input"><input type="text" class="v_code" name="v_code" placeholder="Verification code"/></div>\
|
||||
<div class="v_btn"><input id="auth_verif_btn" value="log in" type="submit"></div>\
|
||||
<div class="v_tips">* Please use the Google Authenticator app to get the verification code.<br>\
|
||||
<a target="_blank" href="https://forum.aapanel.com/d/357-how-to-use-google-authenticator-in-the-aapanel" class="btlink">Unable to verify, click help</a></div>\
|
||||
<div class="v_btn"><input id="auth_verif_btn" value="Log in" type="submit"></div>\
|
||||
<div class="v_tips">* Please use the Google Authenticator app to get the verification code<br><a target="_blank" href="https://forum.aapanel.com/d/357-how-to-use-google-authenticator-in-the-aapanel" class="btlink">Unable to verify, click Help</a></div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
// 点击验证登录
|
||||
$('[name="v_code"]').keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
$('#auth_verif_btn').click();
|
||||
}
|
||||
});
|
||||
$('#auth_verif_btn').click(function(e){
|
||||
data['vcode'] = $('[name="v_code"]').val();
|
||||
var loadT = layer.msg("{{data['lan']['JS2']}}", { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
$.post('/login', data, function (rdata) {
|
||||
layer.close(loadT);
|
||||
if(!rdata.status){
|
||||
layer.msg(rdata.msg, { icon: 2 });
|
||||
return false;
|
||||
}
|
||||
layer.msg(rdata.msg, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
window.location.href = '/';
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
layer.close(loadT);
|
||||
if (!rdata.status) {
|
||||
$("#errorStr").html(rdata.msg);
|
||||
$("input[name='password']").val('');
|
||||
num = rdata.msg.substring(rdata.msg.indexOf('[') + 1, rdata.msg.indexOf(']'));
|
||||
if (num < 5) {
|
||||
$(".yzm").show();
|
||||
$(".login").css("height", "332px");
|
||||
$("input[name='code']").val('');
|
||||
success: function () {
|
||||
// 点击验证登录
|
||||
$('[name="v_code"]').keyup(function (e) {
|
||||
if (e.keyCode == 13) {
|
||||
$('#auth_verif_btn').click();
|
||||
}
|
||||
});
|
||||
$('#auth_verif_btn').click(function (e) {
|
||||
data['vcode'] = $('[name="v_code"]').val().trim();
|
||||
var loadT = layer.msg("{{data['lan']['JS2']}}", {
|
||||
icon: 16,
|
||||
time: 0,
|
||||
shade: [0.3, '#000']
|
||||
});
|
||||
$.post('/login', data, function (rdata) {
|
||||
layer.close(loadT);
|
||||
if (!rdata.status) {
|
||||
layer.msg(rdata.msg, {
|
||||
icon: 2
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$(".yzm").show();
|
||||
Wreset();
|
||||
$(".passcode").click();
|
||||
layer.msg(rdata.msg, { icon: 2 });
|
||||
return;
|
||||
}
|
||||
|
||||
layer.msg(rdata.msg, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
window.location.href = '/';
|
||||
layer.msg(rdata.msg, {
|
||||
icon: 16,
|
||||
time: 0,
|
||||
shade: [0.3, '#000']
|
||||
});
|
||||
window.location.href = '/';
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
layer.close(loadT);
|
||||
if (!rdata.status) {
|
||||
$("#errorStr").html(rdata.msg);
|
||||
$("input[name='password']").val('');
|
||||
num = rdata.msg.substring(rdata.msg.indexOf('[') + 1, rdata.msg.indexOf(']'))
|
||||
if (num < 5) {
|
||||
$(".yzm").show();
|
||||
$(".login").css("height", "332px");
|
||||
$("input[name='code']").val('');
|
||||
}
|
||||
$(".yzm").show();
|
||||
Wreset();
|
||||
$(".passcode").click();
|
||||
layer.msg(rdata.msg, {
|
||||
icon: 2
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.msg(rdata.msg, {
|
||||
icon: 16,
|
||||
time: 0,
|
||||
shade: [0.3, '#000']
|
||||
});
|
||||
window.location.href = '/';
|
||||
});
|
||||
});
|
||||
if ("{{data['app_login']}}" == 'True') {
|
||||
$('.bg_img').addClass('pc');
|
||||
$('.account').hide().next().show();
|
||||
$('.tips>span').html('<img src="/static/img/safety_ico.png"><span>Switch account login</span>')
|
||||
setTime = window.setInterval(controlTime, 2000);
|
||||
}
|
||||
$(window).on('resize', function () {
|
||||
Wreset();
|
||||
})
|
||||
})
|
||||
|
||||
</script> -->
|
||||
<script type="text/javascript">
|
||||
|
||||
if(typeof(String.prototype.trim) === "undefined"){
|
||||
String.prototype.trim = function()
|
||||
{
|
||||
return String(this).replace(/^\s+|\s+$/g, '');
|
||||
};
|
||||
}
|
||||
|
||||
select_host = {
|
||||
hosts: {{data.hosts|safe}},
|
||||
my_hosts : {},
|
||||
bt_version:"{{g.version}}",
|
||||
request:function(url){
|
||||
var s_time = Date.now();
|
||||
var to_url = window.location.protocol + '//' + url + '/test.txt?time=' + s_time
|
||||
http_request = new XMLHttpRequest();
|
||||
http_request.open('GET', to_url, true);
|
||||
http_request.setRequestHeader("Content-type","text/plain");
|
||||
http_request.send();
|
||||
http_request.onreadystatechange = function (e) {
|
||||
if (e.srcElement.readyState == 4 && e.srcElement.status == 200) {
|
||||
if(e.srcElement.responseText === 'true'){
|
||||
var e_time = Date.now();
|
||||
select_host.my_hosts[url] = e_time - s_time
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
run:function(){
|
||||
for(var i=0;i<select_host.hosts.length;i++){
|
||||
select_host.request(select_host.hosts[i].url);
|
||||
}
|
||||
},
|
||||
compare:function (prop) {
|
||||
return function (obj1, obj2) {
|
||||
var val1 = obj1[prop];
|
||||
var val2 = obj2[prop];
|
||||
if (!isNaN(Number(val1)) && !isNaN(Number(val2))) {
|
||||
val1 = Number(val1);
|
||||
val2 = Number(val2);
|
||||
}
|
||||
if (val1 < val2) {
|
||||
return -1;
|
||||
} else if (val1 > val2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
select_host.run();
|
||||
setTimeout(function(){
|
||||
if(select_host.hosts.length > 0){
|
||||
var my_keys = Object.keys(select_host.my_hosts);
|
||||
var host_data = [];
|
||||
for(var i=0;i<select_host.hosts.length;i++){
|
||||
if(my_keys.indexOf(select_host.hosts[i].url) == -1) continue;
|
||||
select_host.hosts[i].speed = select_host.my_hosts[select_host.hosts[i].url];
|
||||
host_data.push(select_host.hosts[i]);
|
||||
}
|
||||
host_data = host_data.sort(select_host.compare('speed'));
|
||||
var cdn_option = '';
|
||||
for(var i=0;i<host_data.length;i++){
|
||||
cdn_option += '<option value="'+host_data[i].url+'">'+host_data[i].name + '('+ host_data[i].speed +'ms)' +'</option>';
|
||||
}
|
||||
|
||||
document.getElementById('static_cdn').innerHTML = cdn_option;
|
||||
|
||||
var host_url = "";
|
||||
if(host_data.length > 0){
|
||||
host_url = window.location.protocol + '//' + host_data[0].url;
|
||||
}
|
||||
if(!host_url) select_host.bt_version = "static";
|
||||
if(!host_url){
|
||||
document.getElementById('static_cdn').innerHTML = '<option value="local">This server</option>';
|
||||
}
|
||||
|
||||
}else{
|
||||
host_url = "";
|
||||
select_host.bt_version = "static";
|
||||
}
|
||||
|
||||
|
||||
function loadJs(urls,i,callback){
|
||||
i++;
|
||||
var script=document.createElement('script');
|
||||
script.type="text/javascript";
|
||||
if(typeof(callback)!="undefined"){
|
||||
if(script.readyState){
|
||||
script.onreadystatechange=function(){
|
||||
if(script.readyState == "loaded" || script.readyState == "complete"){
|
||||
script.onreadystatechange=null;
|
||||
if(i==urls.length){
|
||||
callback();
|
||||
}else{
|
||||
loadJs(urls,i,callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
script.onload=function(){
|
||||
if(i==urls.length){
|
||||
callback();
|
||||
}else{
|
||||
loadJs(urls,i,callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
script.src=urls[i-1];
|
||||
document.body.appendChild(script);
|
||||
|
||||
}
|
||||
my_urls = [
|
||||
host_url+'/'+select_host.bt_version+'/js/jquery-1.10.2.min.js',
|
||||
host_url+'/'+select_host.bt_version+'/js/Validform_v5.3.2_min.js',
|
||||
host_url+'/'+select_host.bt_version+'/js/md5.js',
|
||||
host_url+'/'+select_host.bt_version+'/js/jquery.qrcode.min.js',
|
||||
host_url+'/'+select_host.bt_version+'/layer/layer.js',
|
||||
host_url+'/'+select_host.bt_version+'/language/zh-cn.js'
|
||||
];
|
||||
|
||||
loadJs(my_urls,0,run);
|
||||
},200);
|
||||
function run(){
|
||||
function Wreset() {
|
||||
var w = $(window).width();
|
||||
var yzmw = $(".login .line").width() - 140;
|
||||
if ($(".yzm").is(":visible") && w > 640) {
|
||||
$(".login").css({ "height": "365px", "margin-top": "-230px" });
|
||||
}
|
||||
else {
|
||||
$(".login").removeAttr("style")
|
||||
}
|
||||
$(".login .yzm .inputtxt").width(yzmw);
|
||||
}
|
||||
$(function () {
|
||||
Wreset();
|
||||
var setTime = '';
|
||||
// $.get('/public?name=app&fun=login_qrcode', function (res) {
|
||||
// if (res.status) {
|
||||
// $('#qrcode').qrcode({
|
||||
// render: "canvas",
|
||||
// width: 150,
|
||||
// height: 150,
|
||||
// background: "#fefefe",
|
||||
// foreground: "#333",
|
||||
// text: res.msg
|
||||
// });
|
||||
// $('.entrance').show();
|
||||
// }
|
||||
// }).error(function (res, textStatus, errorThrown) {
|
||||
// if (res.status == 404) {
|
||||
// $('.entrance').hide();
|
||||
// }
|
||||
// });
|
||||
function controlTime() {
|
||||
$.get('/public?name=app&fun=is_scan_ok', function (res) {
|
||||
if (res.status) {
|
||||
layer.msg('Scanning code succeeded, waiting...', { icon: 1 });
|
||||
clearInterval(setTime);
|
||||
loginAdmin(res.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
function loginAdmin(key) {
|
||||
$.get('/public?name=app&fun=set_login', { secret_key: key }, function (res) {
|
||||
layer.msg(res.msg, { icon: res.status ? 1 : 2 })
|
||||
if (res.status) {
|
||||
layer.msg('Secure login in progress,waiting...', { time: 0, shade: [0.4, '#fff'], icon: 16 });
|
||||
setTimeout(function () {
|
||||
location.href = '/';
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
$('.bg_img').click(function (event) {
|
||||
if ($(this).hasClass('pc')) {
|
||||
$(this).removeClass('pc');
|
||||
$('.scanCode').hide().prev().show();
|
||||
clearInterval(setTime);
|
||||
$('.tips>span').html('<img src="/static/img/scan_ico.png"><span>Switch code scanning login</span>');
|
||||
} else {
|
||||
$(this).addClass('pc');
|
||||
$('.account').hide().next().show();
|
||||
$('.tips>span').html('<img src="/static/img/safety_ico.png"><span>Switch account login</span>')
|
||||
setTime = window.setInterval(controlTime, 2000);
|
||||
}
|
||||
});
|
||||
if("{{data['app_login']}}" == 'True'){
|
||||
$('.bg_img').addClass('pc');
|
||||
$('.account').hide().next().show();
|
||||
$('.tips>span').html('<img src="/static/img/safety_ico.png"><span>Switch account login</span>')
|
||||
setTime = window.setInterval(controlTime, 2000);
|
||||
}
|
||||
})
|
||||
window.onresize = function () {
|
||||
Wreset();
|
||||
}
|
||||
$(function () {
|
||||
$(".loginform").Validform({
|
||||
tiptype: function (msg, o, cssctl) {
|
||||
if (!o.obj.is("form")) {
|
||||
var objtip = o.obj.siblings(".Validform_checktip");
|
||||
cssctl(objtip, o.type);
|
||||
objtip.text(msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#login-button').click(function () {
|
||||
var username = $("input[name='username']").val().trim();
|
||||
var password = $("input[name='password']").val().trim();
|
||||
var code = $("input[name='code']").val().trim();
|
||||
|
||||
if (username == '' || password == '') {
|
||||
layer.msg("{{data['lan']['JS1']}}", { icon: 2 });
|
||||
return;
|
||||
}
|
||||
|
||||
var data = { username: md5(username), password: md5(md5(password) + '' + '_bt.cn'), code: code,cdn_url:$("#static_cdn").val() }
|
||||
var loadT = layer.msg("{{data['lan']['JS2']}}", { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
$.post('/login', data, function (rdata) {
|
||||
if(rdata == '1'){
|
||||
layer.close(loadT);
|
||||
layer.open({
|
||||
type:1,
|
||||
title:false,
|
||||
area: ['350px', '265px'],
|
||||
content:'<div class="verification_view">\
|
||||
<div class="v_title">Google authentication</div>\
|
||||
<div class="v_input"><input type="text" class="v_code" name="v_code" placeholder="Verification code"/></div>\
|
||||
<div class="v_btn"><input id="auth_verif_btn" value="Log in" type="submit"></div>\
|
||||
<div class="v_tips">* Please use the Google Authenticator app to get the verification code<br><a target="_blank" href="https://forum.aapanel.com/d/357-how-to-use-google-authenticator-in-the-aapanel" class="btlink">Unable to verify, click Help</a></div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
// 点击验证登录
|
||||
$('[name="v_code"]').keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
$('#auth_verif_btn').click();
|
||||
}
|
||||
});
|
||||
$('#auth_verif_btn').click(function(e){
|
||||
data['vcode'] = $('[name="v_code"]').val().trim();
|
||||
var loadT = layer.msg("{{data['lan']['JS2']}}", { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
$.post('/login', data, function (rdata) {
|
||||
layer.close(loadT);
|
||||
if(!rdata.status){
|
||||
layer.msg(rdata.msg, { icon: 2 });
|
||||
return false;
|
||||
}
|
||||
layer.msg(rdata.msg, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
window.location.href = '/';
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
layer.close(loadT);
|
||||
if (!rdata.status) {
|
||||
$("#errorStr").html(rdata.msg);
|
||||
$("input[name='password']").val('');
|
||||
num = rdata.msg.substring(rdata.msg.indexOf('[') + 1, rdata.msg.indexOf(']'))
|
||||
if (num < 5) {
|
||||
$(".yzm").show();
|
||||
$(".login").css("height", "332px");
|
||||
$("input[name='code']").val('');
|
||||
}
|
||||
$(".yzm").show();
|
||||
Wreset();
|
||||
$(".passcode").click();
|
||||
layer.msg(rdata.msg, { icon: 2 });
|
||||
return;
|
||||
}
|
||||
|
||||
layer.msg(rdata.msg, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
window.location.href = '/';
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
if (typeof (String.prototype.trim) === "undefined") {
|
||||
String.prototype.trim = function () {
|
||||
return String(this).replace(/^\s+|\s+$/g, '');
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
<div class="site_table_view bgw mtb15 pd15">
|
||||
<div class="info-title-tips">
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span> {{data['lan']['PS']}}After the site is successfully established, please<a class="btlink" href="/crontab">[Cron]</a>Add scheduled backup tasks to the page!</p>
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span> {{data['lan']['PS']}}after the site is successfully established, please<a class="btlink" href="/crontab">[Cron]</a>add scheduled backup tasks to the page!</p>
|
||||
</div>
|
||||
<div id="bt_site_table"></div>
|
||||
</div>
|
||||
|
||||
@@ -2,57 +2,49 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="main-content">
|
||||
<div class="container-fluid" style="padding-bottom:54px">
|
||||
<div class="pos-box bgw mtb15">
|
||||
<div class="position f14 c9 pull-left">
|
||||
<a class="plr10 c4" href="/">{{data['lan']['H1']}}</a>/<span class="plr10 c4">{{data['lan']['H2']}}</span>
|
||||
</div>
|
||||
<div class="search pull-right">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="softbox bgw mtb15">
|
||||
<div class="softlist">
|
||||
<div class="soft-filter pd15">
|
||||
<div class="row soft-filter-box">
|
||||
<div class="col-md-12">
|
||||
<span class="filter-title f14 c4">{{data['lan']['SEARCH_APP']}}</span>
|
||||
<div class="soft-search">
|
||||
<form target="hid" onsubmit='soft.get_list(1,0,$("#SearchValue").val())'>
|
||||
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="search" style="width:232px" />
|
||||
<button type="button" class="ser-sub pull-left" onclick='soft.get_list(1,0,$("#SearchValue").val())'></button>
|
||||
</form>
|
||||
<iframe name='hid' id="hid" style="display:none"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row soft-filter-box"><div class="col-md-12"><span class="filter-title f14 c4">{{data['lan']['APP_SORT']}}</span><div class="menu-sub softtype"></div></div></div>
|
||||
</div>
|
||||
<div class="divtable pd15 relative">
|
||||
<button class="btn btn-default btn-sm" onclick="soft.flush_cache()" title="{{data['lan']['UPDATE_FROM_CLOUD']}}" style="position:absolute;top:-49px;right:15px">{{data['lan']['UPDATE_APP_LIST']}}</button>
|
||||
<div id="updata_pro_info" style="display:none">
|
||||
<div class="alert alert-success" style="margin-bottom:15px"><strong>{{data['lan']['PS']}}</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="{{data['lan']['UPDATE_PRO_NOW']}}" style="margin-left:8px">"{{data['lan']['UPDATE_NOW']}}"</button></div>
|
||||
</div>
|
||||
<table id="softList" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top:10px"></table>
|
||||
<div id='softPage' class="dataTables_paginate paging_bootstrap page">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid" style="padding-bottom:54px">
|
||||
<div class="pos-box bgw mtb15">
|
||||
<div class="position f14 c9 pull-left">
|
||||
<a class="plr10 c4" href="/">{{data['lan']['H1']}}</a>/<span class="plr10 c4">{{data['lan']['H2']}}</span>
|
||||
</div>
|
||||
<div class="search pull-right"></div>
|
||||
</div>
|
||||
<div class="softbox bgw mtb15">
|
||||
<div class="softlist">
|
||||
<div class="soft-filter pd15">
|
||||
<div class="row soft-filter-box">
|
||||
<div class="col-md-12">
|
||||
<span class="filter-title f14 c4">{{data['lan']['SEARCH_APP']}}</span>
|
||||
<div class="soft-search">
|
||||
<form target="hid" onsubmit='soft.get_list(1,0,$("#SearchValue").val())'>
|
||||
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="search" style="width:232px" />
|
||||
<button type="button" class="ser-sub pull-left" onclick='soft.get_list(1,0,$("#SearchValue").val())'></button>
|
||||
</form>
|
||||
<iframe name='hid' id="hid" style="display:none"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row soft-filter-box"><div class="col-md-12"><span class="filter-title f14 c4">{{data['lan']['APP_SORT']}}</span><div class="menu-sub softtype"></div></div></div>
|
||||
</div>
|
||||
<div class="divtable pd15 relative">
|
||||
<button class="btn btn-default btn-sm" onclick="soft.flush_cache()" title="{{data['lan']['UPDATE_FROM_CLOUD']}}" style="position:absolute;top:-49px;right:15px">{{data['lan']['UPDATE_APP_LIST']}}</button>
|
||||
<div id="updata_pro_info">
|
||||
<div class="alert alert-success" style="margin-bottom:15px"><strong>{{data['lan']['PS']}}</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="{{data['lan']['UPDATE_PRO_NOW']}}" style="margin-left:8px">"{{data['lan']['UPDATE_NOW']}}"</button></div>
|
||||
</div>
|
||||
<table id="softList" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top:10px"></table>
|
||||
<div id='softPage' class="dataTables_paginate paging_bootstrap page"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/jquery.dragsort-0.5.2.min.js"></script>
|
||||
<script type="text/javascript" src="/static/laydate/laydate.js?date=20180301"></script>
|
||||
<script type="text/javascript" src="/static/ace/ace.js?date={{g.version}}"></script>
|
||||
<script type="text/javascript" src="/static/js/soft.js?version_20200109={{g['version']}}"></script>
|
||||
<script src="https://js.stripe.com/v3/"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
bt.set_cookie('sites_path', "{{session['config']['sites_path']}}");
|
||||
bt.set_cookie('serverType', "{{session['webserver']}}");
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
<span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span> -->
|
||||
</span>
|
||||
</div>
|
||||
<div class="term_content_tab"></div>
|
||||
<div class="term_content_tab">
|
||||
<div class="term-tool-button tool-hide"><span class="glyphicon glyphicon-menu-right"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="term_tootls">
|
||||
<div class="tootls_tab"><span class="active">Server list</span><a href="javascript:;" data-type="host" title="Add server SSH information"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></a></div>
|
||||
|
||||
+62
-5
@@ -414,6 +414,11 @@ class acme_v2:
|
||||
|
||||
# 设置验证信息
|
||||
def set_auth_info(self, identifier_auth):
|
||||
|
||||
#从云端验证
|
||||
if not self.cloud_check_domain(identifier_auth['domain']):
|
||||
self.err = "Cloud verification failed!"
|
||||
|
||||
# 是否手动验证DNS
|
||||
if identifier_auth['auth_to'] == 'dns':
|
||||
return None
|
||||
@@ -427,6 +432,14 @@ class acme_v2:
|
||||
self.create_dns_record(
|
||||
identifier_auth['auth_to'], identifier_auth['domain'], identifier_auth['auth_value'])
|
||||
|
||||
#从云端验证域名是否可访问
|
||||
def cloud_check_domain(self,domain):
|
||||
try:
|
||||
result = requests.post('https://www.aapanel.com/api/panel/checkDomain',{"domain":domain,"ssl":1}).json()
|
||||
return result['status']
|
||||
except: return False
|
||||
|
||||
|
||||
#清理验证文件
|
||||
def claer_auth_file(self,index):
|
||||
if not self._config['orders'][index]['auth_type'] in ['http','tls']:
|
||||
@@ -881,9 +894,10 @@ fullchain.pem Paste into certificate input box
|
||||
return p12.export()
|
||||
|
||||
# 拆分根证书
|
||||
def split_ca_data(self, cert):
|
||||
datas = cert.split('-----END CERTIFICATE-----')
|
||||
return {"cert": datas[0] + "-----END CERTIFICATE-----\n", "root": datas[1] + '-----END CERTIFICATE-----\n'}
|
||||
def split_ca_data(self,cert):
|
||||
sp_key = '-----END CERTIFICATE-----\n'
|
||||
datas = cert.split(sp_key)
|
||||
return {"cert": datas[0] + sp_key, "root": sp_key.join(datas[1:])}
|
||||
|
||||
# 构造可选名称
|
||||
def get_alt_names(self, index):
|
||||
@@ -1237,6 +1251,8 @@ fullchain.pem Paste into certificate input box
|
||||
def apply_cert(self, domains, auth_type='dns', auth_to='Dns_com|None|None', **args):
|
||||
write_log("", "wb+")
|
||||
try:
|
||||
if 'auto_wildcard' in args and args['auto_wildcard']:
|
||||
self._auto_wildcard = True
|
||||
self.get_apis()
|
||||
index = None
|
||||
if 'index' in args:
|
||||
@@ -1382,7 +1398,42 @@ fullchain.pem Paste into certificate input box
|
||||
return to_path
|
||||
return False
|
||||
|
||||
def get_site_id(self,domains):
|
||||
site_ids=[]
|
||||
for domain in domains:
|
||||
if '*' in domain:
|
||||
continue
|
||||
site_id = public.M('domain').where('name=?', (domain,)).field('pid').select()
|
||||
if not site_id:
|
||||
continue
|
||||
site_ids.append(site_id[0]['pid'])
|
||||
if not site_ids:
|
||||
return False
|
||||
site_ids = list(set(site_ids))
|
||||
if not len(site_ids) == 1:
|
||||
return False
|
||||
return site_ids[0]
|
||||
|
||||
def get_site_runpath(self,domains):
|
||||
site_id = self.get_site_id(domains)
|
||||
if not site_id:
|
||||
return False
|
||||
import panelSite
|
||||
from collections import namedtuple
|
||||
ps = panelSite.panelSite()
|
||||
# 构造一个类
|
||||
get = namedtuple("get", ["id"])
|
||||
get.id=site_id
|
||||
site_path = public.M('sites').where('id=?', (get.id,)).field('path').select()[0]['path']
|
||||
runpath = ps.GetRunPath(get)
|
||||
return site_path + runpath
|
||||
|
||||
def find_site_stopped(self,domains):
|
||||
site_id = self.get_site_id(domains)
|
||||
if not site_id:
|
||||
return False
|
||||
site_status = public.M('sites').where('id=?', (site_id,)).field('status').select()[0]['status']
|
||||
return site_status
|
||||
|
||||
# 续签证书
|
||||
def renew_cert(self, index):
|
||||
@@ -1406,6 +1457,8 @@ fullchain.pem Paste into certificate input box
|
||||
self._config['orders'][i]['cert_timeout'] = int(time.time())
|
||||
if self._config['orders'][i]['cert_timeout'] > s_time or self._config['orders'][i]['auth_to'] == 'dns':
|
||||
continue
|
||||
if self.find_site_stopped(self._config['orders'][i]['domains']) == '0':
|
||||
continue
|
||||
|
||||
#已删除的网站直接跳过续签
|
||||
if self._config['orders'][i]['auth_to'].find('|') == -1 and self._config['orders'][i]['auth_to'].find('/') != -1:
|
||||
@@ -1418,15 +1471,19 @@ fullchain.pem Paste into certificate input box
|
||||
if not order_index:
|
||||
write_log(public.getMsg('ACME_NO_NEED_RENEW'))
|
||||
return
|
||||
write_log(public.getMsg("ACME_NEED_RENEW",(len(order_index),)))
|
||||
write_log(public.getMsg("ACME_NEED_RENEW",(str(len(order_index)),)))
|
||||
n = 0
|
||||
self.get_apis()
|
||||
cert = None
|
||||
for index in order_index:
|
||||
n += 1
|
||||
write_log(public.getMsg("ACME_RENEWING",(str(n),self._config['orders'][index]['domains'])))
|
||||
write_log(public.getMsg("ACME_RENEWING",(str(n),str(self._config['orders'][index]['domains']))))
|
||||
write_log(public.getMsg('ACME_CREAT_ORDER'))
|
||||
try:
|
||||
run_path = self.get_site_runpath(self._config['orders'][index]['domains'])
|
||||
if run_path:
|
||||
if self._config['orders'][index]['auth_to'] != run_path:
|
||||
self._config['orders'][index]['auth_to'] = run_path
|
||||
index = self.create_order(
|
||||
self._config['orders'][index]['domains'],
|
||||
self._config['orders'][index]['auth_type'],
|
||||
|
||||
+12
-8
@@ -36,8 +36,13 @@ class ajax:
|
||||
#取Nginx负载状态
|
||||
self.CheckStatusConf()
|
||||
result = public.httpGet('http://127.0.0.1/nginx_status')
|
||||
tmp = result.split()
|
||||
if len(tmp) < 15:
|
||||
is_curl = False
|
||||
tmp = []
|
||||
if result:
|
||||
tmp = result.split()
|
||||
if len(tmp) < 15: is_curl = True
|
||||
|
||||
if is_curl:
|
||||
result = public.ExecShell('curl http://127.0.0.1/nginx_status')[0]
|
||||
tmp = result.split()
|
||||
data = {}
|
||||
@@ -464,7 +469,9 @@ class ajax:
|
||||
import json
|
||||
conf_status = public.M('config').where("id=?",('1',)).field('status').find()
|
||||
if int(session['config']['status']) == 0 and int(conf_status['status']) == 0:
|
||||
public.HttpGet('{}/api/setupCount/setupPanel?type=Linux'.format(self.__official_url))
|
||||
# public.HttpGet('{}/api/setupCount/setupPanel?type=Linux'.format(self.__official_url))
|
||||
public.arequests('get', '{}/api/setupCount/setupPanel?type=Linux'.format(self.__official_url))
|
||||
|
||||
public.M('config').where("id=?",('1',)).setField('status',1)
|
||||
|
||||
#取回远程版本信息
|
||||
@@ -492,10 +499,7 @@ class ajax:
|
||||
data['intrusion'] = 0
|
||||
data['uid'] = self.get_uid()
|
||||
#msg = public.getMsg('PANEL_UPDATE_MSG');
|
||||
data['o'] = ''
|
||||
filename = '/www/server/panel/data/o.pl'
|
||||
if os.path.exists(filename): data['o'] = str(public.readFile(filename))
|
||||
# sUrl = 'https://console.aapanel.com/api/panel/updateLinuxEn'
|
||||
data['o'] = public.get_oem_name()
|
||||
sUrl = '{}/api/panel/updateLinuxEn'.format(self.__official_url)
|
||||
updateInfo = json.loads(public.httpPost(sUrl,data))
|
||||
if not updateInfo: return public.returnMsg(False,"CONNECT_ERR")
|
||||
@@ -1189,7 +1193,7 @@ class ajax:
|
||||
php_path = '/usr/local/lsws/lsphp'
|
||||
php_bin = php_path + php_version + '/bin/php'
|
||||
php_ini = php_path + php_version + '/etc/php.ini'
|
||||
if not os.path.exists('/etc/redhat-release'):
|
||||
if not os.path.exists('/etc/redhat-release') and public.get_webserver() == 'openlitespeed':
|
||||
php_ini = php_path + php_version + '/etc/php/'+args.php_version+'/litespeed/php.ini'
|
||||
tmp = public.ExecShell(php_bin + ' /www/server/panel/class/php_info.php')[0]
|
||||
if tmp.find('Warning: JIT is incompatible') != -1:
|
||||
|
||||
@@ -246,10 +246,30 @@ class apache:
|
||||
return public.returnMsg(False, 'CONF_FILE_NOT_EXISTS')
|
||||
reg = '\s*#LOG_FORMAT_BEGIN_{n}(\n|.)+#LOG_FORMAT_END_{n}\n?'.format(n=args.log_format_name)
|
||||
conf = re.sub(reg,'',conf)
|
||||
self._del_format_log_of_website(args.log_format_name)
|
||||
public.writeFile(self.httpdconf,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
|
||||
def _del_format_log_of_website(self,log_format_name):
|
||||
site_format_log_status = self._get_format_log_to_website(log_format_name)
|
||||
try:
|
||||
for s in site_format_log_status.keys():
|
||||
if not site_format_log_status[s]:
|
||||
continue
|
||||
website_conf_file = '/www/server/panel/vhost/apache/{}.conf'.format(s)
|
||||
format_exist_reg = 'CustomLog\s+"/www.*"\s+{}'.format(log_format_name)
|
||||
conf = public.readFile(website_conf_file)
|
||||
if not conf:continue
|
||||
if not re.search(format_exist_reg,conf):continue
|
||||
access_log = re.search(format_exist_reg,conf).group().split()
|
||||
access_log = access_log[0] + ' ' +access_log[1] + 'combined'
|
||||
conf = re.sub(format_exist_reg,access_log,conf)
|
||||
public.writeFile(website_conf_file,conf)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_httpd_access_log_format_parameter(self,args=None):
|
||||
data = {
|
||||
"%h":"Client's IP address",
|
||||
|
||||
+40
-30
@@ -8,6 +8,7 @@
|
||||
# +-------------------------------------------------------------------
|
||||
from BTPanel import session, cache , request, redirect, g
|
||||
from datetime import datetime
|
||||
from public import dict_obj
|
||||
import os
|
||||
import public
|
||||
import json
|
||||
@@ -15,17 +16,6 @@ import sys
|
||||
import time
|
||||
|
||||
|
||||
class dict_obj:
|
||||
def __contains__(self, key):
|
||||
return getattr(self, key, None)
|
||||
|
||||
def __setitem__(self, key, value): setattr(self, key, value)
|
||||
def __getitem__(self, key): return getattr(self, key, None)
|
||||
def __delitem__(self, key): delattr(self, key)
|
||||
def __delattr__(self, key): delattr(self, key)
|
||||
def get_items(self): return self
|
||||
|
||||
|
||||
class panelSetup:
|
||||
def init(self):
|
||||
ua = request.headers.get('User-Agent','')
|
||||
@@ -33,7 +23,7 @@ class panelSetup:
|
||||
ua = ua.lower()
|
||||
if ua.find('spider') != -1 or ua.find('bot') != -1:
|
||||
return redirect('https://www.google.com')
|
||||
g.version = '6.8.8'
|
||||
g.version = '6.8.12'
|
||||
g.title = public.GetConfigValue('title')
|
||||
g.uri = request.path
|
||||
g.debug = os.path.exists('data/debug.pl')
|
||||
@@ -50,22 +40,28 @@ class panelSetup:
|
||||
else:
|
||||
g.cdn_url = '/static'
|
||||
session['title'] = g.title
|
||||
dirPath = '/www/server/phpmyadmin/pma'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
dirPath = '/www/server/adminer'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
dirPath = '/www/server/panel/adminer'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
g.is_aes = False
|
||||
self.other_import()
|
||||
return None
|
||||
|
||||
|
||||
def other_import(self):
|
||||
g.o = public.readFile('data/o.pl')
|
||||
g.other_css = []
|
||||
g.other_js = []
|
||||
if g.o:
|
||||
s_path = 'BTPanel/static/other/{}'
|
||||
css_name = "css/{}.css".format(g.o)
|
||||
css_file = s_path.format(css_name)
|
||||
if os.path.exists(css_file): g.other_css.append('/static/other/{}'.format(css_name))
|
||||
|
||||
js_name = "js/{}.js".format(g.o)
|
||||
js_file = s_path.format(js_name)
|
||||
if os.path.exists(js_file): g.other_js.append('/static/other/{}'.format(js_name))
|
||||
|
||||
|
||||
|
||||
class panelAdmin(panelSetup):
|
||||
setupPath = '/www/server'
|
||||
|
||||
@@ -110,7 +106,7 @@ class panelAdmin(panelSetup):
|
||||
if not 'lan' in session:
|
||||
session['lan'] = public.GetLanguage()
|
||||
if not 'home' in session:
|
||||
session['home'] = 'https://console.aapanel.com'
|
||||
session['home'] = 'https://brandnew.aapanel.com'
|
||||
return False
|
||||
|
||||
# 检查Web服务器类型
|
||||
@@ -276,15 +272,29 @@ class panelAdmin(panelSetup):
|
||||
def GetOS(self):
|
||||
if not 'server_os' in session:
|
||||
tmp = {}
|
||||
if os.path.exists('/etc/redhat-release'):
|
||||
issue_file = '/etc/issue'
|
||||
redhat_release = '/etc/redhat-release'
|
||||
if os.path.exists(redhat_release):
|
||||
tmp['x'] = 'RHEL'
|
||||
tmp['osname'] = public.ReadFile(
|
||||
'/etc/redhat-release').split()[0]
|
||||
tmp['osname'] = self.get_osname(redhat_release)
|
||||
elif os.path.exists('/usr/bin/yum'):
|
||||
tmp['x'] = 'RHEL'
|
||||
tmp['osname'] = public.ReadFile('/etc/issue').split()[0]
|
||||
elif os.path.exists('/etc/issue'):
|
||||
tmp['osname'] = self.get_osname(issue_file)
|
||||
elif os.path.exists(issue_file):
|
||||
tmp['x'] = 'Debian'
|
||||
tmp['osname'] = public.ReadFile('/etc/issue').split()[0]
|
||||
tmp['osname'] = self.get_osname(issue_file)
|
||||
session['server_os'] = tmp
|
||||
return False
|
||||
|
||||
|
||||
def get_osname(self,i_file):
|
||||
'''
|
||||
@name 从指定文件中获取系统名称
|
||||
@author hwliang<2021-04-07>
|
||||
@param i_file<string> 指定文件全路径
|
||||
@return string
|
||||
'''
|
||||
if not os.path.exists(i_file): return ''
|
||||
issue_str = public.ReadFile(i_file).strip()
|
||||
if issue_str: return issue_str.split()[0]
|
||||
return ''
|
||||
|
||||
+151
-8
@@ -21,9 +21,9 @@ class config:
|
||||
_bk_key_file = _setup_path + "/data/bk_two_step_auth.txt"
|
||||
_username_file = _setup_path + "/data/username.txt"
|
||||
_core_fle_path = _setup_path + '/data/qrcode'
|
||||
__mail_config = '/www/server/panel/data/stmp_mail.json'
|
||||
__mail_list_data = '/www/server/panel/data/mail_list.json'
|
||||
__dingding_config = '/www/server/panel/data/dingding.json'
|
||||
__mail_config = _setup_path+'/data/stmp_mail.json'
|
||||
__mail_list_data = _setup_path+'/data/mail_list.json'
|
||||
__dingding_config = _setup_path+'/data/dingding.json'
|
||||
__mail_list = []
|
||||
__weixin_user = []
|
||||
|
||||
@@ -112,7 +112,7 @@ class config:
|
||||
return public.returnMsg(False, 'SEND_FAILED')
|
||||
|
||||
# 查看能使用的告警通道
|
||||
def get_settings(self, get):
|
||||
def get_settings(self, get=None):
|
||||
qq_mail_info = json.loads(public.ReadFile(self.__mail_config))
|
||||
if len(qq_mail_info) == 0:
|
||||
user_mail = False
|
||||
@@ -127,6 +127,7 @@ class config:
|
||||
ret['user_mail'] = {"user_name": user_mail, "mail_list": self.__mail_list,"info":self.get_user_mail(get)}
|
||||
ret['dingding'] = {"dingding": dingding,"info":self.get_dingding(get)}
|
||||
return ret
|
||||
|
||||
# 设置钉钉报警
|
||||
def set_dingding(self, get):
|
||||
if not (hasattr(get, 'url') or hasattr(get, 'atall')):
|
||||
@@ -161,12 +162,12 @@ class config:
|
||||
|
||||
|
||||
def getPanelState(self,get):
|
||||
return os.path.exists('/www/server/panel/data/close.pl')
|
||||
return os.path.exists(self._setup_path+'/data/close.pl')
|
||||
|
||||
def reload_session(self):
|
||||
userInfo = public.M('users').where("id=?",(1,)).field('username,password').find()
|
||||
token = public.Md5(userInfo['username'] + '/' + userInfo['password'])
|
||||
public.writeFile('/www/server/panel/data/login_token.pl',token)
|
||||
public.writeFile(self._setup_path+'/data/login_token.pl',token)
|
||||
|
||||
sess_path = 'data/sess_files'
|
||||
if not os.path.exists(sess_path):
|
||||
@@ -705,7 +706,7 @@ class config:
|
||||
sps = sp.set_lets(get)
|
||||
return sps
|
||||
else:
|
||||
sslConf = '/www/server/panel/data/ssl.pl'
|
||||
sslConf = self._setup_path+'/data/ssl.pl'
|
||||
if os.path.exists(sslConf):
|
||||
public.ExecShell('rm -f ' + sslConf)
|
||||
return public.returnMsg(True,'PANEL_SSL_CLOSE')
|
||||
@@ -1676,9 +1677,151 @@ class config:
|
||||
import file_execute_deny
|
||||
p = file_execute_deny.FileExecuteDeny()
|
||||
return p.del_file_deny(args)
|
||||
#查看告警
|
||||
def get_login_send(self,get):
|
||||
result={}
|
||||
import time
|
||||
time.sleep(0.5)
|
||||
if os.path.exists('/www/server/panel/data/login_send_mail.pl'):
|
||||
result['mail']=True
|
||||
else:
|
||||
result['mail']=False
|
||||
if os.path.exists('/www/server/panel/data/login_send_dingding.pl'):
|
||||
result['dingding']=True
|
||||
else:
|
||||
result['dingding']=False
|
||||
if result['mail'] or result['dingding']:
|
||||
return public.returnMsg(True, result)
|
||||
return public.returnMsg(False, result)
|
||||
|
||||
#设置告警
|
||||
def set_login_send(self,get):
|
||||
type=get.type.strip()
|
||||
if type=='mail':
|
||||
if not os.path.exists("/www/server/panel/data/login_send_mail.pl"):
|
||||
os.mknod("/www/server/panel/data/login_send_mail.pl")
|
||||
if os.path.exists("/www/server/panel/data/login_send_dingding.pl"):
|
||||
os.remove("/www/server/panel/data/login_send_dingding.pl")
|
||||
return public.returnMsg(True, 'Setup Successfully')
|
||||
elif type=='dingding':
|
||||
if not os.path.exists("/www/server/panel/data/login_send_dingding.pl"):
|
||||
os.mknod("/www/server/panel/data/login_send_dingding.pl")
|
||||
if os.path.exists("/www/server/panel/data/login_send_mail.pl"):
|
||||
os.remove("/www/server/panel/data/login_send_mail.pl")
|
||||
return public.returnMsg(True, 'Setup Successfully')
|
||||
else:
|
||||
return public.returnMsg(False,'The delivery type is not supported')
|
||||
|
||||
#取消告警
|
||||
def clear_login_send(self,get):
|
||||
type = get.type.strip()
|
||||
if type == 'mail':
|
||||
if os.path.exists("/www/server/panel/data/login_send_mail.pl"):
|
||||
os.remove("/www/server/panel/data/login_send_mail.pl")
|
||||
return public.returnMsg(True, '取消成功')
|
||||
elif type == 'dingding':
|
||||
if os.path.exists("/www/server/panel/data/login_send_dingding.pl"):
|
||||
os.remove("/www/server/panel/data/login_send_dingding.pl")
|
||||
return public.returnMsg(True, '取消成功')
|
||||
else:
|
||||
return public.returnMsg(False, '不支持该发送类型')
|
||||
|
||||
#告警日志
|
||||
def get_login_log(self,get):
|
||||
public.create_logs()
|
||||
import page
|
||||
page = page.Page()
|
||||
count = public.M('logs2').where('type=?', (u'aapanel login reminder',)).field('log,addtime').count()
|
||||
limit = 7
|
||||
info = {}
|
||||
info['count'] = count
|
||||
info['row'] = limit
|
||||
info['p'] = 1
|
||||
if hasattr(get, 'p'):
|
||||
info['p'] = int(get['p'])
|
||||
info['uri'] = get
|
||||
info['return_js'] = ''
|
||||
if hasattr(get, 'tojs'):
|
||||
info['return_js'] = get.tojs
|
||||
data = {}
|
||||
# 获取分页数据
|
||||
data['page'] = page.GetPage(info, '1,2,3,4,5,8')
|
||||
data['data'] = public.M('logs2').where('type=?', (u'aapanel login reminder',)).field('log,addtime').order('id desc').limit(
|
||||
str(page.SHIFT) + ',' + str(page.ROW)).field('log,addtime').select()
|
||||
return data
|
||||
|
||||
#白名单设置
|
||||
def login_ipwhite(self,get):
|
||||
type=get.type
|
||||
if type=='get':
|
||||
return self.get_login_ipwhite(get)
|
||||
if type=='add':
|
||||
return self.add_login_ipwhite(get)
|
||||
if type=='del':
|
||||
return self.del_login_ipwhite(get)
|
||||
if type=='clear':
|
||||
return self.clear_login_ipwhite(get)
|
||||
|
||||
#查看IP白名单
|
||||
def get_login_ipwhite(self,get):
|
||||
try:
|
||||
path='/www/server/panel/data/send_login_white.json'
|
||||
ip_white=json.loads(public.ReadFile('/www/server/panel/data/send_login_white.json'))
|
||||
if not ip_white:return public.returnMsg(True, [])
|
||||
return public.returnMsg(True, ip_white)
|
||||
except:
|
||||
public.WriteFile(path, '[]')
|
||||
return public.returnMsg(True, [])
|
||||
|
||||
def add_login_ipwhite(self,get):
|
||||
ip=get.ip.strip()
|
||||
try:
|
||||
path = '/www/server/panel/data/send_login_white.json'
|
||||
ip_white = json.loads(public.ReadFile('/www/server/panel/data/send_login_white.json'))
|
||||
if not ip in ip_white:
|
||||
ip_white.append(ip)
|
||||
public.WriteFile(path, json.dumps(ip_white))
|
||||
return public.returnMsg(True, "Add successfully")
|
||||
except:
|
||||
public.WriteFile(path, json.dumps([ip]))
|
||||
return public.returnMsg(True, "Add successfully")
|
||||
|
||||
def del_login_ipwhite(self,get):
|
||||
ip = get.ip.strip()
|
||||
try:
|
||||
path = '/www/server/panel/data/send_login_white.json'
|
||||
ip_white = json.loads(public.ReadFile('/www/server/panel/data/send_login_white.json'))
|
||||
if ip in ip_white:
|
||||
ip_white.remove(ip)
|
||||
public.WriteFile(path, json.dumps(ip_white))
|
||||
return public.returnMsg(True, "Delete successfully")
|
||||
except:
|
||||
public.WriteFile(path, json.dumps([]))
|
||||
return public.returnMsg(True, "Delete successfully")
|
||||
|
||||
def clear_login_ipwhite(self,get):
|
||||
path = '/www/server/panel/data/send_login_white.json'
|
||||
public.WriteFile(path, json.dumps([]))
|
||||
return public.returnMsg(True, "Clear successfully")
|
||||
|
||||
|
||||
def get_panel_ssl_status(self,get):
|
||||
import os
|
||||
if os.path.exists('/www/server/panel/data/ssl.pl'):
|
||||
if os.path.exists(self._setup_path+'/data/ssl.pl'):
|
||||
return public.returnMsg(True,'success')
|
||||
return public.returnMsg(False,'false')
|
||||
|
||||
def set_backup_notification(self,get):
|
||||
import os
|
||||
f = self._setup_path+'/data/send_back_error.pl'
|
||||
if os.path.exists(f):
|
||||
public.ExecShell('rm -f {}'.format(f))
|
||||
return public.returnMsg(True,'Disable successfully')
|
||||
public.writeFile(f,'1')
|
||||
return public.returnMsg(True,'Enable Successfully')
|
||||
|
||||
def get_backup_notification(self,get):
|
||||
import os
|
||||
if os.path.exists(self._setup_path+'/data/send_back_error.pl'):
|
||||
return public.returnMsg(True,'success')
|
||||
return public.returnMsg(False,'false')
|
||||
+39
-20
@@ -10,6 +10,7 @@ import public,db,os,time,re
|
||||
from BTPanel import session,cache
|
||||
class crontab:
|
||||
field = 'id,name,type,where1,where_hour,where_minute,echo,addtime,status,save,backupTo,sName,sBody,sType,urladdress'
|
||||
field += ",save_local,notice,notice_channel"
|
||||
#取计划任务列表
|
||||
def GetCrontab(self,get):
|
||||
self.checkBackup()
|
||||
@@ -23,8 +24,10 @@ class crontab:
|
||||
public.M('crontab').execute("ALTER TABLE 'crontab' ADD 'sBody' TEXT",())
|
||||
public.M('crontab').execute("ALTER TABLE 'crontab' ADD 'sType' TEXT",())
|
||||
public.M('crontab').execute("ALTER TABLE 'crontab' ADD 'urladdress' TEXT",())
|
||||
public.M('crontab').execute("ALTER TABLE 'crontab' ADD 'save_local' INTEGER DEFAULT 0",())
|
||||
public.M('crontab').execute("ALTER TABLE 'crontab' ADD 'notice' INTEGER DEFAULT 0",())
|
||||
public.M('crontab').execute("ALTER TABLE 'crontab' ADD 'notice_channel' TEXT DEFAULT ''",())
|
||||
cront = public.M('crontab').order("id desc").field(self.field).select()
|
||||
|
||||
data=[]
|
||||
for i in range(len(cront)):
|
||||
tmp = {}
|
||||
@@ -149,9 +152,17 @@ class crontab:
|
||||
cronInfo['backupTo'] = get['backupTo']
|
||||
cronInfo['sBody'] = get['sBody']
|
||||
cronInfo['urladdress'] = get['urladdress']
|
||||
public.M('crontab').where('id=?',(id,)).save('name,type,where1,where_hour,where_minute,save,backupTo,sBody,urladdress',
|
||||
(get['name'],get['type'],get['where1'],get['hour'],get['minute'],get['save'],get['backupTo'],get['sBody'],get['urladdress']))
|
||||
|
||||
columns = 'name,type,where1,where_hour,where_minute,save,backupTo,sBody,urladdress'
|
||||
values = (get['name'],get['type'],get['where1'],get['hour'],
|
||||
get['minute'],get['save'],get['backupTo'],get['sBody']
|
||||
,get['urladdress'])
|
||||
if 'save_local' in get:
|
||||
columns += ",save_local, notice, notice_channel"
|
||||
values = (get['name'],get['type'],get['where1'],get['hour'],
|
||||
get['minute'],get['save'],get['backupTo'],get['sBody'],
|
||||
get['urladdress'],get['save_local'],get["notice"],
|
||||
get["notice_channel"])
|
||||
public.M('crontab').where('id=?',(id,)).save(columns,values)
|
||||
self.remove_for_crond(cronInfo['echo'])
|
||||
self.sync_to_crond(cronInfo)
|
||||
public.WriteLog('TYPE_CRON',"MODIFY_CRON",(cronInfo['name']))
|
||||
@@ -164,8 +175,6 @@ class crontab:
|
||||
data = public.M('crontab').where('id=?',(id,)).field(self.field).find()
|
||||
return data
|
||||
|
||||
|
||||
|
||||
#同步到crond
|
||||
def sync_to_crond(self,cronInfo):
|
||||
if 'status' in cronInfo:
|
||||
@@ -196,10 +205,19 @@ class crontab:
|
||||
wRes = self.WriteShell(cuonConfig)
|
||||
if type(wRes) != bool: return wRes
|
||||
self.CrondReload()
|
||||
addData=public.M('crontab').add(
|
||||
'name,type,where1,where_hour,where_minute,echo,addtime,status,save,backupTo,sType,sName,sBody,urladdress',
|
||||
(get['name'],get['type'],get['where1'],get['hour'],get['minute'],cronName,time.strftime('%Y-%m-%d %X',time.localtime()),1,get['save'],get['backupTo'],get['sType'],get['sName'],get['sBody'],get['urladdress'])
|
||||
)
|
||||
columns = 'name,type,where1,where_hour,where_minute,echo,addtime,\
|
||||
status,save,backupTo,sType,sName,sBody,urladdress'
|
||||
values = (get['name'],get['type'],get['where1'],get['hour'],
|
||||
get['minute'],cronName,time.strftime('%Y-%m-%d %X',time.localtime()),
|
||||
1,get['save'],get['backupTo'],get['sType'],get['sName'],get['sBody'],
|
||||
get['urladdress'])
|
||||
if "save_local" in get:
|
||||
columns += ",save_local,notice,notice_channel"
|
||||
values = (get['name'],get['type'],get['where1'],get['hour'],
|
||||
get['minute'],cronName,time.strftime('%Y-%m-%d %X',time.localtime()),
|
||||
1,get['save'],get['backupTo'],get['sType'],get['sName'],get['sBody'],
|
||||
get['urladdress'], get["save_local"], get['notice'], get['notice_channel'])
|
||||
addData=public.M('crontab').add(columns,values)
|
||||
if addData>0:
|
||||
result = public.returnMsg(True,'ADD_SUCCESS')
|
||||
result['id'] = addData
|
||||
@@ -339,6 +357,10 @@ class crontab:
|
||||
def GetShell(self,param):
|
||||
#try:
|
||||
type=param['sType']
|
||||
if not 'echo' in param:
|
||||
cronName=public.md5(public.md5(str(time.time()) + '_bt'))
|
||||
else:
|
||||
cronName = param['echo']
|
||||
if type=='toFile':
|
||||
shell=param.sFile
|
||||
else :
|
||||
@@ -353,10 +375,11 @@ class crontab:
|
||||
if type in ['site','path'] and param['sBody'] != 'undefined' and len(param['sBody']) > 1:
|
||||
exports = param['sBody'].replace("\r\n","\n").replace("\n",",")
|
||||
head += "BT_EXCLUDE=\"" + exports.strip() + "\"\nexport BT_EXCLUDE\n"
|
||||
attach_param = " " + cronName
|
||||
wheres={
|
||||
'path': head + python_bin +" " + public.GetConfigValue('setup_path')+"/panel/script/backup.py path "+param['sName']+" "+str(param['save']),
|
||||
'site' : head +python_bin+ " " + public.GetConfigValue('setup_path')+"/panel/script/backup.py site "+param['sName']+" "+str(param['save']),
|
||||
'database': head +python_bin+ " " + public.GetConfigValue('setup_path')+"/panel/script/backup.py database "+param['sName']+" "+str(param['save']),
|
||||
'path': head + python_bin +" " + public.GetConfigValue('setup_path')+"/panel/script/backup.py path "+param['sName']+" "+str(param['save'])+attach_param,
|
||||
'site' : head +python_bin+ " " + public.GetConfigValue('setup_path')+"/panel/script/backup.py site "+param['sName']+" "+str(param['save'])+attach_param,
|
||||
'database': head +python_bin+ " " + public.GetConfigValue('setup_path')+"/panel/script/backup.py database "+param['sName']+" "+str(param['save'])+attach_param,
|
||||
'logs' : head +python_bin+ " " + public.GetConfigValue('setup_path')+"/panel/script/logsBackup "+param['sName']+log+" "+str(param['save']),
|
||||
'rememory' : head + "/bin/bash " + public.GetConfigValue('setup_path') + '/panel/script/rememory.sh',
|
||||
'webshell': head +python_bin+ " " + public.GetConfigValue('setup_path') + '/panel/class/webshell_check.py site ' + param['sName'] +' ' +param['urladdress']
|
||||
@@ -365,9 +388,9 @@ class crontab:
|
||||
cfile = public.GetConfigValue('setup_path') + "/panel/plugin/" + param['backupTo'] + "/" + param['backupTo'] + "_main.py"
|
||||
if not os.path.exists(cfile): cfile = public.GetConfigValue('setup_path') + "/panel/script/backup_" + param['backupTo'] + ".py"
|
||||
wheres={
|
||||
'path': head + python_bin+" " + cfile + " path " + param['sName'] + " " + str(param['save']),
|
||||
'site' : head + python_bin+" " + cfile + " site " + param['sName'] + " " + str(param['save']),
|
||||
'database': head + python_bin+" " + cfile + " database " + param['sName'] + " " + str(param['save']),
|
||||
'path': head + python_bin+" " + cfile + " path " + param['sName'] + " " + str(param['save'])+attach_param,
|
||||
'site' : head + python_bin+" " + cfile + " site " + param['sName'] + " " + str(param['save'])+attach_param,
|
||||
'database': head + python_bin+" " + cfile + " database " + param['sName'] + " " + str(param['save'])+attach_param,
|
||||
'logs' : head + python_bin+" " + public.GetConfigValue('setup_path')+"/panel/script/logsBackup "+param['sName']+log+" "+str(param['save']),
|
||||
'rememory' : head + "/bin/bash " + public.GetConfigValue('setup_path') + '/panel/script/rememory.sh',
|
||||
'webshell': head + python_bin+" " + public.GetConfigValue('setup_path') + '/panel/class/webshell_check.py site ' + param['sName'] +' ' +param['urladdress']
|
||||
@@ -389,10 +412,6 @@ echo "--------------------------------------------------------------------------
|
||||
'''
|
||||
cronPath=public.GetConfigValue('setup_path')+'/cron'
|
||||
if not os.path.exists(cronPath): public.ExecShell('mkdir -p ' + cronPath)
|
||||
if not 'echo' in param:
|
||||
cronName=public.md5(public.md5(str(time.time()) + '_bt'))
|
||||
else:
|
||||
cronName = param['echo']
|
||||
file = cronPath+'/' + cronName
|
||||
public.writeFile(file,self.CheckScript(shell))
|
||||
public.ExecShell('chmod 750 ' + file)
|
||||
|
||||
+9
-3
@@ -34,9 +34,11 @@ class database(datatool.datatools):
|
||||
if self.CheckRecycleBin(data_name): return public.returnMsg(False,'DATABASE_DEL_RECYCLE_BIN',(data_name,))
|
||||
if len(data_name) > 64: return public.returnMsg(False, 'DATABASE_NAME_LEN')
|
||||
reg = r"^[\w\.-]+$"
|
||||
if not re.match(reg, data_name): return public.returnMsg(False,'DATABASE_NAME_ERR_T')
|
||||
if not hasattr(get,'db_user'): get.db_user = data_name
|
||||
username = get.db_user.strip()
|
||||
if not re.match(reg, data_name): return public.returnMsg(False,'DATABASE_NAME_ERR_T')
|
||||
if not re.match(reg, username): return public.returnMsg(False,'DATABASE_NAME_ERR')
|
||||
if not hasattr(get,'db_user'): get.db_user = data_name
|
||||
|
||||
checks = ['root','mysql','test','sys','panel_logs']
|
||||
if username in checks or len(username) < 1: return public.returnMsg(False,'DATABASE_USER_NAME_ERR')
|
||||
if data_name in checks or len(data_name) < 1: return public.returnMsg(False,'DATABASE_NAME_ERR')
|
||||
@@ -299,6 +301,8 @@ SetLink
|
||||
find = public.M('databases').where("id=?",(id,)).field('id,pid,name,username,password,accept,ps,addtime').find()
|
||||
accept = find['accept']
|
||||
username = find['username']
|
||||
if "'" in username:
|
||||
username=re.sub("\'","\\'",username)
|
||||
#删除MYSQL
|
||||
result = panelMysql.panelMysql().execute("drop database `" + name + "`")
|
||||
isError=self.IsSqlError(result)
|
||||
@@ -481,7 +485,7 @@ SetLink
|
||||
try:
|
||||
password = public.M('config').where('id=?',(1,)).getField('mysql_root')
|
||||
os.environ["MYSQL_PWD"] = password
|
||||
public.ExecShell("/www/server/mysql/bin/mysqldump -R -E --default-character-set="+ public.get_database_character(name) +" --force --opt \"" + name + "\" -u root | gzip > " + backupName)
|
||||
public.ExecShell("/www/server/mysql/bin/mysqldump -R -E --triggers=false --default-character-set="+ public.get_database_character(name) +" --force --opt \"" + name + "\" -u root | gzip > " + backupName)
|
||||
except Exception as e:
|
||||
raise
|
||||
finally:
|
||||
@@ -748,6 +752,8 @@ SetLink
|
||||
#修改数据库目录
|
||||
def SetDataDir(self,get):
|
||||
if get.datadir[-1] == '/': get.datadir = get.datadir[0:-1]
|
||||
if len(get.datadir) > 32: return public.returnMsg(False,'The data directory length cannot exceed 32 bits')
|
||||
if not re.search(r"^[0-9A-Za-z_/\\]$+",get.datadir): return public.returnMsg(False,'Special symbols cannot be included in the database path')
|
||||
if not os.path.exists(get.datadir): public.ExecShell('mkdir -p ' + get.datadir)
|
||||
mysqlInfo = self.GetMySQLInfo(get)
|
||||
if mysqlInfo['datadir'] == get.datadir: return public.returnMsg(False,'DATABASE_MOVE_RE')
|
||||
|
||||
@@ -125,6 +125,8 @@ class FileExecuteDeny:
|
||||
reg = '\s*#BEGIN_DENY_{n}\n(.|\n)*#END_DENY_{n}\n'.format(n=name)
|
||||
conf = re.sub(reg,'',conf)
|
||||
else:
|
||||
if dir[0] != '/':dir = '/'+dir
|
||||
if dir[-1] != '/':dir = dir+'/'
|
||||
new = '''
|
||||
#BEGIN_DENY_%s
|
||||
location ~* ^%s.*.(%s)$ {
|
||||
@@ -146,9 +148,11 @@ class FileExecuteDeny:
|
||||
reg = '\s*#BEGIN_DENY_{n}\n(.|\n)*#END_DENY_{n}'.format(n=name)
|
||||
conf = re.sub(reg,'',conf)
|
||||
else:
|
||||
if dir[0] != '/':dir = '/'+dir
|
||||
if dir[-1] != '/':dir = dir+'/'
|
||||
new = '''
|
||||
#BEGIN_DENY_{n}
|
||||
<Directory ~ "{d}.*\.(s)$">
|
||||
<Directory ~ "{d}.*\.({s})$">
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</Directory>
|
||||
|
||||
+204
-26
@@ -159,6 +159,10 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
text2 = html.escape(str_convert, quote=True)
|
||||
else:
|
||||
text2 = cgi.escape(str_convert, quote=True)
|
||||
|
||||
reps = {'&':'&'}
|
||||
for rep in reps.keys():
|
||||
if text2.find(rep) != -1: text2 = text2.replace(rep,reps[rep])
|
||||
return text2
|
||||
|
||||
# 上传文件
|
||||
@@ -184,6 +188,20 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
(filename, get['path']))
|
||||
return public.returnMsg(True, 'FILE_UPLOAD_SUCCESS')
|
||||
|
||||
def f_name_check(self,filename):
|
||||
'''
|
||||
@name 文件名检测2
|
||||
@author hwliang<2021-03-16>
|
||||
@param filename<string> 文件名
|
||||
@return bool
|
||||
'''
|
||||
f_strs = [';','&','<','>']
|
||||
for fs in f_strs:
|
||||
if filename.find(fs) != -1:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# 上传文件2
|
||||
def upload(self, args):
|
||||
if not 'f_name' in args:
|
||||
@@ -196,6 +214,9 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
args.f_name = args.f_name.encode('utf-8')
|
||||
args.f_path = args.f_path.encode('utf-8')
|
||||
|
||||
|
||||
if not self.f_name_check(args.f_name): return public.returnMsg(False,'FILE_NAME_ERR')
|
||||
|
||||
if args.f_path == '/':
|
||||
return public.returnMsg(False,'UPLOAD_DIR_ERR')
|
||||
|
||||
@@ -291,7 +312,8 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
if get.path == '':
|
||||
get.path = '/www'
|
||||
if not os.path.exists(get.path):
|
||||
return public.ReturnMsg(False,'DIR_NOT_EXISTS')
|
||||
get.path = '/www/wwwroot'
|
||||
#return public.ReturnMsg(False, '指定目录不存在!')
|
||||
if get.path == '/www/Recycle_bin':
|
||||
return public.returnMsg(False,'RECYCLE_BIN_ERR')
|
||||
if not os.path.isdir(get.path):
|
||||
@@ -670,6 +692,29 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
except:
|
||||
return public.returnMsg(False, 'FILE_CREATE_ERR')
|
||||
|
||||
#创建软链
|
||||
def CreateLink(self,get):
|
||||
'''
|
||||
@name 创建软链接
|
||||
@author hwliang<2021-03-23>
|
||||
@param get<dict_obj{
|
||||
sfile<string> 源文件
|
||||
dfile<string> 软链文件名
|
||||
}>
|
||||
@return dict
|
||||
'''
|
||||
|
||||
if not 'sfile' in get: return public.returnMsg(False,'INIT_ARGS_ERR')
|
||||
if not os.path.exists(get.sfile): return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
if os.path.exists(get.dfile): return public.returnMsg(False,'SOFTCHAIN_FILE_EXIST')
|
||||
if get.dfile[0] != '/': return public.returnMsg(False,'SOFTCHAIN_FILE_PATH')
|
||||
public.ExecShell("ln -sf {} {}".format(get.sfile,get.dfile))
|
||||
if not os.path.exists(get.dfile): return public.returnMsg(False,'SOFTLINK_CREATE_ERR')
|
||||
public.WriteLog('TYPE_FIREWALL','CREATE_SOFTLINK',(get.dfile,get.sfile))
|
||||
return public.returnMsg(True,'SOFTLINK_CREATE_SUCCESS')
|
||||
|
||||
|
||||
|
||||
# 创建目录
|
||||
def CreateDir(self, get):
|
||||
if sys.version_info[0] == 2:
|
||||
@@ -828,6 +873,9 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
data['files'].append(tmp)
|
||||
except:
|
||||
continue
|
||||
|
||||
data['dirs'] = sorted(data['dirs'],key = lambda x: x['time'],reverse=True)
|
||||
data['files'] = sorted(data['files'],key = lambda x: x['time'],reverse=True)
|
||||
return data
|
||||
|
||||
# 彻底删除
|
||||
@@ -1494,11 +1542,6 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
os.remove(sfile)
|
||||
return True
|
||||
|
||||
|
||||
#创建软链
|
||||
def create_link(self,args):
|
||||
pass
|
||||
|
||||
# 复制目录
|
||||
def copytree(self, sfile, dfile):
|
||||
if sfile == dfile:
|
||||
@@ -1506,6 +1549,8 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
if not os.path.exists(dfile):
|
||||
os.makedirs(dfile)
|
||||
for f_name in os.listdir(sfile):
|
||||
if not f_name.strip(): continue
|
||||
if f_name.find('./') != -1: continue
|
||||
src_filename = (sfile + '/' + f_name).replace('//', '/')
|
||||
dst_filename = (dfile + '/' + f_name).replace('//', '/')
|
||||
mode_info = public.get_mode_and_user(src_filename)
|
||||
@@ -1964,7 +2009,13 @@ cd %s
|
||||
return public.returnMsg(False, 'ADDRESS_NOT_EXIST')
|
||||
pdata = {}
|
||||
if 'expire' in get: pdata['expire'] = get.expire
|
||||
if 'password' in get: pdata['password'] = get.password
|
||||
if 'password' in get:
|
||||
pdata['password'] = get.password
|
||||
if len(pdata['password']) < 4 and len(pdata['password']) > 0:
|
||||
return public.returnMsg(False,'The length of the extracted password cannot be less than 4 digits')
|
||||
if not re.match('^\w+$',pdata['password']):
|
||||
return public.returnMsg(False,'No special symbols can be used in the extracted password')
|
||||
|
||||
if 'ps' in get: pdata['ps'] = get.ps
|
||||
public.M(my_table).where('id=?', (id,)).update(pdata)
|
||||
return public.returnMsg(True, 'EDIT_SUCCESS')
|
||||
@@ -1986,6 +2037,8 @@ cd %s
|
||||
}
|
||||
if len(pdata['password']) < 4 and len(pdata['password']) > 0:
|
||||
return public.returnMsg(False,'PASSWD_ERR')
|
||||
if not re.match('^\w+$',pdata['password']):
|
||||
return public.returnMsg(False,'No special symbols can be used in the extracted password')
|
||||
#更新 or 插入
|
||||
token = public.M(my_table).where('filename=?',(get.filename,)).getField('token')
|
||||
if token:
|
||||
@@ -2002,10 +2055,10 @@ cd %s
|
||||
|
||||
#取PHP-CLI执行命令
|
||||
def __get_php_bin(self,php_version=None):
|
||||
php_vs = ["80","74","73","72","71","70","56","55","54","53","52"]
|
||||
php_vs = ["80","74","73","72","71","70","56","55","54","53"]
|
||||
if php_version:
|
||||
if php_version != 'auto':
|
||||
if not php_version in php_vs: return False
|
||||
if not php_version in php_vs: return ''
|
||||
else:
|
||||
php_version = None
|
||||
|
||||
@@ -2020,9 +2073,9 @@ cd %s
|
||||
php_v = pv
|
||||
break
|
||||
# 如果没安装直接返回False
|
||||
if not php_v: return False
|
||||
# 处理PHP-CLI-INI配置文件
|
||||
php_ini = '/tmp/composer_php_cli_' + php_v + '.ini'
|
||||
if not php_v: return ''
|
||||
#处理PHP-CLI-INI配置文件
|
||||
php_ini = '/www/server/panel/tmp/composer_php_cli_'+php_v+'.ini'
|
||||
if not os.path.exists(php_ini):
|
||||
# 如果不存在,则从PHP安装目录下复制一份
|
||||
src_php_ini = php_path + php_v + '/etc/php.ini'
|
||||
@@ -2045,8 +2098,12 @@ cd %s
|
||||
# 安装composer
|
||||
def get_composer_bin(self):
|
||||
composer_bin = '/usr/bin/composer'
|
||||
download_addr = 'wget -O {} {}/install/src/composer.phper -T 5'.format(composer_bin,public.get_url())
|
||||
if not os.path.exists(composer_bin):
|
||||
public.ExecShell('wget -O {} {}/install/src/composer.phper -T 5'.format(composer_bin,public.get_url()))
|
||||
public.ExecShell(download_addr)
|
||||
elif os.path.getsize(composer_bin) < 100:
|
||||
public.ExecShell(download_addr)
|
||||
|
||||
public.ExecShell('chmod +x {}'.format(composer_bin))
|
||||
if not os.path.exists(composer_bin):
|
||||
return False
|
||||
@@ -2068,16 +2125,28 @@ cd %s
|
||||
return public.returnMsg(False,'PHP_VER_NOT_FOUND')
|
||||
if not os.path.exists(get.path + '/composer.json'):
|
||||
return public.returnMsg(False,'COMPOSER_CONF_NOT_FOUND')
|
||||
log_file = '/tmp/composer.log'
|
||||
user = ''
|
||||
if 'user' in get:
|
||||
user = 'sudo -u {} '.format(get.user)
|
||||
if not os.path.exists('/usr/bin/sudo'):
|
||||
if os.path.exists('/usr/bin/apt'):
|
||||
public.ExecShell("apt install sudo -y > {}".format(log_file))
|
||||
else:
|
||||
public.ExecShell("yum install sudo -y > {}".format(log_file))
|
||||
public.ExecShell("mkdir -p /home/www && chown -R www:www /home/www")
|
||||
|
||||
#设置指定源
|
||||
if 'repo' in get:
|
||||
if get.repo != 'repos.packagist':
|
||||
public.ExecShell('{} {} config -g repo.packagist composer {}'.format(php_bin,composer_bin,get.repo))
|
||||
public.ExecShell('export COMPOSER_HOME=/tmp && {}{} {} config -g repo.packagist composer {}'.format(user,php_bin,composer_bin,get.repo))
|
||||
else:
|
||||
public.ExecShell('{} {} config -g --unset repos.packagist'.format(php_bin,composer_bin))
|
||||
public.ExecShell('export COMPOSER_HOME=/tmp && {}{} {} config -g --unset repos.packagist'.format(user,php_bin,composer_bin))
|
||||
#执行composer命令
|
||||
composer_exec_str = '{} {} {} -vvv'.format(php_bin,composer_bin,get.composer_args)
|
||||
public.ExecShell("cd {} && nohup {} &> /tmp/panelExec.pl &".format(get.path,composer_exec_str))
|
||||
public.WriteLog('Composer',composer_exec_str)
|
||||
if os.path.exists(log_file): os.remove(log_file)
|
||||
public.ExecShell("cd {} && export COMPOSER_HOME=/tmp && {} nohup {} &> {} && echo 'BT-Exec-Completed' >> {} && rm -rf /home/www &".format(get.path,user,composer_exec_str,log_file,log_file))
|
||||
public.WriteLog('Composer',"EXEC_COMPOSER",(get.path,get.composer_args))
|
||||
return public.returnMsg(True,'COMMAND_SENT')
|
||||
|
||||
# 取composer版本
|
||||
@@ -2089,13 +2158,22 @@ cd %s
|
||||
try:
|
||||
bs = str(public.readFile(composer_bin,'rb'))
|
||||
result = re.findall(r"const VERSION\s*=\s*.{0,2}'([\d\.]+)",bs)[0]
|
||||
if not result: raise Exception('empty!')
|
||||
except:
|
||||
php_bin = self.__get_php_bin()
|
||||
composer_exec_str = php_bin + ' ' + composer_bin +' --version 2>/dev/null|grep \'Composer version\'|awk \'{print $3}\''
|
||||
if not php_bin: return public.returnMsg(False,'No available PHP version found!')
|
||||
composer_exec_str = 'export COMPOSER_HOME=/tmp && ' + php_bin + ' ' + composer_bin +' --version 2>/dev/null|grep \'Composer version\'|awk \'{print $3}\''
|
||||
result = public.ExecShell(composer_exec_str)[0].strip()
|
||||
data = public.returnMsg(True,result)
|
||||
import panelSite
|
||||
data['php_versions'] = panelSite.panelSite().GetPHPVersion(get)
|
||||
if 'path' in get:
|
||||
import panelSite
|
||||
data['php_versions'] = panelSite.panelSite().GetPHPVersion(get)
|
||||
data['comp_json'] = True
|
||||
data['comp_lock'] = False
|
||||
if not os.path.exists(get.path + '/composer.json'):
|
||||
data['comp_json'] = public.getMsg('COMPOSER_CONF_NOT_EXIST')
|
||||
if os.path.exists(get.path + '/composer.lock'):
|
||||
data['comp_lock'] = public.getMsg('COMPOSERLOGCK_EXIST')
|
||||
return data
|
||||
|
||||
# 升级composer版本
|
||||
@@ -2104,15 +2182,15 @@ cd %s
|
||||
if not composer_bin:
|
||||
return public.returnMsg(False,'NO_COMPOSER_AVAILABLE')
|
||||
php_bin = self.__get_php_bin()
|
||||
|
||||
if not php_bin: return public.returnMsg(False,'No available PHP version found!')
|
||||
#设置指定源
|
||||
if 'repo' in get:
|
||||
if get.repo:
|
||||
public.ExecShell('{} {} config -g repo.packagist composer {}'.format(php_bin,composer_bin,get.repo))
|
||||
# if 'repo' in get:
|
||||
# if get.repo:
|
||||
# public.ExecShell('{} {} config -g repo.packagist composer {}'.format(php_bin,composer_bin,get.repo))
|
||||
|
||||
version1 = self.get_composer_version(get)['msg']
|
||||
composer_exec_str = '{} {} self-update -vvv'.format(php_bin,composer_bin)
|
||||
public.ExecShell(composer_exec_str)[0]
|
||||
composer_exec_str = 'export COMPOSER_HOME=/tmp && {} {} self-update -vvv'.format(php_bin,composer_bin)
|
||||
public.ExecShell(composer_exec_str)
|
||||
version2 = self.get_composer_version(get)['msg']
|
||||
if version1 == version2:
|
||||
msg = public.getMsg("COMPOSER_UPDATE_ERR")
|
||||
@@ -2121,6 +2199,106 @@ cd %s
|
||||
public.WriteLog('Composer',msg)
|
||||
return public.returnMsg(True,msg)
|
||||
|
||||
# 计算文件HASH
|
||||
def get_file_hash(self,args=None,filename=None):
|
||||
if not filename: filename = args.filename
|
||||
import hashlib
|
||||
md5_obj = hashlib.md5()
|
||||
sha1_obj = hashlib.sha1()
|
||||
f = open(filename,'rb')
|
||||
while True:
|
||||
b = f.read(8096)
|
||||
if not b :
|
||||
break
|
||||
md5_obj.update(b)
|
||||
sha1_obj.update(b)
|
||||
f.close()
|
||||
return {'md5':md5_obj.hexdigest(),'sha1':sha1_obj.hexdigest()}
|
||||
|
||||
|
||||
# 取历史副本
|
||||
def get_history_info(self, filename):
|
||||
try:
|
||||
save_path = ('/www/backup/file_history/' +
|
||||
filename).replace('//', '/')
|
||||
if not os.path.exists(save_path):
|
||||
return []
|
||||
result = []
|
||||
for f in sorted(os.listdir(save_path)):
|
||||
f_name = (save_path + '/' + f).replace('//', '/')
|
||||
pdata = {}
|
||||
pdata['md5'] = public.FileMd5(f_name)
|
||||
f_stat = os.stat(f_name)
|
||||
pdata['st_mtime'] = int(f)
|
||||
pdata['st_size'] = f_stat.st_size
|
||||
pdata['history_file'] = f_name
|
||||
result.append(pdata)
|
||||
return result
|
||||
except:
|
||||
return []
|
||||
|
||||
#获取文件扩展名
|
||||
def get_file_ext(self,filename):
|
||||
ss_exts = ['tar.gz','tar.bz2','tar.bz']
|
||||
for s in ss_exts:
|
||||
e_len = len(s)
|
||||
f_len = len(filename)
|
||||
if f_len < e_len: continue
|
||||
if filename[-e_len:] == s:
|
||||
return s
|
||||
if filename.find('.') == -1: return ''
|
||||
return filename.split('.')[-1]
|
||||
|
||||
|
||||
# 取所属用户或组
|
||||
def get_mode_user(self,uid):
|
||||
import pwd
|
||||
try:
|
||||
return pwd.getpwuid(uid).pw_name
|
||||
except:
|
||||
return uid
|
||||
|
||||
|
||||
# 取指定文件属性
|
||||
def get_file_attribute(self,args):
|
||||
filename = args.filename.strip()
|
||||
if not os.path.exists(filename):
|
||||
return public.returnMsg(False,'the specified file does not exist!')
|
||||
attribute = {}
|
||||
attribute['name'] = os.path.basename(filename)
|
||||
attribute['path'] = os.path.dirname(filename)
|
||||
f_stat = os.stat(filename)
|
||||
attribute['st_atime'] = int(f_stat.st_atime) # 最后访问时间
|
||||
attribute['st_mtime'] = int(f_stat.st_mtime) # 最后修改时间
|
||||
attribute['st_ctime'] = int(f_stat.st_ctime) # 元数据修改时间/权限或数据者变更时间
|
||||
attribute['st_size'] = f_stat.st_size # 文件大小(bytes)
|
||||
attribute['st_gid'] = f_stat.st_gid # 用户组id
|
||||
attribute['st_uid'] = f_stat.st_uid # 用户id
|
||||
attribute['st_nlink'] = f_stat.st_nlink # inode 的链接数
|
||||
attribute['st_ino'] = f_stat.st_ino # inode 的节点号
|
||||
attribute['st_mode'] = f_stat.st_mode # inode 保护模式
|
||||
attribute['st_dev'] = f_stat.st_dev # inode 驻留设备
|
||||
attribute['user'] = self.get_mode_user(f_stat.st_uid) # 所属用户
|
||||
attribute['group'] = self.get_mode_user(f_stat.st_gid) # 所属组
|
||||
attribute['mode'] = str(oct(f_stat.st_mode)[-3:]) # 文件权限号
|
||||
attribute['md5'] = 'Do not count files or directories larger than 100MB' # 文件MD5
|
||||
attribute['sha1'] = 'Do not count files or directories larger than 100MB' # 文件sha1
|
||||
attribute['is_dir'] = os.path.isdir(filename) # 是否为目录
|
||||
attribute['is_link'] = os.path.islink(filename) # 是否为链接文件
|
||||
if attribute['is_link']:
|
||||
attribute['st_type'] = 'Link file'
|
||||
elif attribute['is_dir']:
|
||||
attribute['st_type'] = 'Dir'
|
||||
else:
|
||||
attribute['st_type'] = self.get_file_ext(filename)
|
||||
attribute['history'] = []
|
||||
if f_stat.st_size < 104857600 and not attribute['is_dir']:
|
||||
hash_info = self.get_file_hash(filename=filename)
|
||||
attribute['md5'] = hash_info['md5']
|
||||
attribute['sha1'] = hash_info['sha1']
|
||||
attribute['history'] = self.get_history_info(filename) # 历史文件
|
||||
return attribute
|
||||
|
||||
# 数据库对象
|
||||
def _get_sqlite_connect(self):
|
||||
try:
|
||||
|
||||
@@ -2,7 +2,7 @@ import sys
|
||||
from gzip import GzipFile
|
||||
from io import BytesIO
|
||||
|
||||
from flask import request, current_app
|
||||
from flask import request, current_app,session,Response
|
||||
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
@@ -78,7 +78,7 @@ class Compress(object):
|
||||
def after_request(self, response):
|
||||
app = self.app or current_app
|
||||
accept_encoding = request.headers.get('Accept-Encoding', '')
|
||||
|
||||
response.headers['Server'] = 'nginx'
|
||||
if (response.mimetype not in app.config['COMPRESS_MIMETYPES'] or
|
||||
'gzip' not in accept_encoding.lower() or
|
||||
not 200 <= response.status_code < 300 or
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flaskext.session
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Adds server session support to your application.
|
||||
|
||||
:copyright: (c) 2014 by Shipeng Feng.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
__version__ = '0.3.0'
|
||||
|
||||
import os
|
||||
|
||||
from .sessions import NullSessionInterface, RedisSessionInterface, \
|
||||
MemcachedSessionInterface, FileSystemSessionInterface, \
|
||||
MongoDBSessionInterface, SqlAlchemySessionInterface
|
||||
|
||||
|
||||
class Session(object):
|
||||
"""This class is used to add Server-side Session to one or more Flask
|
||||
applications.
|
||||
|
||||
There are two usage modes. One is initialize the instance with a very
|
||||
specific Flask application::
|
||||
|
||||
app = Flask(__name__)
|
||||
Session(app)
|
||||
|
||||
The second possibility is to create the object once and configure the
|
||||
application later::
|
||||
|
||||
sess = Session()
|
||||
|
||||
def create_app():
|
||||
app = Flask(__name__)
|
||||
sess.init_app(app)
|
||||
return app
|
||||
|
||||
By default Flask-Session will use :class:`NullSessionInterface`, you
|
||||
really should configurate your app to use a different SessionInterface.
|
||||
|
||||
.. note::
|
||||
|
||||
You can not use ``Session`` instance directly, what ``Session`` does
|
||||
is just change the :attr:`~flask.Flask.session_interface` attribute on
|
||||
your Flask applications.
|
||||
"""
|
||||
|
||||
def __init__(self, app=None):
|
||||
self.app = app
|
||||
if app is not None:
|
||||
self.init_app(app)
|
||||
|
||||
def init_app(self, app):
|
||||
"""This is used to set up session for your app object.
|
||||
|
||||
:param app: the Flask app object with proper configuration.
|
||||
"""
|
||||
app.session_interface = self._get_interface(app)
|
||||
|
||||
def _get_interface(self, app):
|
||||
config = app.config.copy()
|
||||
config.setdefault('SESSION_TYPE', 'null')
|
||||
config.setdefault('SESSION_PERMANENT', True)
|
||||
config.setdefault('SESSION_USE_SIGNER', False)
|
||||
config.setdefault('SESSION_KEY_PREFIX', 'session:')
|
||||
config.setdefault('SESSION_REDIS', None)
|
||||
config.setdefault('SESSION_MEMCACHED', None)
|
||||
config.setdefault('SESSION_FILE_DIR',
|
||||
os.path.join(os.getcwd(), 'flask_sessionstore'))
|
||||
config.setdefault('SESSION_FILE_THRESHOLD', 500)
|
||||
config.setdefault('SESSION_FILE_MODE', 384)
|
||||
config.setdefault('SESSION_MONGODB', None)
|
||||
config.setdefault('SESSION_MONGODB_DB', 'flask_sessionstore')
|
||||
config.setdefault('SESSION_MONGODB_COLLECT', 'sessions')
|
||||
config.setdefault('SESSION_SQLALCHEMY', None)
|
||||
config.setdefault('SESSION_SQLALCHEMY_TABLE', 'sessions')
|
||||
|
||||
if config['SESSION_TYPE'] == 'redis':
|
||||
session_interface = RedisSessionInterface(
|
||||
config['SESSION_REDIS'], config['SESSION_KEY_PREFIX'],
|
||||
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
|
||||
elif config['SESSION_TYPE'] == 'memcached':
|
||||
session_interface = MemcachedSessionInterface(
|
||||
config['SESSION_MEMCACHED'], config['SESSION_KEY_PREFIX'],
|
||||
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
|
||||
elif config['SESSION_TYPE'] == 'filesystem':
|
||||
session_interface = FileSystemSessionInterface(
|
||||
config['SESSION_FILE_DIR'], config['SESSION_FILE_THRESHOLD'],
|
||||
config['SESSION_FILE_MODE'], config['SESSION_KEY_PREFIX'],
|
||||
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
|
||||
elif config['SESSION_TYPE'] == 'mongodb':
|
||||
session_interface = MongoDBSessionInterface(
|
||||
config['SESSION_MONGODB'], config['SESSION_MONGODB_DB'],
|
||||
config['SESSION_MONGODB_COLLECT'],
|
||||
config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
|
||||
config['SESSION_PERMANENT'])
|
||||
elif config['SESSION_TYPE'] == 'sqlalchemy':
|
||||
session_interface = SqlAlchemySessionInterface(
|
||||
app, config['SESSION_SQLALCHEMY'],
|
||||
config['SESSION_SQLALCHEMY_TABLE'],
|
||||
config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
|
||||
config['SESSION_PERMANENT'])
|
||||
else:
|
||||
session_interface = NullSessionInterface()
|
||||
|
||||
return session_interface
|
||||
@@ -0,0 +1,563 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flaskext.session.sessions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Server-side Sessions and SessionInterfaces.
|
||||
|
||||
:copyright: (c) 2014 by Shipeng Feng.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
import pickle
|
||||
|
||||
from flask.sessions import SessionInterface as FlaskSessionInterface
|
||||
from flask.sessions import SessionMixin
|
||||
from werkzeug.datastructures import CallbackDict
|
||||
from itsdangerous import Signer, BadSignature, want_bytes
|
||||
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
if not PY2:
|
||||
text_type = str
|
||||
else:
|
||||
text_type = unicode
|
||||
|
||||
|
||||
def total_seconds(td):
|
||||
return td.days * 60 * 60 * 24 + td.seconds
|
||||
|
||||
|
||||
class ServerSideSession(CallbackDict, SessionMixin):
|
||||
"""Baseclass for server-side based sessions."""
|
||||
|
||||
def __init__(self, initial=None, sid=None, permanent=None):
|
||||
def on_update(self):
|
||||
self.modified = True
|
||||
CallbackDict.__init__(self, initial, on_update)
|
||||
self.sid = sid
|
||||
if permanent:
|
||||
self.permanent = permanent
|
||||
self.modified = False
|
||||
|
||||
|
||||
class RedisSession(ServerSideSession):
|
||||
pass
|
||||
|
||||
|
||||
class MemcachedSession(ServerSideSession):
|
||||
pass
|
||||
|
||||
|
||||
class FileSystemSession(ServerSideSession):
|
||||
pass
|
||||
|
||||
|
||||
class MongoDBSession(ServerSideSession):
|
||||
pass
|
||||
|
||||
|
||||
class SqlAlchemySession(ServerSideSession):
|
||||
pass
|
||||
|
||||
|
||||
class SessionInterface(FlaskSessionInterface):
|
||||
|
||||
def _generate_sid(self):
|
||||
return str(uuid4())
|
||||
|
||||
def _get_signer(self, app):
|
||||
if not app.secret_key:
|
||||
return None
|
||||
return Signer(app.secret_key, salt='flask-sessions',
|
||||
key_derivation='hmac')
|
||||
|
||||
|
||||
class NullSessionInterface(SessionInterface):
|
||||
"""Used to open a :class:`flask.sessions.NullSession` instance.
|
||||
"""
|
||||
|
||||
def open_session(self, app, request):
|
||||
return None
|
||||
|
||||
|
||||
class RedisSessionInterface(SessionInterface):
|
||||
"""Uses the Redis key-value store as a session backend.
|
||||
|
||||
.. versionadded:: 0.2
|
||||
The `use_signer` parameter was added.
|
||||
|
||||
:param redis: A ``redis.Redis`` instance.
|
||||
:param key_prefix: A prefix that is added to all Redis store keys.
|
||||
:param use_signer: Whether to sign the session id cookie or not.
|
||||
:param permanent: Whether to use permanent session or not.
|
||||
"""
|
||||
|
||||
serializer = pickle
|
||||
session_class = RedisSession
|
||||
|
||||
def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
|
||||
if redis is None:
|
||||
from redis import Redis
|
||||
redis = Redis()
|
||||
self.redis = redis
|
||||
self.key_prefix = key_prefix
|
||||
self.use_signer = use_signer
|
||||
self.permanent = permanent
|
||||
|
||||
def open_session(self, app, request):
|
||||
sid = request.cookies.get(app.session_cookie_name)
|
||||
if not sid:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
if self.use_signer:
|
||||
signer = self._get_signer(app)
|
||||
if signer is None:
|
||||
return None
|
||||
try:
|
||||
sid_as_bytes = signer.unsign(sid)
|
||||
sid = sid_as_bytes.decode()
|
||||
except BadSignature:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
if not PY2 and not isinstance(sid, text_type):
|
||||
sid = sid.decode('utf-8', 'strict')
|
||||
val = self.redis.get(self.key_prefix + sid)
|
||||
if val is not None:
|
||||
try:
|
||||
data = self.serializer.loads(val)
|
||||
return self.session_class(data, sid=sid)
|
||||
except:
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
def save_session(self, app, session, response):
|
||||
domain = self.get_cookie_domain(app)
|
||||
path = self.get_cookie_path(app)
|
||||
if not session:
|
||||
if session.modified:
|
||||
self.redis.delete(self.key_prefix + session.sid)
|
||||
response.delete_cookie(app.session_cookie_name,
|
||||
domain=domain, path=path)
|
||||
return
|
||||
|
||||
# Modification case. There are upsides and downsides to
|
||||
# emitting a set-cookie header each request. The behavior
|
||||
# is controlled by the :meth:`should_set_cookie` method
|
||||
# which performs a quick check to figure out if the cookie
|
||||
# should be set or not. This is controlled by the
|
||||
# SESSION_REFRESH_EACH_REQUEST config flag as well as
|
||||
# the permanent flag on the session itself.
|
||||
# if not self.should_set_cookie(app, session):
|
||||
# return
|
||||
|
||||
httponly = self.get_cookie_httponly(app)
|
||||
secure = self.get_cookie_secure(app)
|
||||
expires = self.get_expiration_time(app, session)
|
||||
val = self.serializer.dumps(dict(session))
|
||||
self.redis.setex(name=self.key_prefix + session.sid, value=val,
|
||||
time=total_seconds(app.permanent_session_lifetime))
|
||||
if self.use_signer:
|
||||
session_id = self._get_signer(app).sign(want_bytes(session.sid))
|
||||
else:
|
||||
session_id = session.sid
|
||||
response.set_cookie(app.session_cookie_name, session_id,
|
||||
expires=expires, httponly=httponly,
|
||||
domain=domain, path=path, secure=secure)
|
||||
|
||||
|
||||
class MemcachedSessionInterface(SessionInterface):
|
||||
"""A Session interface that uses memcached as backend.
|
||||
|
||||
.. versionadded:: 0.2
|
||||
The `use_signer` parameter was added.
|
||||
|
||||
:param client: A ``memcache.Client`` instance.
|
||||
:param key_prefix: A prefix that is added to all Memcached store keys.
|
||||
:param use_signer: Whether to sign the session id cookie or not.
|
||||
:param permanent: Whether to use permanent session or not.
|
||||
"""
|
||||
|
||||
serializer = pickle
|
||||
session_class = MemcachedSession
|
||||
|
||||
def __init__(self, client, key_prefix, use_signer=False, permanent=True):
|
||||
if client is None:
|
||||
client = self._get_preferred_memcache_client()
|
||||
if client is None:
|
||||
raise RuntimeError('no memcache module found')
|
||||
self.client = client
|
||||
self.key_prefix = key_prefix
|
||||
self.use_signer = use_signer
|
||||
self.permanent = permanent
|
||||
|
||||
def _get_preferred_memcache_client(self):
|
||||
servers = ['127.0.0.1:11211']
|
||||
try:
|
||||
import pylibmc
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return pylibmc.Client(servers)
|
||||
|
||||
try:
|
||||
import memcache
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return memcache.Client(servers)
|
||||
|
||||
def _get_memcache_timeout(self, timeout):
|
||||
"""
|
||||
Memcached deals with long (> 30 days) timeouts in a special
|
||||
way. Call this function to obtain a safe value for your timeout.
|
||||
"""
|
||||
if timeout > 2592000: # 60*60*24*30, 30 days
|
||||
# See http://code.google.com/p/memcached/wiki/FAQ
|
||||
# "You can set expire times up to 30 days in the future. After that
|
||||
# memcached interprets it as a date, and will expire the item after
|
||||
# said date. This is a simple (but obscure) mechanic."
|
||||
#
|
||||
# This means that we have to switch to absolute timestamps.
|
||||
timeout += int(time.time())
|
||||
return timeout
|
||||
|
||||
def open_session(self, app, request):
|
||||
sid = request.cookies.get(app.session_cookie_name)
|
||||
if not sid:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
if self.use_signer:
|
||||
signer = self._get_signer(app)
|
||||
if signer is None:
|
||||
return None
|
||||
try:
|
||||
sid_as_bytes = signer.unsign(sid)
|
||||
sid = sid_as_bytes.decode()
|
||||
except BadSignature:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
full_session_key = self.key_prefix + sid
|
||||
if PY2 and isinstance(full_session_key, unicode):
|
||||
full_session_key = full_session_key.encode('utf-8')
|
||||
val = self.client.get(full_session_key)
|
||||
if val is not None:
|
||||
try:
|
||||
if not PY2:
|
||||
val = want_bytes(val)
|
||||
data = self.serializer.loads(val)
|
||||
return self.session_class(data, sid=sid)
|
||||
except:
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
def save_session(self, app, session, response):
|
||||
domain = self.get_cookie_domain(app)
|
||||
path = self.get_cookie_path(app)
|
||||
full_session_key = self.key_prefix + session.sid
|
||||
if PY2 and isinstance(full_session_key, unicode):
|
||||
full_session_key = full_session_key.encode('utf-8')
|
||||
if not session:
|
||||
if session.modified:
|
||||
self.client.delete(full_session_key)
|
||||
response.delete_cookie(app.session_cookie_name,
|
||||
domain=domain, path=path)
|
||||
return
|
||||
|
||||
httponly = self.get_cookie_httponly(app)
|
||||
secure = self.get_cookie_secure(app)
|
||||
expires = self.get_expiration_time(app, session)
|
||||
if not PY2:
|
||||
val = self.serializer.dumps(dict(session), 0)
|
||||
else:
|
||||
val = self.serializer.dumps(dict(session))
|
||||
self.client.set(full_session_key, val, self._get_memcache_timeout(
|
||||
total_seconds(app.permanent_session_lifetime)))
|
||||
if self.use_signer:
|
||||
session_id = self._get_signer(app).sign(want_bytes(session.sid))
|
||||
else:
|
||||
session_id = session.sid
|
||||
response.set_cookie(app.session_cookie_name, session_id,
|
||||
expires=expires, httponly=httponly,
|
||||
domain=domain, path=path, secure=secure)
|
||||
|
||||
|
||||
class FileSystemSessionInterface(SessionInterface):
|
||||
"""Uses the :class:`werkzeug.contrib.cache.FileSystemCache` as a session
|
||||
backend.
|
||||
|
||||
.. versionadded:: 0.2
|
||||
The `use_signer` parameter was added.
|
||||
|
||||
:param cache_dir: the directory where session files are stored.
|
||||
:param threshold: the maximum number of items the session stores before it
|
||||
starts deleting some.
|
||||
:param mode: the file mode wanted for the session files, default 0600
|
||||
:param key_prefix: A prefix that is added to FileSystemCache store keys.
|
||||
:param use_signer: Whether to sign the session id cookie or not.
|
||||
:param permanent: Whether to use permanent session or not.
|
||||
"""
|
||||
|
||||
session_class = FileSystemSession
|
||||
|
||||
def __init__(self, cache_dir, threshold, mode, key_prefix,
|
||||
use_signer=False, permanent=True):
|
||||
from werkzeug.contrib.cache import FileSystemCache
|
||||
self.cache = FileSystemCache(cache_dir, threshold=threshold, mode=mode)
|
||||
self.key_prefix = key_prefix
|
||||
self.use_signer = use_signer
|
||||
self.permanent = permanent
|
||||
|
||||
def open_session(self, app, request):
|
||||
sid = request.cookies.get(app.session_cookie_name)
|
||||
if not sid:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
if self.use_signer:
|
||||
signer = self._get_signer(app)
|
||||
if signer is None:
|
||||
return None
|
||||
try:
|
||||
sid_as_bytes = signer.unsign(sid)
|
||||
sid = sid_as_bytes.decode()
|
||||
except BadSignature:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
data = self.cache.get(self.key_prefix + sid)
|
||||
if data is not None:
|
||||
return self.session_class(data, sid=sid)
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
def save_session(self, app, session, response):
|
||||
domain = self.get_cookie_domain(app)
|
||||
path = self.get_cookie_path(app)
|
||||
if not session:
|
||||
if session.modified:
|
||||
self.cache.delete(self.key_prefix + session.sid)
|
||||
response.delete_cookie(app.session_cookie_name,
|
||||
domain=domain, path=path)
|
||||
return
|
||||
|
||||
httponly = self.get_cookie_httponly(app)
|
||||
secure = self.get_cookie_secure(app)
|
||||
expires = self.get_expiration_time(app, session)
|
||||
data = dict(session)
|
||||
self.cache.set(self.key_prefix + session.sid, data,
|
||||
total_seconds(app.permanent_session_lifetime))
|
||||
if self.use_signer:
|
||||
session_id = self._get_signer(app).sign(want_bytes(session.sid))
|
||||
else:
|
||||
session_id = session.sid
|
||||
response.set_cookie(app.session_cookie_name, session_id,
|
||||
expires=expires, httponly=httponly,
|
||||
domain=domain, path=path, secure=secure)
|
||||
|
||||
|
||||
class MongoDBSessionInterface(SessionInterface):
|
||||
"""A Session interface that uses mongodb as backend.
|
||||
|
||||
.. versionadded:: 0.2
|
||||
The `use_signer` parameter was added.
|
||||
|
||||
:param client: A ``pymongo.MongoClient`` instance.
|
||||
:param db: The database you want to use.
|
||||
:param collection: The collection you want to use.
|
||||
:param key_prefix: A prefix that is added to all MongoDB store keys.
|
||||
:param use_signer: Whether to sign the session id cookie or not.
|
||||
:param permanent: Whether to use permanent session or not.
|
||||
"""
|
||||
|
||||
serializer = pickle
|
||||
session_class = MongoDBSession
|
||||
|
||||
def __init__(self, client, db, collection, key_prefix, use_signer=False,
|
||||
permanent=True):
|
||||
if client is None:
|
||||
from pymongo import MongoClient
|
||||
client = MongoClient()
|
||||
self.client = client
|
||||
self.store = client[db][collection]
|
||||
self.key_prefix = key_prefix
|
||||
self.use_signer = use_signer
|
||||
self.permanent = permanent
|
||||
|
||||
def open_session(self, app, request):
|
||||
sid = request.cookies.get(app.session_cookie_name)
|
||||
if not sid:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
if self.use_signer:
|
||||
signer = self._get_signer(app)
|
||||
if signer is None:
|
||||
return None
|
||||
try:
|
||||
sid_as_bytes = signer.unsign(sid)
|
||||
sid = sid_as_bytes.decode()
|
||||
except BadSignature:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
store_id = self.key_prefix + sid
|
||||
document = self.store.find_one({'id': store_id})
|
||||
if document and document.get('expiration') <= datetime.utcnow():
|
||||
# Delete expired session
|
||||
self.store.remove({'id': store_id})
|
||||
document = None
|
||||
if document is not None:
|
||||
try:
|
||||
val = document['val']
|
||||
data = self.serializer.loads(want_bytes(val))
|
||||
return self.session_class(data, sid=sid)
|
||||
except:
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
def save_session(self, app, session, response):
|
||||
domain = self.get_cookie_domain(app)
|
||||
path = self.get_cookie_path(app)
|
||||
store_id = self.key_prefix + session.sid
|
||||
if not session:
|
||||
if session.modified:
|
||||
self.store.remove({'id': store_id})
|
||||
response.delete_cookie(app.session_cookie_name,
|
||||
domain=domain, path=path)
|
||||
return
|
||||
|
||||
httponly = self.get_cookie_httponly(app)
|
||||
secure = self.get_cookie_secure(app)
|
||||
expires = self.get_expiration_time(app, session)
|
||||
val = self.serializer.dumps(dict(session))
|
||||
self.store.update({'id': store_id},
|
||||
{'id': store_id,
|
||||
'val': val,
|
||||
'expiration': expires}, True)
|
||||
if self.use_signer:
|
||||
session_id = self._get_signer(app).sign(want_bytes(session.sid))
|
||||
else:
|
||||
session_id = session.sid
|
||||
response.set_cookie(app.session_cookie_name, session_id,
|
||||
expires=expires, httponly=httponly,
|
||||
domain=domain, path=path, secure=secure)
|
||||
|
||||
|
||||
class SqlAlchemySessionInterface(SessionInterface):
|
||||
"""Uses the Flask-SQLAlchemy from a flask app as a session backend.
|
||||
|
||||
.. versionadded:: 0.2
|
||||
|
||||
:param app: A Flask app instance.
|
||||
:param db: A Flask-SQLAlchemy instance.
|
||||
:param table: The table name you want to use.
|
||||
:param key_prefix: A prefix that is added to all store keys.
|
||||
:param use_signer: Whether to sign the session id cookie or not.
|
||||
:param permanent: Whether to use permanent session or not.
|
||||
"""
|
||||
|
||||
serializer = pickle
|
||||
session_class = SqlAlchemySession
|
||||
|
||||
def __init__(self, app, db, table, key_prefix, use_signer=False,
|
||||
permanent=True):
|
||||
if db is None:
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
db = SQLAlchemy(app)
|
||||
self.db = db
|
||||
self.key_prefix = key_prefix
|
||||
self.use_signer = use_signer
|
||||
self.permanent = permanent
|
||||
|
||||
class Session(self.db.Model):
|
||||
__tablename__ = table
|
||||
|
||||
id = self.db.Column(self.db.Integer, primary_key=True)
|
||||
session_id = self.db.Column(self.db.String(256), unique=True)
|
||||
data = self.db.Column(self.db.LargeBinary)
|
||||
expiry = self.db.Column(self.db.DateTime)
|
||||
|
||||
def __init__(self, session_id, data, expiry):
|
||||
self.session_id = session_id
|
||||
self.data = data
|
||||
self.expiry = expiry
|
||||
|
||||
def __repr__(self):
|
||||
return '<Session data %s>' % self.data
|
||||
|
||||
self.db.create_all()
|
||||
self.sql_session_model = Session
|
||||
|
||||
def open_session(self, app, request):
|
||||
sid = request.cookies.get(app.session_cookie_name)
|
||||
if not sid:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
if self.use_signer:
|
||||
signer = self._get_signer(app)
|
||||
if signer is None:
|
||||
return None
|
||||
try:
|
||||
sid_as_bytes = signer.unsign(sid)
|
||||
sid = sid_as_bytes.decode()
|
||||
except BadSignature:
|
||||
sid = self._generate_sid()
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
store_id = self.key_prefix + sid
|
||||
saved_session = self.sql_session_model.query.filter_by(
|
||||
session_id=store_id).first()
|
||||
if saved_session and saved_session.expiry <= datetime.utcnow():
|
||||
# Delete expired session
|
||||
self.db.session.delete(saved_session)
|
||||
self.db.session.commit()
|
||||
saved_session = None
|
||||
if saved_session:
|
||||
try:
|
||||
val = saved_session.data
|
||||
data = self.serializer.loads(want_bytes(val))
|
||||
return self.session_class(data, sid=sid)
|
||||
except:
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
return self.session_class(sid=sid, permanent=self.permanent)
|
||||
|
||||
def save_session(self, app, session, response):
|
||||
domain = self.get_cookie_domain(app)
|
||||
path = self.get_cookie_path(app)
|
||||
store_id = self.key_prefix + session.sid
|
||||
saved_session = self.sql_session_model.query.filter_by(
|
||||
session_id=store_id).first()
|
||||
if not session:
|
||||
if session.modified:
|
||||
if saved_session:
|
||||
self.db.session.delete(saved_session)
|
||||
self.db.session.commit()
|
||||
response.delete_cookie(app.session_cookie_name,
|
||||
domain=domain, path=path)
|
||||
return
|
||||
|
||||
httponly = self.get_cookie_httponly(app)
|
||||
secure = self.get_cookie_secure(app)
|
||||
expires = self.get_expiration_time(app, session)
|
||||
val = self.serializer.dumps(dict(session))
|
||||
if saved_session:
|
||||
saved_session.data = val
|
||||
saved_session.expiry = expires
|
||||
self.db.session.commit()
|
||||
else:
|
||||
new_session = self.sql_session_model(store_id, val, expires)
|
||||
self.db.session.add(new_session)
|
||||
self.db.session.commit()
|
||||
if self.use_signer:
|
||||
session_id = self._get_signer(app).sign(want_bytes(session.sid))
|
||||
else:
|
||||
session_id = session.sid
|
||||
response.set_cookie(app.session_cookie_name, session_id,
|
||||
expires=expires, httponly=httponly,
|
||||
domain=domain, path=path, secure=secure)
|
||||
@@ -34,6 +34,11 @@ class http:
|
||||
result = self._get_curl(url,timeout,headers,verify)
|
||||
elif type == 'php':
|
||||
result = self._get_php(url,timeout,headers,verify)
|
||||
elif type == 'src':
|
||||
if sys.version_info[0] == 2:
|
||||
result = self._get_py2(url,timeout,headers,verify)
|
||||
else:
|
||||
result = self._get_py3(url,timeout,headers,verify)
|
||||
return result
|
||||
|
||||
def post(self,url,data,timeout = 60,headers = {},verify = False,type = 'python'):
|
||||
@@ -51,6 +56,11 @@ class http:
|
||||
result = self._post_curl(url,data,timeout,headers,verify)
|
||||
elif type == 'php':
|
||||
result = self._post_php(url,data,timeout,headers,verify)
|
||||
elif type == 'src':
|
||||
if sys.version_info[0] == 2:
|
||||
result = self._post_py2(url,data,timeout,headers,verify)
|
||||
else:
|
||||
result = self._post_py3(url,data,timeout,headers,verify)
|
||||
return result
|
||||
|
||||
#POST请求 Python2
|
||||
|
||||
+41
-2
@@ -142,7 +142,7 @@ class nginx:
|
||||
log_format = loads(args.log_format)
|
||||
data = """
|
||||
#LOG_FORMAT_BEGIN_{n}
|
||||
log_format {n} '{c};'
|
||||
log_format {n} '{c}';
|
||||
#LOG_FORMAT_END_{n}
|
||||
""".format(n=args.log_format_name,c=' '.join(log_format))
|
||||
data = data.replace('$http_user_agent','"$http_user_agent"')
|
||||
@@ -171,6 +171,7 @@ class nginx:
|
||||
return public.returnMsg(False, 'NGINX_CONF_NOT_EXISTS')
|
||||
reg = '\s*#LOG_FORMAT_BEGIN_{n}(\n|.)+#LOG_FORMAT_END_{n}\n?'.format(n=args.log_format_name)
|
||||
conf = re.sub(reg,'',conf)
|
||||
self._del_format_log_of_website(args.log_format_name)
|
||||
public.writeFile(self.nginxconf,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
@@ -245,7 +246,10 @@ class nginx:
|
||||
if not conf:
|
||||
return public.returnMsg(False, 'NGINX_CONF_NOT_EXISTS')
|
||||
format_exist_reg = '(access_log\s+/www.*\.log).*;'
|
||||
access_log = re.search(format_exist_reg, conf).groups()[0] + ' ' + args.log_format_name + ';'
|
||||
access_log = self.get_nginx_access_log(conf)
|
||||
if not access_log:
|
||||
continue
|
||||
access_log = 'access_log '+ access_log + ' ' + args.log_format_name + ';'
|
||||
if site['name'] not in sites and re.search(format_exist_reg,conf):
|
||||
access_log = ' '.join(access_log.split()[:-1])+';'
|
||||
conf = re.sub(reg, access_log, conf)
|
||||
@@ -257,6 +261,22 @@ class nginx:
|
||||
except:
|
||||
return public.returnMsg(False, str(public.get_error_info()))
|
||||
|
||||
def get_nginx_access_log(self,nginx_conf):
|
||||
try:
|
||||
reg = 'access_log\s+(.*\.log)'
|
||||
log_path = re.findall(reg, nginx_conf)
|
||||
if not log_path:
|
||||
return False
|
||||
for i in log_path:
|
||||
if 'purge_cache' in i:
|
||||
continue
|
||||
if not os.path.exists(i):
|
||||
continue
|
||||
return i
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def _get_format_log_to_website(self,log_format_name):
|
||||
tmp = public.M('sites').field('name').select()
|
||||
reg = 'access_log.*{};'.format(log_format_name)
|
||||
@@ -272,3 +292,22 @@ class nginx:
|
||||
else:
|
||||
data[i['name']] = False
|
||||
return data
|
||||
|
||||
def _del_format_log_of_website(self,log_format_name):
|
||||
site_format_log_status = self._get_format_log_to_website(log_format_name)
|
||||
try:
|
||||
for s in site_format_log_status.keys():
|
||||
if not site_format_log_status[s]:
|
||||
continue
|
||||
website_conf_file = '/www/server/panel/vhost/nginx/{}.conf'.format(s)
|
||||
format_exist_reg = 'access_log\s+/www.*\.log\s+{};'.format(log_format_name)
|
||||
conf = public.readFile(website_conf_file)
|
||||
if not conf:continue
|
||||
if not re.search(format_exist_reg,conf):continue
|
||||
access_log = re.search(format_exist_reg,conf).group().split()
|
||||
access_log = access_log[0] + ' ' +access_log[1] +';'
|
||||
conf = re.sub(format_exist_reg,access_log,conf)
|
||||
public.writeFile(website_conf_file,conf)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
+2
-2
@@ -24,7 +24,7 @@ class panelApi:
|
||||
|
||||
data['limit_addr'] = '\n'.join(data['limit_addr'])
|
||||
data['bind'] = self.get_bind_token()
|
||||
qrcode = (public.getPanelAddr() + "|" + data['token'] + "|" + data['key'] + '|' + data['bind']['token']).encode('utf-8')
|
||||
qrcode = (public.getPanelAddr() + "|" + data['token'] + "|" + data['key'] + '|' + data['bind']['token']+'|aapanel').encode('utf-8')
|
||||
data['qrcode'] = public.base64.b64encode(qrcode).decode('utf-8')
|
||||
data['apps'] = sorted(data['apps'],key=lambda x: x['time'],reverse=True)
|
||||
del(data['key'])
|
||||
@@ -216,7 +216,7 @@ class panelApi:
|
||||
data['token'] = public.md5(token)
|
||||
data['token_crypt'] = public.en_crypt(data['token'],token).decode('utf-8')
|
||||
public.WriteLog('SET_API','%s API interface' % stats[data['open']])
|
||||
token = stats[data['open']] + 'success!'
|
||||
token = stats[data['open']] + ' success!'
|
||||
elif get.t_type == '3':
|
||||
data['limit_addr'] = get.limit_addr.split('\n')
|
||||
public.WriteLog('SET_API','Change IP limit to [%s]' % get.limit_addr)
|
||||
|
||||
+43
-4
@@ -12,7 +12,7 @@
|
||||
#------------------------------
|
||||
|
||||
import public,time,json,os,requests
|
||||
from BTPanel import session
|
||||
from BTPanel import session,cache
|
||||
|
||||
class panelAuth:
|
||||
__product_list_path = 'data/product_list.pl'
|
||||
@@ -63,11 +63,16 @@ class panelAuth:
|
||||
def get_plugin_price(self, get):
|
||||
try:
|
||||
userPath = 'data/userInfo.json'
|
||||
if not 'pluginName' in get: return public.returnMsg(False,'INIT_ARGS_ERR')
|
||||
if not 'pluginName' in get and not 'product_id' in get: return public.returnMsg(False,'INIT_ARGS_ERR')
|
||||
if not os.path.exists(userPath): return public.returnMsg(False,'LOGIN_FIRST')
|
||||
params = {}
|
||||
params['product_id'] = self.get_plugin_info(get.pluginName)['id']
|
||||
if not hasattr(get,'product_id'):
|
||||
params['product_id'] = self.get_plugin_info(get.pluginName)['id']
|
||||
else:
|
||||
params['product_id'] = get.product_id
|
||||
data = self.send_cloud('{}/api/product/prices'.format(self.__official_url), params)
|
||||
if len(data['res']) > 3:
|
||||
return data['res'][-3:]
|
||||
return data['res']
|
||||
except:
|
||||
del(session['get_product_list'])
|
||||
@@ -291,4 +296,38 @@ class panelAuth:
|
||||
data = self.send_cloud('{}/api/authorize/product/activate'.format(self.__official_url), params)
|
||||
if not data['success']: return public.returnMsg(False,'Activate Failed')
|
||||
session['focre_cloud'] = True
|
||||
return public.returnMsg(True,'Activate successfully')
|
||||
return public.returnMsg(True,'Activate successfully')
|
||||
|
||||
def renew_product_auth(self,get):
|
||||
params = {}
|
||||
params['serial_no'] = get.serial_no
|
||||
params['pay_channel'] = get.pay_channel
|
||||
params['cycle'] = get.cycle
|
||||
params['cycle_unit'] = get.cycle_unit
|
||||
params['src'] = 2
|
||||
params['environment_info'] = json.dumps(public.fetch_env_info())
|
||||
if hasattr(get,'coupon_id') and get.pay_channel == '10':
|
||||
params['coupon_id'] = get.coupon_id
|
||||
data = self.send_cloud('{}/api/authorize/product/renew'.format(self.__official_url), params)
|
||||
session['focre_cloud'] = True
|
||||
# 使用抵扣券续费直接返回续费结果
|
||||
if get.pay_channel == '10':
|
||||
if not data['success']:
|
||||
return public.returnMsg(False, 'Renew Failed')
|
||||
return public.returnMsg(True,'Renew successfully')
|
||||
# 使用支付续费返回stripe的请求数据
|
||||
return data['res']
|
||||
|
||||
def free_trial(self,get):
|
||||
"""
|
||||
每个账号有一次免费试用专业版15天的机会
|
||||
:return:
|
||||
"""
|
||||
params = {}
|
||||
params['environment_info'] = json.dumps(public.fetch_env_info())
|
||||
data = self.send_cloud('{}/api/product/obtainProfessionalMemberFree'.format(self.__official_url), params)
|
||||
session['focre_cloud'] = True
|
||||
# 使用抵扣券续费直接返回续费结果
|
||||
if not data['success']:
|
||||
return public.returnMsg(False, 'Apply Failed')
|
||||
return public.returnMsg(True,'Apply successfully')
|
||||
|
||||
+337
-34
@@ -30,19 +30,28 @@ class backup:
|
||||
_db_mysql = None
|
||||
_cloud = None
|
||||
_is_save_local = os.path.exists('data/is_save_local_backup.pl')
|
||||
def __init__(self,cloud_object = None):
|
||||
_error_msg = ""
|
||||
_backup_all = False
|
||||
def __init__(self,cloud_object=None, cron_info={}):
|
||||
'''
|
||||
@name 数据备份对象
|
||||
@param cloud_object 远程上传对象,需具备以下几个属性和方法:
|
||||
_title = '中文名称,如:阿里云OSS'
|
||||
_name = '英文名称,如:alioss'
|
||||
|
||||
upload_file(filename,data_type = None)
|
||||
文件名 , 数据类型 site/database/path
|
||||
|
||||
delete_file(filename,data_type = None)
|
||||
文件名 , 数据类型 site/database/path
|
||||
|
||||
给_error_msg赋值,传递错误消息:
|
||||
_error_msg = "错误消息"
|
||||
'''
|
||||
self._cloud = cloud_object
|
||||
self.cron_info = None
|
||||
if cron_info and 'echo' in cron_info.keys():
|
||||
self.cron_info = self.get_cron_info(cron_info["echo"])
|
||||
self._path = public.M('config').where("id=?",(1,)).getField('backup_path')
|
||||
|
||||
def echo_start(self):
|
||||
@@ -62,6 +71,9 @@ class backup:
|
||||
def echo_error(self,msg):
|
||||
print("=" * 90)
|
||||
print("|-Error:{}".format(msg))
|
||||
if self._error_msg:
|
||||
self._error_msg += "\n"
|
||||
self._error_msg += msg
|
||||
|
||||
#构造排除
|
||||
def get_exclude(self,exclude = []):
|
||||
@@ -103,13 +115,15 @@ class backup:
|
||||
arr['path'] = disk[6]
|
||||
tmp1 = [disk[2],disk[3],disk[4],disk[5]]
|
||||
arr['size'] = tmp1
|
||||
arr['inodes'] = [inodes[1],inodes[2],inodes[3],inodes[4]]
|
||||
if int(inodes[1]) == 0 and int(inodes[2]) == 0:
|
||||
arr['inodes'] = [inodes[1],10000,10000,0]
|
||||
else:
|
||||
arr['inodes'] = [inodes[1],inodes[2],inodes[3],inodes[4]]
|
||||
diskInfo.append(arr)
|
||||
except:
|
||||
continue
|
||||
return diskInfo
|
||||
|
||||
|
||||
#取磁盘可用空间
|
||||
def get_disk_free(self,dfile):
|
||||
diskInfo = self.GetDiskInfo2()
|
||||
@@ -125,24 +139,29 @@ class backup:
|
||||
return _root['path'],float(_root['size'][2]) * 1024,int(_root['inodes'][2])
|
||||
return '',0,0
|
||||
|
||||
|
||||
#备份指定目录
|
||||
def backup_path(self,spath,dfile = None,exclude=[],save=3):
|
||||
|
||||
error_msg = ""
|
||||
self.echo_start()
|
||||
if not os.path.exists(spath):
|
||||
self.echo_error(public.getMsg('BACKUP_DIR_NOT_EXIST',(spath,)))
|
||||
error_msg= public.getMsg('BACKUP_DIR_NOT_EXIST',(spath,))
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
if spath[-1] == '/':
|
||||
spath = spath[:-1]
|
||||
|
||||
dirname = os.path.basename(spath)
|
||||
|
||||
if not dfile:
|
||||
fname = 'path_{}_{}.tar.gz'.format(dirname,public.format_date("%Y%m%d_%H%M%S"))
|
||||
dfile = os.path.join(self._path,'path',fname)
|
||||
|
||||
if not self.backup_path_to(spath,dfile,exclude):
|
||||
if self._error_msg:
|
||||
error_msg = self._error_msg
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
if self._cloud:
|
||||
@@ -150,17 +169,23 @@ class backup:
|
||||
if self._cloud.upload_file(dfile,'path'):
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOAD_SUCCESS",(self._cloud._title,)))
|
||||
else:
|
||||
self.echo_error(public.getMsg('BACKUP_UPLOAD_FAILED'))
|
||||
if hasattr(self._cloud, "error_msg"):
|
||||
if self._cloud.error_msg:
|
||||
error_msg = self._cloud.error_msg
|
||||
if not error_msg:
|
||||
error_msg = public.getMsg('BACKUP_UPLOAD_FAILED')
|
||||
self.echo_error(error_msg)
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
return False
|
||||
|
||||
remark = "Backup to " + self._cloud._title
|
||||
self.send_failture_notification(error_msg, remark=remark)
|
||||
return False
|
||||
|
||||
filename = dfile
|
||||
if self._cloud:
|
||||
filename = dfile + '|' + self._cloud._name + '|' + fname
|
||||
|
||||
|
||||
pdata = {
|
||||
'type': '2',
|
||||
'name': spath,
|
||||
@@ -172,10 +197,22 @@ class backup:
|
||||
public.M('backup').insert(pdata)
|
||||
|
||||
if self._cloud:
|
||||
if not self._is_save_local:
|
||||
_not_save_local = True
|
||||
save_local = 0
|
||||
if self.cron_info:
|
||||
save_local = self.cron_info["save_local"]
|
||||
if save_local:
|
||||
_not_save_local = False
|
||||
else:
|
||||
if self._is_save_local:
|
||||
_not_save_local = False
|
||||
|
||||
if _not_save_local:
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
self.echo_info(public.getMsg("BACKUP_DEL",(dfile,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('KEEP_LOCAL'))
|
||||
|
||||
if not self._cloud:
|
||||
backups = public.M('backup').where("type=? and pid=? and name=? and filename NOT LIKE '%|%'",('2',0,spath)).field('id,name,filename').select()
|
||||
@@ -245,10 +282,10 @@ class backup:
|
||||
exclude_config = "Not set"
|
||||
|
||||
if siteName:
|
||||
self.echo_info(public.getMsg('BACKUP_SITE',(siteName)))
|
||||
self.echo_info(public.getMsg('BACKUP_SITE',(siteName,)))
|
||||
self.echo_info(public.getMsg('WEBSITE_DIR',(spath,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('BACKUP_DIR',(spath)))
|
||||
self.echo_info(public.getMsg('BACKUP_DIR',(spath,)))
|
||||
|
||||
self.echo_info(public.getMsg(
|
||||
"DIR_SIZE",
|
||||
@@ -306,17 +343,28 @@ class backup:
|
||||
pid = find['id']
|
||||
fname = 'web_{}_{}.tar.gz'.format(siteName,public.format_date("%Y%m%d_%H%M%S"))
|
||||
dfile = os.path.join(self._path,'site',fname)
|
||||
error_msg = ""
|
||||
if not self.backup_path_to(spath,dfile,exclude,siteName=siteName):
|
||||
if self._error_msg:
|
||||
error_msg = self._error_msg
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
if self._cloud:
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOADING",(self._cloud._title,)))
|
||||
if self._cloud.upload_file(dfile,'site'):
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOAD_SUCCESS",(self._cloud._title,)))
|
||||
else:
|
||||
self.echo_error('BACKUP_UPLOAD_FAILED')
|
||||
if hasattr(self._cloud, "error_msg"):
|
||||
if self._cloud.error_msg:
|
||||
error_msg = self._cloud.error_msg
|
||||
if not error_msg:
|
||||
error_msg = public.getMsg('BACKUP_UPLOAD_FAILED')
|
||||
self.echo_error(error_msg)
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
|
||||
remark = "Backup to " + self._cloud._title
|
||||
self.send_failture_notification(error_msg, remark=remark)
|
||||
return False
|
||||
|
||||
filename = dfile
|
||||
@@ -333,10 +381,22 @@ class backup:
|
||||
}
|
||||
public.M('backup').insert(pdata)
|
||||
if self._cloud:
|
||||
if not self._is_save_local:
|
||||
_not_save_local = True
|
||||
save_local = 0
|
||||
if self.cron_info:
|
||||
save_local = self.cron_info["save_local"]
|
||||
if save_local:
|
||||
_not_save_local = False
|
||||
else:
|
||||
if self._is_save_local:
|
||||
_not_save_local = False
|
||||
|
||||
if _not_save_local:
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
self.echo_info(public.getMsg("BACKUP_DEL",(dfile,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('KEEP_LOCAL'))
|
||||
|
||||
#清理多余备份
|
||||
if not self._cloud:
|
||||
@@ -347,13 +407,40 @@ class backup:
|
||||
self.delete_old(backups,save,'site')
|
||||
self.echo_end()
|
||||
return dfile
|
||||
|
||||
|
||||
#备份所有数据库
|
||||
def backup_database_all(self,save = 3):
|
||||
databases = public.M('databases').field('name').select()
|
||||
self._backup_all = True
|
||||
failture_count = 0
|
||||
results = []
|
||||
for database in databases:
|
||||
self._error_msg = ""
|
||||
result = self.backup_database(database['name'],save=save)
|
||||
if not result:
|
||||
failture_count += 1
|
||||
results.append((database['name'], result, self._error_msg,))
|
||||
|
||||
if failture_count > 0:
|
||||
self.send_all_failture_notification("database", results)
|
||||
self._backup_all = False
|
||||
|
||||
#备份所有站点
|
||||
def backup_site_all(self,save = 3):
|
||||
sites = public.M('sites').field('name').select()
|
||||
self._backup_all = True
|
||||
failture_count = 0
|
||||
results = []
|
||||
for site in sites:
|
||||
self.backup_site(site['name'],save)
|
||||
self._error_msg = ""
|
||||
result = self.backup_site(site['name'],save)
|
||||
if not result:
|
||||
failture_count += 1
|
||||
results.append((site['name'], result, self._error_msg,))
|
||||
|
||||
if failture_count > 0:
|
||||
self.send_all_failture_notification("site", results)
|
||||
self._backup_all = False
|
||||
|
||||
#配置
|
||||
def mypass(self,act):
|
||||
@@ -401,14 +488,23 @@ class backup:
|
||||
if not os.path.exists(dpath):
|
||||
os.makedirs(dpath,384)
|
||||
|
||||
error_msg = ""
|
||||
import panelMysql
|
||||
if not self._db_mysql:self._db_mysql = panelMysql.panelMysql()
|
||||
d_tmp = self._db_mysql.query("select sum(DATA_LENGTH)+sum(INDEX_LENGTH) from information_schema.tables where table_schema='%s'" % db_name)
|
||||
p_size = self.map_to_list(d_tmp)[0][0]
|
||||
try:
|
||||
p_size = self.map_to_list(d_tmp)[0][0]
|
||||
except:
|
||||
error_msg = public.getMsg('DB_CONN_ERR')
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
if p_size == None:
|
||||
self.echo_error(public.getMsg('DB_BACKUP_ERR',(db_name,)))
|
||||
return
|
||||
error_msg = public.getMsg('DB_BACKUP_ERR',(db_name,))
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
character = public.get_database_character(db_name)
|
||||
|
||||
@@ -423,14 +519,17 @@ class backup:
|
||||
))
|
||||
if disk_path:
|
||||
if disk_free < p_size:
|
||||
self.echo_error(
|
||||
public.getMsg("PARTITION_LESS_THEN",(
|
||||
error_msg = public.getMsg("PARTITION_LESS_THEN",(
|
||||
str(public.to_size(p_size),)
|
||||
)))
|
||||
))
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
if disk_inode < self._inode_min:
|
||||
self.echo_error(public.getMsg("INODE_LESS_THEN",(self._inode_min,)))
|
||||
error_msg = public.getMsg("INODE_LESS_THEN",(self._inode_min,))
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
stime = time.time()
|
||||
@@ -451,7 +550,9 @@ class backup:
|
||||
#self.mypass(False)
|
||||
gz_size = os.path.getsize(dfile)
|
||||
if gz_size < 400:
|
||||
self.echo_error(public.getMsg("EXPORT_DB_ERR"))
|
||||
error_msg = public.getMsg("EXPORT_DB_ERR")
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
self.echo_info(public.readFile(self._err_log))
|
||||
return False
|
||||
compressed_time = str('{:.2f}'.format(time.time() - stime))
|
||||
@@ -465,9 +566,17 @@ class backup:
|
||||
if self._cloud.upload_file(dfile, 'database'):
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOAD_SUCCESS",(self._cloud._title,)))
|
||||
else:
|
||||
self.echo_error('BACKUP_UPLOAD_FAILED')
|
||||
if hasattr(self._cloud, "error_msg"):
|
||||
if self._cloud.error_msg:
|
||||
error_msg = self._cloud.error_msg
|
||||
if not error_msg:
|
||||
error_msg = public.getMsg('BACKUP_UPLOAD_FAILED')
|
||||
self.echo_error(error_msg)
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
|
||||
remark = "Backup to " + self._cloud._title
|
||||
self.send_failture_notification(error_msg, remark=remark)
|
||||
return False
|
||||
|
||||
filename = dfile
|
||||
@@ -488,12 +597,23 @@ class backup:
|
||||
}
|
||||
public.M('backup').insert(pdata)
|
||||
|
||||
|
||||
if self._cloud:
|
||||
if not self._is_save_local:
|
||||
_not_save_local = True
|
||||
save_local = 0
|
||||
if self.cron_info:
|
||||
save_local = self.cron_info["save_local"]
|
||||
if save_local:
|
||||
_not_save_local = False
|
||||
else:
|
||||
if self._is_save_local:
|
||||
_not_save_local = False
|
||||
|
||||
if _not_save_local:
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
self.echo_info(public.getMsg("BACKUP_DEL",(dfile)))
|
||||
self.echo_info(public.getMsg("BACKUP_DEL",(dfile,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('KEEP_LOCAL'))
|
||||
|
||||
#清理多余备份
|
||||
if not self._cloud:
|
||||
@@ -504,11 +624,194 @@ class backup:
|
||||
self.echo_end()
|
||||
return dfile
|
||||
|
||||
def generate_success_title(self, task_name):
|
||||
from send_mail import send_mail
|
||||
sm = send_mail()
|
||||
now = public.format_date(format="%Y-%m-%d %H:%M")
|
||||
server_ip = sm.GetLocalIp()
|
||||
title = public.getMsg("BACKUP_TASK_TITLE",(server_ip, task_name))
|
||||
return title
|
||||
|
||||
#备份所有数据库
|
||||
def backup_database_all(self,save = 3):
|
||||
databases = public.M('databases').field('name').select()
|
||||
for database in databases:
|
||||
self.backup_database(database['name'],save=save)
|
||||
def generate_failture_title(self):
|
||||
title = "aaPanel backup task failed reminder"
|
||||
return title
|
||||
|
||||
def generate_all_failture_notice(self, task_name, msg, backup_type, remark=""):
|
||||
# from send_mail import send_mail
|
||||
# sm = send_mail()
|
||||
now = public.format_date(format="%Y-%m-%d %H:%M:%S")
|
||||
server_ip = public.GetLocalIp()
|
||||
if remark:
|
||||
remark = "\n* Task notes: {}".format(remark)
|
||||
|
||||
notice_content = """Hello,
|
||||
aaPanel reminds you that the cron you set failed to execute:
|
||||
* Server IP: {}
|
||||
* Time: {}
|
||||
* Task name: {}{}
|
||||
* The following is a list of {} that failed to backup:
|
||||
<table style="color:red;">
|
||||
{}
|
||||
</table>
|
||||
Please deal with it as soon as possible to avoid unnecessary trouble due to the failure of the backup task.
|
||||
- Notification by aaPanel""".format(
|
||||
server_ip, now, task_name, remark, backup_type, msg)
|
||||
return notice_content
|
||||
|
||||
def generate_failture_notice(self, task_name, msg, remark):
|
||||
# from send_mail import send_mail
|
||||
# sm = send_mail()
|
||||
now = public.format_date(format="%Y-%m-%d %H:%M:%S")
|
||||
server_ip = public.GetLocalIp()
|
||||
if remark:
|
||||
remark = "\n* Task notes: {}".format(remark)
|
||||
|
||||
notice_content = """Hello,
|
||||
aaPanel reminds you that the cron you set failed to execute:
|
||||
* Server IP: {}
|
||||
* Time: {}
|
||||
* Task name:{}{}
|
||||
* Error messages:
|
||||
<span style="color:red;">
|
||||
{}
|
||||
</span>
|
||||
Please deal with it as soon as possible to avoid unnecessary trouble due to the failure of the backup task.
|
||||
-- Notification by aaPanel""".format(
|
||||
server_ip, now, task_name, remark, msg)
|
||||
return notice_content
|
||||
|
||||
def get_cron_info(self, cron_name):
|
||||
""" 通过计划任务名称查找计划任务配置参数 """
|
||||
try:
|
||||
cron_info = public.M('crontab').where('echo=?',(cron_name,))\
|
||||
.field('name,save_local,notice,notice_channel').find()
|
||||
return cron_info
|
||||
except Exception as e:
|
||||
pass
|
||||
return {}
|
||||
|
||||
def send_failture_notification(self, error_msg, remark=""):
|
||||
"""发送任务失败消息
|
||||
|
||||
:error_msg 错误信息
|
||||
:remark 备注
|
||||
"""
|
||||
if self._backup_all:
|
||||
return
|
||||
if not self.cron_info:
|
||||
return
|
||||
cron_info = self.cron_info
|
||||
cron_title = cron_info["name"]
|
||||
save_local = cron_info["save_local"]
|
||||
notice = cron_info["notice"]
|
||||
notice_channel = cron_info["notice_channel"]
|
||||
if notice == 0 or not notice_channel:
|
||||
return
|
||||
|
||||
if notice == 1 or notice == 2:
|
||||
title = self.generate_failture_title()
|
||||
task_name = cron_title
|
||||
msg = self.generate_failture_notice(task_name, error_msg, remark)
|
||||
res = self.send_notification(notice_channel, title, msg)
|
||||
if res:
|
||||
self.echo_info(public.getMsg('NOTIFICATION_SENT'))
|
||||
|
||||
def send_all_failture_notification(self, backup_type, results, remark=""):
|
||||
"""统一发送任务失败消息
|
||||
|
||||
:results [(备份对象, 备份结果,错误信息),...]
|
||||
:remark 备注
|
||||
"""
|
||||
if not self.cron_info:
|
||||
return
|
||||
cron_info = self.cron_info
|
||||
cron_title = cron_info["name"]
|
||||
save_local = cron_info["save_local"]
|
||||
notice = cron_info["notice"]
|
||||
notice_channel = cron_info["notice_channel"]
|
||||
if notice == 0 or not notice_channel:
|
||||
return
|
||||
|
||||
if notice == 1 or notice == 2:
|
||||
title = self.generate_failture_title()
|
||||
type_desc = {
|
||||
"site": "site",
|
||||
"database": "database"
|
||||
}
|
||||
backup_type_desc = type_desc[backup_type]
|
||||
task_name = cron_title
|
||||
failture_count = 0
|
||||
total = 0
|
||||
content = ""
|
||||
|
||||
for obj in results:
|
||||
total += 1
|
||||
obj_name = obj[0]
|
||||
result = obj[1]
|
||||
if not result:
|
||||
failture_count += 1
|
||||
content += "<tr><td style='color:red'>{}</td><tr>".format(obj_name)
|
||||
|
||||
if failture_count > 0:
|
||||
if self._cloud:
|
||||
remark = public.getMsg("BACKUP_MSG"),(
|
||||
self._cloud._title, total, backup_type_desc, failture_count)
|
||||
else:
|
||||
remark = public.getMsg("BACKUP_MSG1"),(
|
||||
failture_count, total, backup_type_desc)
|
||||
|
||||
msg = self.generate_all_failture_notice(task_name, content, backup_type_desc, remark)
|
||||
res = self.send_notification(notice_channel, title, msg)
|
||||
if res:
|
||||
self.echo_info(public.getMsg('NOTIFICATION_SENT'))
|
||||
else:
|
||||
self.echo_error(public.getMsg('NOTIFICATION_ERR'))
|
||||
|
||||
def send_notification(self, channel, title, msg = ""):
|
||||
try:
|
||||
from send_mail import send_mail
|
||||
tondao = []
|
||||
if channel.find(",") >= 0:
|
||||
tongdao = channel.split(",")
|
||||
else:
|
||||
tongdao = [channel]
|
||||
|
||||
sm = send_mail()
|
||||
send_res = []
|
||||
error_count = 0
|
||||
channel_names = {
|
||||
"mail": "email",
|
||||
# "dingidng": "钉钉"
|
||||
}
|
||||
error_channel = []
|
||||
settings = sm.get_settings()
|
||||
for td in tongdao:
|
||||
_res = False
|
||||
if td == "mail":
|
||||
if len(settings["user_mail"]['mail_list']) == 0:
|
||||
continue
|
||||
mail_list = settings['user_mail']['mail_list']
|
||||
if len(mail_list) == 1:
|
||||
mail_list = mail_list[0]
|
||||
_res = sm.qq_smtp_send(mail_list, title=title, body=msg.replace("\n", "<br/>"))
|
||||
if not _res:
|
||||
error_count += 1
|
||||
error_channel.append(channel_names[td])
|
||||
if td == "dingding":
|
||||
if len(settings["dingding"]['info']) == 0:
|
||||
continue
|
||||
_res = sm.dingding_send(msg)
|
||||
send_res.append(_res)
|
||||
if not _res:
|
||||
error_count += 1
|
||||
error_channel.append(channel_names[td])
|
||||
if error_count > 0:
|
||||
print("Notification:{} failed to send".format(",".join(error_channel)))
|
||||
if error_count == len(tongdao):
|
||||
return False
|
||||
return True
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
+24
-7
@@ -201,9 +201,16 @@ class CloudFlareDns(BaseDns):
|
||||
self.CLOUDFLARE_API_BASE_URL = CLOUDFLARE_API_BASE_URL
|
||||
super(CloudFlareDns, self).__init__()
|
||||
|
||||
def get_headers(self):
|
||||
if os.path.exists('/www/server/panel/data/cf_limit_api.pl'):
|
||||
headers = {"Authorization": "Bearer "+self.CLOUDFLARE_API_KEY}
|
||||
else:
|
||||
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
return headers
|
||||
|
||||
def find_dns_zone(self, domain_name):
|
||||
url = urljoin(self.CLOUDFLARE_API_BASE_URL, "zones?status=active&name={0}".format(domain_name))
|
||||
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
headers = self.get_headers()
|
||||
find_dns_zone_response = requests.get(url, headers=headers, timeout=self.HTTP_TIMEOUT)
|
||||
if find_dns_zone_response.status_code != 200:
|
||||
raise ValueError(
|
||||
@@ -231,7 +238,11 @@ class CloudFlareDns(BaseDns):
|
||||
self.CLOUDFLARE_API_BASE_URL,
|
||||
"zones/{0}/dns_records".format(self.CLOUDFLARE_DNS_ZONE_ID),
|
||||
)
|
||||
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
# if '_' in self.CLOUDFLARE_API_KEY or '-' in self.CLOUDFLARE_API_KEY:
|
||||
# headers = {"Authorization": "Bearer "+self.CLOUDFLARE_API_KEY}
|
||||
# else:
|
||||
# headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
headers = self.get_headers()
|
||||
body = {
|
||||
"type": s_type,
|
||||
"name": domain_name,
|
||||
@@ -257,7 +268,11 @@ class CloudFlareDns(BaseDns):
|
||||
self.CLOUDFLARE_API_BASE_URL,
|
||||
"zones/{0}/dns_records".format(self.CLOUDFLARE_DNS_ZONE_ID),
|
||||
)
|
||||
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
# if '_' in self.CLOUDFLARE_API_KEY or '-' in self.CLOUDFLARE_API_KEY:
|
||||
# headers = {"Authorization": "Bearer "+self.CLOUDFLARE_API_KEY}
|
||||
# else:
|
||||
# headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
headers = self.get_headers()
|
||||
body = {
|
||||
"type": "TXT",
|
||||
"name": "_acme-challenge" + "." + domain_name + ".",
|
||||
@@ -278,8 +293,11 @@ class CloudFlareDns(BaseDns):
|
||||
|
||||
|
||||
def remove_record(self,domain_name,dns_name,s_type):
|
||||
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
|
||||
# if '_' in self.CLOUDFLARE_API_KEY or '-' in self.CLOUDFLARE_API_KEY:
|
||||
# headers = {"Authorization": "Bearer "+self.CLOUDFLARE_API_KEY}
|
||||
# else:
|
||||
# headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
headers = self.get_headers()
|
||||
list_dns_payload = {"type": s_type, "name": dns_name}
|
||||
list_dns_url = urljoin(
|
||||
self.CLOUDFLARE_API_BASE_URL,
|
||||
@@ -296,7 +314,6 @@ class CloudFlareDns(BaseDns):
|
||||
self.CLOUDFLARE_API_BASE_URL,
|
||||
"zones/{0}/dns_records/{1}".format(self.CLOUDFLARE_DNS_ZONE_ID, dns_record_id),
|
||||
)
|
||||
headers = {"X-Auth-Email": self.CLOUDFLARE_EMAIL, "X-Auth-Key": self.CLOUDFLARE_API_KEY}
|
||||
requests.delete(
|
||||
url, headers=headers, timeout=self.HTTP_TIMEOUT
|
||||
)
|
||||
@@ -447,7 +464,7 @@ class CloudxnsDns(object):
|
||||
headers = self.get_headers(url)
|
||||
req = requests.get(url=url, headers=headers,verify=False)
|
||||
req = req.json()
|
||||
|
||||
|
||||
return req
|
||||
|
||||
def get_domain_id(self, domain_name):
|
||||
|
||||
+59
-3
@@ -4,26 +4,81 @@
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# | Author: hwliang <2020-05-18>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
# +-------------------------------------------------------------------
|
||||
# | 消息提醒
|
||||
# +-------------------------------------------------------------------
|
||||
import os,sys,time
|
||||
import public
|
||||
class panelMessage:
|
||||
import public,json
|
||||
if os.environ.get('BT_TASK') != '1':
|
||||
from BTPanel import cache
|
||||
else:
|
||||
import cachelib
|
||||
cache = cachelib.SimpleCache()
|
||||
|
||||
class panelMessage:
|
||||
os = 'linux'
|
||||
|
||||
def __init__(self):
|
||||
# if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'messages','%retry_num%')).count():
|
||||
# public.M('messages').execute("alter TABLE messages add send integer DEFAULT 0",())
|
||||
# public.M('messages').execute("alter TABLE messages add retry_num integer DEFAULT 0",())
|
||||
pass
|
||||
|
||||
|
||||
def set_send_status(self, id, data):
|
||||
'''
|
||||
@name 设置消息发送状态
|
||||
@author cjxin <2021-04-12>
|
||||
@param args dict_obj{
|
||||
id: 消息标识,
|
||||
data
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
|
||||
public.M('messages').where('id=?',id).update(data)
|
||||
return public.returnMsg(True,'设置成功!')
|
||||
|
||||
|
||||
"""
|
||||
获取官网推送消息,一小时获取一次
|
||||
"""
|
||||
def get_cloud_messages(self,args):
|
||||
#ret = cache.get('get_cloud_messages')
|
||||
#if ret: return public.returnMsg(True,'同步成功1!')
|
||||
data = {}
|
||||
data['version'] = public.version()
|
||||
data['os'] = self.os
|
||||
sUrl = public.GetConfigValue('home') + '/api/wpanel/get_messages'
|
||||
import http_requests
|
||||
http_requests.DEFAULT_TYPE = 'src'
|
||||
info = http_requests.post(sUrl,data).json()
|
||||
# info = json.loads(public.httpPost(sUrl,data))
|
||||
for x in info:
|
||||
count = public.M('messages').where('level=? and msg=?',(x['level'],x['msg'],)).count()
|
||||
if count: continue
|
||||
|
||||
pdata = {
|
||||
"level":x['level'],
|
||||
"msg":x['msg'],
|
||||
"state":1,
|
||||
"expire":int(time.time()) + (int(x['expire']) * 86400),
|
||||
"addtime": int(time.time())
|
||||
}
|
||||
public.M('messages').insert(pdata)
|
||||
#cache.set('get_cloud_messages',3600)
|
||||
return public.returnMsg(True,'同步成功!')
|
||||
|
||||
def get_messages(self,args = None):
|
||||
'''
|
||||
@name 获取消息列表
|
||||
@author hwliang <2020-05-18>
|
||||
@return list
|
||||
'''
|
||||
self.get_cloud_messages(args)
|
||||
data = public.M('messages').where('state=? and expire>?',(1,int(time.time()))).order("id desc").select()
|
||||
return data
|
||||
|
||||
@@ -33,6 +88,7 @@ class panelMessage:
|
||||
@author hwliang <2020-05-18>
|
||||
@return list
|
||||
'''
|
||||
self.get_cloud_messages(args)
|
||||
data = public.M('messages').order("id desc").select()
|
||||
return data
|
||||
|
||||
|
||||
+35
-27
@@ -153,7 +153,6 @@ class panelPlugin:
|
||||
'Depend on the following software, please install first [%s]' %
|
||||
versionInfo[
|
||||
'dependent'])
|
||||
|
||||
#安装插件
|
||||
def install_plugin(self,get):
|
||||
if not self.check_sys_write(): return public.returnMsg(False,'CANT_WRITE_SYS_DIR')
|
||||
@@ -163,6 +162,8 @@ class panelPlugin:
|
||||
check_result = self.check_install_limit(get)
|
||||
if check_result:
|
||||
return check_result
|
||||
if pluginInfo['name'] in ['dns_manager','mail_sys']:
|
||||
pluginInfo['type'] = 5
|
||||
if pluginInfo['type'] != 5:
|
||||
result = self.install_sync(pluginInfo,get)
|
||||
else:
|
||||
@@ -170,15 +171,20 @@ class panelPlugin:
|
||||
try:
|
||||
if 'status' in result:
|
||||
if result['status']:
|
||||
public.httpPost('{}/api/setupCount/setupPlugin'.format(self.__official_url),{"pid":pluginInfo['id'],'p_name':pluginInfo['name']},3)
|
||||
get.force = 1
|
||||
self.get_cloud_list(get)
|
||||
public.arequests('post','{}/api/setupCount/setupPlugin'.format(self.__official_url),data={"pid":pluginInfo['id'],'p_name':pluginInfo['name']},timeout=3)
|
||||
# get.force = 1
|
||||
# self.get_cloud_list(get)
|
||||
except:pass
|
||||
return result
|
||||
|
||||
#同步安装
|
||||
def install_sync(self,pluginInfo,get):
|
||||
import panelAuth
|
||||
try:
|
||||
token = panelAuth.panelAuth().create_serverid(None)['token']
|
||||
except:
|
||||
# return public.returnMsg(False,'Please log in as aaPanel account first')
|
||||
token = None
|
||||
if 'download' in pluginInfo['versions'][0]:
|
||||
tmp_path = '/www/server/panel/temp'
|
||||
if not os.path.exists(tmp_path): os.makedirs(tmp_path,mode=384)
|
||||
@@ -187,14 +193,14 @@ class panelPlugin:
|
||||
public.downloadFile('{}/api/plugin/download?filename={}&token={}'.format(
|
||||
self.__official_url,
|
||||
pluginInfo['versions'][0]['download'],
|
||||
panelAuth.panelAuth().create_serverid(None)['token']
|
||||
token
|
||||
),toFile)
|
||||
if public.FileMd5(toFile) != pluginInfo['versions'][0]['md5']: return public.returnMsg(False,'CHECK_FILE_HASH')
|
||||
update = False
|
||||
if os.path.exists(pluginInfo['install_checks']): update =pluginInfo['versions'][0]['version_msg']
|
||||
return self.update_zip(None,toFile,update)
|
||||
else:
|
||||
download_url = public.get_url() + '/install/plugin/' + pluginInfo['name'] + '/install.sh'
|
||||
download_url = public.get_url() + '/install/plugin/' + pluginInfo['name'] + '_en/install.sh'
|
||||
toFile = '/tmp/%s.sh' % pluginInfo['name']
|
||||
public.downloadFile(download_url,toFile)
|
||||
self.set_pyenv(toFile)
|
||||
@@ -418,30 +424,23 @@ class panelPlugin:
|
||||
is_plugin = True
|
||||
import panelMessage #引用消息提醒模块
|
||||
pm = panelMessage.panelMessage()
|
||||
pm.remove_message_all()
|
||||
|
||||
#企业版到期提醒
|
||||
if not data['ltd'] in [-1]:
|
||||
level,expire_day = self.get_level_msg('ltd',s_time,data['ltd'])
|
||||
self.add_expire_msg('企业版',level,'ltd',expire_day,100000032,data['ltd'])
|
||||
pm.remove_message_level('pro')
|
||||
return True
|
||||
if not data['ltd'] in [-1] :
|
||||
|
||||
if data['pro'] < 0 or (data['pro'] - s_time) / 86400 < 15 :
|
||||
level,expire_day = self.get_level_msg('ltd',s_time,data['ltd'])
|
||||
print(level,expire_day)
|
||||
self.add_expire_msg('企业版',level,'ltd',expire_day,100000046,data['ltd'])
|
||||
pm.remove_message_level('pro')
|
||||
return True
|
||||
|
||||
#专业版到期提醒
|
||||
if not data['pro'] in [-1,0]:
|
||||
level,expire_day = self.get_level_msg('pro',s_time,data['pro'])
|
||||
self.add_expire_msg('专业版',level,'pro',expire_day,100000011,data['pro'])
|
||||
self.add_expire_msg('专业版',level,'pro',expire_day,100000030,data['pro'])
|
||||
pm.remove_message_level('ltd')
|
||||
is_plugin = False
|
||||
|
||||
#单独购买的插件到期提醒
|
||||
# for p in data['list']:
|
||||
# #跳过非企业版或专业版插件
|
||||
# if not p['type'] in [8,12]: continue
|
||||
# #已经是专业版的情况下跳过专业版插件
|
||||
# if not is_plugin and p['type'] == 8: continue
|
||||
# if not p['endtime'] in [-1,0]:
|
||||
# level,expire_day = self.get_level_msg(p['name'],s_time,p['endtime'])
|
||||
# self.add_expire_msg(p['title'],level,p['name'],expire_day,p['pid'],p['endtime'])
|
||||
return True
|
||||
|
||||
|
||||
@@ -1672,10 +1671,11 @@ class panelPlugin:
|
||||
if conf.find('/www/server/stop') == -1: pstatus = True
|
||||
if os.path.exists('/usr/local/lsws/bin/lswsctrl'):
|
||||
result = self._get_ols_myphpadmin_info()
|
||||
phpversion = result['php_version']
|
||||
phpport = result['php_port']
|
||||
pauth = result['pauth']
|
||||
pstatus = result['pstatus']
|
||||
if result:
|
||||
phpversion = result['php_version']
|
||||
phpport = result['php_port']
|
||||
pauth = result['pauth']
|
||||
pstatus = result['pstatus']
|
||||
try:
|
||||
vfile = setupPath + '/phpmyadmin/version.pl'
|
||||
if os.path.exists(vfile):
|
||||
@@ -1699,6 +1699,7 @@ class panelPlugin:
|
||||
def _get_ols_myphpadmin_info(self):
|
||||
filename = "/www/server/panel/vhost/openlitespeed/detail/phpmyadmin.conf"
|
||||
conf = public.readFile(filename)
|
||||
if not conf:return False
|
||||
reg = '/usr/local/lsws/lsphp(\d+)/bin/lsphp'
|
||||
php_v = re.search(reg,conf)
|
||||
phpversion = '73'
|
||||
@@ -2050,6 +2051,13 @@ class panelPlugin:
|
||||
p_info = public.ReadFile(plugin_path + '/info.json')
|
||||
public.ExecShell("rm -rf /www/server/panel/temp/*")
|
||||
if p_info:
|
||||
#----- 增加图标复制 hwliang<2021-03-23> -----#
|
||||
icon_sfile = plugin_path + '/icon.png'
|
||||
icon_dfile = '/www/server/panel/BTPanel/static/img/soft_ico/ico-{}.png'.format(get.plugin_name)
|
||||
if os.path.exists(plugin_path + '/icon.png'):
|
||||
import shutil
|
||||
shutil.copyfile(icon_sfile,icon_dfile)
|
||||
#----- 增加图标复制 END -----#
|
||||
public.WriteLog('TYPE_SOFT','INSTALL_THIRD_PARDY_PLUG' ,(json.loads(p_info)['title'],))
|
||||
return public.returnMsg(True,'PLUGIN_INSTALL_SUCCESS')
|
||||
public.ExecShell("rm -rf " + plugin_path)
|
||||
|
||||
+11
-1
@@ -663,7 +663,17 @@ class panelSSL:
|
||||
if not tmp: continue
|
||||
tmp1 = json.loads(tmp)
|
||||
data.append(tmp1)
|
||||
return data
|
||||
if not data:
|
||||
lets_file = '/www/server/panel/config/letsencrypt.json'
|
||||
tmp = public.readFile(ltes_file)
|
||||
if not tmp:
|
||||
return []
|
||||
tmp = json(tmp)
|
||||
for i in tmp['orders']:
|
||||
data.append({"domains":tmp['orders'][i]['domains'],
|
||||
"notAfter":tmp['orders'][i]['cert_timeout'],
|
||||
"save_path":tmp['orders'][i]['save_path']
|
||||
})
|
||||
except:
|
||||
return []
|
||||
|
||||
|
||||
+1542
-1453
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -67,7 +67,7 @@ class bt_task:
|
||||
data = sql.field('id,name,type,shell,other,status,exectime,endtime,addtime').order(
|
||||
'id asc').limit('10').select()
|
||||
if type(data) == str:
|
||||
public.WriteLog('TASK_QUEUE',data)
|
||||
public.WriteLog('TASK_QUEUE', data,not_web = self.not_web)
|
||||
return []
|
||||
if not 'num' in get:
|
||||
get.num = 15
|
||||
|
||||
+41
-36
@@ -22,7 +22,7 @@ class panelWarning:
|
||||
|
||||
|
||||
def get_list(self,args):
|
||||
self.sync_rule()
|
||||
#self.sync_rule()
|
||||
p = public.get_modules('class/safe_warning')
|
||||
|
||||
data = {
|
||||
@@ -32,6 +32,9 @@ class panelWarning:
|
||||
}
|
||||
|
||||
for m_name in p.__dict__.keys():
|
||||
# 忽略的检查项
|
||||
if p[m_name]._level == 0: continue
|
||||
|
||||
m_info = {
|
||||
'title': p[m_name]._title,
|
||||
'm_name': m_name,
|
||||
@@ -82,45 +85,47 @@ class panelWarning:
|
||||
@author hwliang<2020-08-05>
|
||||
@return void
|
||||
'''
|
||||
try:
|
||||
dep_path = '/www/server/panel/class/safe_warning'
|
||||
local_version_file = self.__path + '/version.pl'
|
||||
last_sync_time = local_version_file = self.__path + '/last_sync.pl'
|
||||
if os.path.exists(dep_path):
|
||||
if os.path.exists(last_sync_time):
|
||||
if int(public.readFile(last_sync_time)) > time.time():
|
||||
return
|
||||
else:
|
||||
if os.path.exists(local_version_file): os.remove(local_version_file)
|
||||
# try:
|
||||
# dep_path = '/www/server/panel/class/safe_warning'
|
||||
# local_version_file = self.__path + '/version.pl'
|
||||
# last_sync_time = local_version_file = self.__path + '/last_sync.pl'
|
||||
# if os.path.exists(dep_path):
|
||||
# if os.path.exists(last_sync_time):
|
||||
# if int(public.readFile(last_sync_time)) > time.time():
|
||||
# return
|
||||
# else:
|
||||
# if os.path.exists(local_version_file): os.remove(local_version_file)
|
||||
|
||||
download_url = public.get_url()
|
||||
version_url = download_url + '/install/warning/version.txt'
|
||||
cloud_version = public.httpGet(version_url)
|
||||
if cloud_version: cloud_version = cloud_version.strip()
|
||||
# download_url = public.get_url()
|
||||
# version_url = download_url + '/install/warning/version.txt'
|
||||
# cloud_version = public.httpGet(version_url)
|
||||
# if cloud_version: cloud_version = cloud_version.strip()
|
||||
|
||||
local_version = public.readFile(local_version_file)
|
||||
if local_version:
|
||||
if cloud_version == local_version:
|
||||
return
|
||||
# local_version = public.readFile(local_version_file)
|
||||
# if local_version:
|
||||
# if cloud_version == local_version:
|
||||
# return
|
||||
|
||||
# tmp_file = '/tmp/bt_safe_warning.zip'
|
||||
# public.ExecShell('wget -O {} {} -T 5'.format(tmp_file,download_url + '/install/warning/safe_warning.zip'))
|
||||
# if not os.path.exists(tmp_file):
|
||||
# return
|
||||
|
||||
# if os.path.getsize(tmp_file) < 2129:
|
||||
# os.remove(tmp_file)
|
||||
# return
|
||||
|
||||
tmp_file = '/tmp/bt_safe_warning.zip'
|
||||
public.ExecShell('wget -O {} {} -T 5'.format(tmp_file,download_url + '/install/warning/safe_warning_en.zip'))
|
||||
if not os.path.exists(tmp_file):
|
||||
return
|
||||
# if not os.path.exists(dep_path):
|
||||
# os.makedirs(dep_path,384)
|
||||
# public.ExecShell("unzip -o {} -d {}/ >/dev/null".format(tmp_file,dep_path))
|
||||
# public.writeFile(local_version_file,cloud_version)
|
||||
# public.writeFile(last_sync_time,str(int(time.time() + 7200)))
|
||||
# if os.path.exists(tmp_file): os.remove(tmp_file)
|
||||
# public.ExecShell("chmod -R 600 {}".format(dep_path))
|
||||
# except:
|
||||
# pass
|
||||
|
||||
|
||||
if os.path.getsize(tmp_file) < 2129:
|
||||
os.remove(tmp_file)
|
||||
return
|
||||
|
||||
if not os.path.exists(dep_path):
|
||||
os.makedirs(dep_path,384)
|
||||
public.ExecShell("unzip -o {} -d {}/ >/dev/null".format(tmp_file,dep_path))
|
||||
public.writeFile(local_version_file,cloud_version)
|
||||
public.writeFile(last_sync_time,str(int(time.time() + 7200)))
|
||||
if os.path.exists(tmp_file): os.remove(tmp_file)
|
||||
public.ExecShell("chmod -R 600 {}".format(dep_path))
|
||||
except:
|
||||
pass
|
||||
|
||||
def set_ignore(self,args):
|
||||
'''
|
||||
|
||||
@@ -31,6 +31,7 @@ function get_info(){
|
||||
$data['0db']['PDO-MySQL'] = in_array('pdo_mysql',$data['modules']);
|
||||
$data['0db']['SqlServer'] =in_array('mssql',$data['modules']);
|
||||
$data['0db']['PDO-SqlServer'] = in_array('pdo_mssql',$data['modules']);
|
||||
if(!$data['0db']['PDO-SqlServer']) $data['0db']['PDO-SqlServer'] = in_array('pdo_sqlsrv',$data['modules']);
|
||||
$data['0db']['Sqlite3'] = in_array('sqlite3',$data['modules']);
|
||||
$data['0db']['PDO-Sqlite'] = in_array('pdo_sqlite',$data['modules']);
|
||||
$data['0db']['PgSQL'] = get_extension_funcs('pg_query')?true:false;
|
||||
|
||||
+139
-138
@@ -13,25 +13,25 @@
|
||||
|
||||
import public,json,os,time,sys,re
|
||||
from BTPanel import session
|
||||
class obj: id=0;
|
||||
class obj: id=0
|
||||
class plugin_deployment:
|
||||
__setupPath = 'data';
|
||||
__panelPath = '/www/server/panel';
|
||||
__setupPath = 'data'
|
||||
__panelPath = '/www/server/panel'
|
||||
logPath = 'data/deployment_speed.json'
|
||||
__tmp = '/www/server/panel/temp/'
|
||||
timeoutCount = 0;
|
||||
oldTime = 0;
|
||||
timeoutCount = 0
|
||||
oldTime = 0
|
||||
|
||||
#获取列表
|
||||
def GetList(self,get):
|
||||
self.GetCloudList(get);
|
||||
jsonFile = self.__panelPath + '/data/deployment_list.json';
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'Profile does not exist!');
|
||||
self.GetCloudList(get)
|
||||
jsonFile = self.__panelPath + '/data/deployment_list.json'
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'Profile does not exist!')
|
||||
data = {}
|
||||
data = self.get_input_list(json.loads(public.readFile(jsonFile)));
|
||||
data = self.get_input_list(json.loads(public.readFile(jsonFile)))
|
||||
|
||||
if not hasattr(get,'type'):
|
||||
get.type = 0;
|
||||
get.type = 0
|
||||
else:
|
||||
get.type = int(get.type)
|
||||
if not hasattr(get,'search'):
|
||||
@@ -39,32 +39,32 @@ class plugin_deployment:
|
||||
m = 0
|
||||
else:
|
||||
if sys.version_info[0] == 2:
|
||||
search = get.search.encode('utf-8').lower();
|
||||
search = get.search.encode('utf-8').lower()
|
||||
else:
|
||||
search = get.search.lower();
|
||||
search = get.search.lower()
|
||||
m = 1
|
||||
|
||||
tmp = [];
|
||||
tmp = []
|
||||
for d in data['list']:
|
||||
i=0;
|
||||
i=0
|
||||
if get.type > 0:
|
||||
if get.type == d['type']: i+=1
|
||||
else:
|
||||
i+=1
|
||||
if search:
|
||||
if d['name'].lower().find(search) != -1: i+=1;
|
||||
if d['title'].lower().find(search) != -1: i+=1;
|
||||
if d['ps'].lower().find(search) != -1: i+=1;
|
||||
if get.type > 0 and get.type != d['type']: i -= 1;
|
||||
if d['name'].lower().find(search) != -1: i+=1
|
||||
if d['title'].lower().find(search) != -1: i+=1
|
||||
if d['ps'].lower().find(search) != -1: i+=1
|
||||
if get.type > 0 and get.type != d['type']: i -= 1
|
||||
|
||||
if i>m:
|
||||
del(d['versions'][0]['download'])
|
||||
del(d['versions'][0]['md5'])
|
||||
d = self.get_icon(d)
|
||||
tmp.append(d);
|
||||
tmp.append(d)
|
||||
|
||||
data['list'] = tmp;
|
||||
return data;
|
||||
data['list'] = tmp
|
||||
return data
|
||||
|
||||
#获取图标
|
||||
def get_icon(self,pinfo):
|
||||
@@ -81,16 +81,16 @@ class plugin_deployment:
|
||||
|
||||
#获取插件列表
|
||||
def GetDepList(self,get):
|
||||
jsonFile = self.__setupPath + '/deployment_list.json';
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'Profile does not exist!');
|
||||
jsonFile = self.__setupPath + '/deployment_list.json'
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'Profile does not exist!')
|
||||
data = {}
|
||||
data = json.loads(public.readFile(jsonFile));
|
||||
return self.get_input_list(data);
|
||||
data = json.loads(public.readFile(jsonFile))
|
||||
return self.get_input_list(data)
|
||||
|
||||
#获取本地导入的插件
|
||||
def get_input_list(self,data):
|
||||
try:
|
||||
jsonFile = self.__setupPath + '/deployment_list_other.json';
|
||||
jsonFile = self.__setupPath + '/deployment_list_other.json'
|
||||
if not os.path.exists(jsonFile): return data
|
||||
i_data = json.loads(public.readFile(jsonFile))
|
||||
for d in i_data:
|
||||
@@ -101,33 +101,34 @@ class plugin_deployment:
|
||||
#从云端获取列表
|
||||
def GetCloudList(self,get):
|
||||
try:
|
||||
jsonFile = self.__setupPath + '/deployment_list.json';
|
||||
jsonFile = self.__setupPath + '/deployment_list.json'
|
||||
if not 'package' in session or not os.path.exists(jsonFile) or hasattr(get,'force'):
|
||||
downloadUrl = 'http://www.bt.cn/api/panel/get_deplist';
|
||||
tmp = json.loads(public.httpGet(downloadUrl,3));
|
||||
if not tmp: return public.returnMsg(False,'Failed to get from the cloud!');
|
||||
public.writeFile(jsonFile,json.dumps(tmp));
|
||||
downloadUrl = 'http://www.bt.cn/api/panel/get_deplist'
|
||||
pdata = public.get_pdata()
|
||||
tmp = json.loads(public.httpPost(downloadUrl,pdata,3))
|
||||
if not tmp: return public.returnMsg(False,'Failed to get from the cloud!')
|
||||
public.writeFile(jsonFile,json.dumps(tmp))
|
||||
session['package'] = True
|
||||
return public.returnMsg(True,'Update completed!');
|
||||
return public.returnMsg(True,'No need to update!');
|
||||
return public.returnMsg(True,'Update completed!')
|
||||
return public.returnMsg(True,'No need to update!')
|
||||
except:
|
||||
return public.returnMsg(False,'Failed to get from the cloud!');
|
||||
return public.returnMsg(False,'Failed to get from the cloud!')
|
||||
|
||||
|
||||
|
||||
#导入程序包
|
||||
def AddPackage(self,get):
|
||||
jsonFile = self.__setupPath + '/deployment_list_other.json';
|
||||
jsonFile = self.__setupPath + '/deployment_list_other.json'
|
||||
if not os.path.exists(jsonFile):
|
||||
public.writeFile(jsonFile,'[]')
|
||||
pinfo = {}
|
||||
pinfo['name'] = get.name;
|
||||
pinfo['title'] = get.title;
|
||||
pinfo['version'] = get.version;
|
||||
pinfo['php'] = get.php;
|
||||
pinfo['ps'] = get.ps;
|
||||
pinfo['name'] = get.name
|
||||
pinfo['title'] = get.title
|
||||
pinfo['version'] = get.version
|
||||
pinfo['php'] = get.php
|
||||
pinfo['ps'] = get.ps
|
||||
pinfo['official'] = '#'
|
||||
pinfo['sort'] = 1000;
|
||||
pinfo['sort'] = 1000
|
||||
pinfo['min_image'] = ''
|
||||
pinfo['id'] = 0
|
||||
pinfo['type'] = 100
|
||||
@@ -154,24 +155,24 @@ class plugin_deployment:
|
||||
"version_msg": "test2"}
|
||||
version['md5'] = self.GetFileMd5(s_file)
|
||||
pinfo['versions'].append(version)
|
||||
data = json.loads(public.readFile(jsonFile));
|
||||
data = json.loads(public.readFile(jsonFile))
|
||||
is_exists = False
|
||||
for i in range(len(data)):
|
||||
if data[i]['name'] == pinfo['name']:
|
||||
data[i] = pinfo
|
||||
is_exists = True
|
||||
|
||||
if not is_exists: data.append(pinfo);
|
||||
if not is_exists: data.append(pinfo)
|
||||
|
||||
public.writeFile(jsonFile,json.dumps(data));
|
||||
return public.returnMsg(True,'Import Success!');
|
||||
public.writeFile(jsonFile,json.dumps(data))
|
||||
return public.returnMsg(True,'Import Success!')
|
||||
|
||||
#取本地包信息
|
||||
def GetPackageOther(self,get):
|
||||
p_name = get.p_name
|
||||
jsonFile = self.__setupPath + '/deployment_list_other.json';
|
||||
jsonFile = self.__setupPath + '/deployment_list_other.json'
|
||||
if not os.path.exists(jsonFile): public.returnMsg(False,'could not find [%s]' % p_name)
|
||||
data = json.loads(public.readFile(jsonFile));
|
||||
data = json.loads(public.readFile(jsonFile))
|
||||
|
||||
for i in range(len(data)):
|
||||
if data[i]['name'] == p_name: return data[i]
|
||||
@@ -180,23 +181,23 @@ class plugin_deployment:
|
||||
|
||||
#删除程序包
|
||||
def DelPackage(self,get):
|
||||
jsonFile = self.__setupPath + '/deployment_list_other.json';
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'Profile does not exist!');
|
||||
jsonFile = self.__setupPath + '/deployment_list_other.json'
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'Profile does not exist!')
|
||||
|
||||
data = {}
|
||||
data = json.loads(public.readFile(jsonFile));
|
||||
data = json.loads(public.readFile(jsonFile))
|
||||
|
||||
tmp = [];
|
||||
tmp = []
|
||||
for d in data:
|
||||
if d['name'] == get.dname:
|
||||
s_file = self.__panelPath + '/package/' + d['name'] + '.zip'
|
||||
if os.path.exists(s_file): os.remove(s_file)
|
||||
continue;
|
||||
tmp.append(d);
|
||||
continue
|
||||
tmp.append(d)
|
||||
|
||||
data = tmp;
|
||||
public.writeFile(jsonFile,json.dumps(data));
|
||||
return public.returnMsg(True,'Successfully deleted!');
|
||||
data = tmp
|
||||
public.writeFile(jsonFile,json.dumps(data))
|
||||
return public.returnMsg(True,'Successfully deleted!')
|
||||
|
||||
#下载文件
|
||||
def DownloadFile(self,url,filename):
|
||||
@@ -205,15 +206,15 @@ class plugin_deployment:
|
||||
if not os.path.exists(path): os.makedirs(path)
|
||||
import urllib,socket
|
||||
socket.setdefaulttimeout(10)
|
||||
self.pre = 0;
|
||||
self.oldTime = time.time();
|
||||
self.pre = 0
|
||||
self.oldTime = time.time()
|
||||
if sys.version_info[0] == 2:
|
||||
urllib.urlretrieve(url,filename=filename,reporthook= self.DownloadHook)
|
||||
else:
|
||||
urllib.request.urlretrieve(url,filename=filename,reporthook= self.DownloadHook)
|
||||
self.WriteLogs(json.dumps({'name':'Download File','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.WriteLogs(json.dumps({'name':'Download File','total':0,'used':0,'pre':0,'speed':0}))
|
||||
except:
|
||||
if self.timeoutCount > 5: return;
|
||||
if self.timeoutCount > 5: return
|
||||
self.timeoutCount += 1
|
||||
time.sleep(5)
|
||||
self.DownloadFile(url,filename)
|
||||
@@ -223,14 +224,14 @@ class plugin_deployment:
|
||||
used = count * blockSize
|
||||
pre1 = int((100.0 * used / totalSize))
|
||||
if self.pre != pre1:
|
||||
dspeed = used / (time.time() - self.oldTime);
|
||||
dspeed = used / (time.time() - self.oldTime)
|
||||
speed = {'name':'Download File','total':totalSize,'used':used,'pre':self.pre,'speed':dspeed}
|
||||
self.WriteLogs(json.dumps(speed))
|
||||
self.pre = pre1
|
||||
|
||||
#写输出日志
|
||||
def WriteLogs(self,logMsg):
|
||||
fp = open(self.logPath,'w+');
|
||||
fp = open(self.logPath,'w+')
|
||||
fp.write(logMsg)
|
||||
fp.close()
|
||||
|
||||
@@ -240,8 +241,8 @@ class plugin_deployment:
|
||||
#param string php_version PHP版本
|
||||
def SetupPackage(self,get):
|
||||
name = get.dname
|
||||
site_name = get.site_name;
|
||||
php_version = get.php_version;
|
||||
site_name = get.site_name
|
||||
php_version = get.php_version
|
||||
#取基础信息
|
||||
find = public.M('sites').where('name=?',(site_name,)).field('id,path,name').find()
|
||||
if not 'path' in find:
|
||||
@@ -249,57 +250,57 @@ class plugin_deployment:
|
||||
path = find['path']
|
||||
if path.replace('//','/') == '/': return public.returnMsg(False,'Dangerous website root directory!')
|
||||
#获取包信息
|
||||
pinfo = self.GetPackageInfo(name);
|
||||
pinfo = self.GetPackageInfo(name)
|
||||
id = pinfo['id']
|
||||
if not pinfo: return public.returnMsg(False,'The specified package does not exist.!');
|
||||
if not pinfo: return public.returnMsg(False,'The specified package does not exist.!')
|
||||
|
||||
#检查本地包
|
||||
self.WriteLogs(json.dumps({'name':'Verifying package...','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.WriteLogs(json.dumps({'name':'Verifying package...','total':0,'used':0,'pre':0,'speed':0}))
|
||||
pack_path = self.__panelPath + '/package'
|
||||
if not os.path.exists(pack_path): os.makedirs(pack_path,384)
|
||||
packageZip = pack_path + '/'+ name + '.zip';
|
||||
isDownload = False;
|
||||
packageZip = pack_path + '/'+ name + '.zip'
|
||||
isDownload = False
|
||||
if os.path.exists(packageZip):
|
||||
md5str = self.GetFileMd5(packageZip);
|
||||
if md5str != pinfo['versions'][0]['md5']: isDownload = True;
|
||||
md5str = self.GetFileMd5(packageZip)
|
||||
if md5str != pinfo['versions'][0]['md5']: isDownload = True
|
||||
else:
|
||||
isDownload = True;
|
||||
isDownload = True
|
||||
|
||||
#下载文件
|
||||
if isDownload:
|
||||
self.WriteLogs(json.dumps({'name':'Downloading file ...','total':0,'used':0,'pre':0,'speed':0}));
|
||||
if pinfo['versions'][0]['download']: self.DownloadFile('http://www.bt.cn/api/Pluginother/get_file?fname=' + pinfo['versions'][0]['download'], packageZip);
|
||||
self.WriteLogs(json.dumps({'name':'Downloading file ...','total':0,'used':0,'pre':0,'speed':0}))
|
||||
if pinfo['versions'][0]['download']: self.DownloadFile('http://www.bt.cn/api/Pluginother/get_file?fname=' + pinfo['versions'][0]['download'], packageZip)
|
||||
|
||||
if not os.path.exists(packageZip): return public.returnMsg(False,'File download failed!' + packageZip);
|
||||
if not os.path.exists(packageZip): return public.returnMsg(False,'File download failed!' + packageZip)
|
||||
|
||||
pinfo = self.set_temp_file(packageZip,path)
|
||||
if not pinfo: return public.returnMsg(False,'Cannot find [aaPanel Auto Deployment Configuration File] in the installation package')
|
||||
|
||||
#设置权限
|
||||
self.WriteLogs(json.dumps({'name':'Setting permissions','total':0,'used':0,'pre':0,'speed':0}));
|
||||
public.ExecShell('chmod -R 755 ' + path);
|
||||
public.ExecShell('chown -R www.www ' + path);
|
||||
self.WriteLogs(json.dumps({'name':'Setting permissions','total':0,'used':0,'pre':0,'speed':0}))
|
||||
public.ExecShell('chmod -R 755 ' + path)
|
||||
public.ExecShell('chown -R www.www ' + path)
|
||||
if pinfo['chmod']:
|
||||
for chm in pinfo['chmod']:
|
||||
public.ExecShell('chmod -R ' + str(chm['mode']) + ' ' + (path + '/' + chm['path']).replace('//','/'));
|
||||
public.ExecShell('chmod -R ' + str(chm['mode']) + ' ' + (path + '/' + chm['path']).replace('//','/'))
|
||||
|
||||
#安装PHP扩展
|
||||
self.WriteLogs(json.dumps({'name':'Install the necessary PHP extensions','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.WriteLogs(json.dumps({'name':'Install the necessary PHP extensions','total':0,'used':0,'pre':0,'speed':0}))
|
||||
import files
|
||||
mfile = files.files();
|
||||
if type(pinfo['php_ext']) != list : pinfo['php_ext'] = pinfo['php_ext'].strip().split(',')
|
||||
for ext in pinfo['php_ext']:
|
||||
if ext == 'pathinfo':
|
||||
import config
|
||||
con = config.config();
|
||||
get.version = php_version;
|
||||
get.type = 'on';
|
||||
con.setPathInfo(get);
|
||||
con = config.config()
|
||||
get.version = php_version
|
||||
get.type = 'on'
|
||||
con.setPathInfo(get)
|
||||
else:
|
||||
get.name = ext
|
||||
get.version = php_version
|
||||
get.type = '1';
|
||||
mfile.InstallSoft(get);
|
||||
get.type = '1'
|
||||
mfile.InstallSoft(get)
|
||||
|
||||
#解禁PHP函数
|
||||
if 'enable_functions' in pinfo:
|
||||
@@ -308,48 +309,48 @@ class plugin_deployment:
|
||||
php_f = public.GetConfigValue('setup_path') + '/php/' + php_version + '/etc/php.ini'
|
||||
php_c = public.readFile(php_f)
|
||||
rep = "disable_functions\s*=\s{0,1}(.*)\n"
|
||||
tmp = re.search(rep,php_c).groups();
|
||||
disable_functions = tmp[0].split(',');
|
||||
tmp = re.search(rep,php_c).groups()
|
||||
disable_functions = tmp[0].split(',')
|
||||
for fun in pinfo['enable_functions']:
|
||||
fun = fun.strip()
|
||||
if fun in disable_functions: disable_functions.remove(fun)
|
||||
disable_functions = ','.join(disable_functions)
|
||||
php_c = re.sub(rep, 'disable_functions = ' + disable_functions + "\n", php_c);
|
||||
php_c = re.sub(rep, 'disable_functions = ' + disable_functions + "\n", php_c)
|
||||
public.writeFile(php_f,php_c)
|
||||
public.phpReload(php_version)
|
||||
except:pass
|
||||
|
||||
|
||||
#执行额外shell进行依赖安装
|
||||
self.WriteLogs(json.dumps({'name':'Execute extra SHELL','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.WriteLogs(json.dumps({'name':'Execute extra SHELL','total':0,'used':0,'pre':0,'speed':0}))
|
||||
if os.path.exists(path+'/install.sh'):
|
||||
public.ExecShell('cd '+path+' && bash ' + 'install.sh ' + find['name'] + " &> install.log");
|
||||
public.ExecShell('cd '+path+' && bash ' + 'install.sh ' + find['name'] + " &> install.log")
|
||||
public.ExecShell('rm -f ' + path+'/install.sh')
|
||||
|
||||
#是否执行Composer
|
||||
if os.path.exists(path + '/composer.json'):
|
||||
self.WriteLogs(json.dumps({'name':'Execute Composer','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.WriteLogs(json.dumps({'name':'Execute Composer','total':0,'used':0,'pre':0,'speed':0}))
|
||||
if not os.path.exists(path + '/composer.lock'):
|
||||
execPHP = '/www/server/php/' + php_version +'/bin/php';
|
||||
execPHP = '/www/server/php/' + php_version +'/bin/php'
|
||||
if execPHP:
|
||||
if public.get_url().find('125.88'):
|
||||
public.ExecShell('cd ' +path+' && '+execPHP+' /usr/bin/composer config repo.packagist composer https://packagist.phpcomposer.com');
|
||||
import panelSite;
|
||||
public.ExecShell('cd ' +path+' && '+execPHP+' /usr/bin/composer config repo.packagist composer https://packagist.phpcomposer.com')
|
||||
import panelSite
|
||||
phpini = '/www/server/php/' + php_version + '/etc/php.ini'
|
||||
phpiniConf = public.readFile(phpini);
|
||||
phpiniConf = phpiniConf.replace('proc_open,proc_get_status,','');
|
||||
public.writeFile(phpini,phpiniConf);
|
||||
public.ExecShell('nohup cd '+path+' && '+execPHP+' /usr/bin/composer install -vvv > /tmp/composer.log 2>&1 &');
|
||||
phpiniConf = public.readFile(phpini)
|
||||
phpiniConf = phpiniConf.replace('proc_open,proc_get_status,','')
|
||||
public.writeFile(phpini,phpiniConf)
|
||||
public.ExecShell('nohup cd '+path+' && '+execPHP+' /usr/bin/composer install -vvv > /tmp/composer.log 2>&1 &')
|
||||
|
||||
#写伪静态
|
||||
self.WriteLogs(json.dumps({'name':'Set URL rewrite','total':0,'used':0,'pre':0,'speed':0}));
|
||||
swfile = path + '/nginx.rewrite';
|
||||
self.WriteLogs(json.dumps({'name':'Set URL rewrite','total':0,'used':0,'pre':0,'speed':0}))
|
||||
swfile = path + '/nginx.rewrite'
|
||||
if os.path.exists(swfile):
|
||||
rewriteConf = public.readFile(swfile);
|
||||
dwfile = self.__panelPath + '/vhost/rewrite/' + site_name + '.conf';
|
||||
public.writeFile(dwfile,rewriteConf);
|
||||
rewriteConf = public.readFile(swfile)
|
||||
dwfile = self.__panelPath + '/vhost/rewrite/' + site_name + '.conf'
|
||||
public.writeFile(dwfile,rewriteConf)
|
||||
|
||||
swfile = path + '/.htaccess';
|
||||
swfile = path + '/.htaccess'
|
||||
if os.path.exists(swfile):
|
||||
swpath = (path + '/'+ pinfo['run_path'] + '/.htaccess').replace('//','/')
|
||||
if pinfo['run_path'] != '/' and not os.path.exists(swpath):
|
||||
@@ -366,23 +367,23 @@ class plugin_deployment:
|
||||
if rm_file_body.find('panel-heading') != -1: os.remove(rm_file)
|
||||
|
||||
#设置运行目录
|
||||
self.WriteLogs(json.dumps({'name':'Set the run directory','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.WriteLogs(json.dumps({'name':'Set the run directory','total':0,'used':0,'pre':0,'speed':0}))
|
||||
if pinfo['run_path'] != '/':
|
||||
import panelSite;
|
||||
siteObj = panelSite.panelSite();
|
||||
mobj = obj();
|
||||
mobj.id = find['id'];
|
||||
mobj.runPath = pinfo['run_path'];
|
||||
siteObj.SetSiteRunPath(mobj);
|
||||
import panelSite
|
||||
siteObj = panelSite.panelSite()
|
||||
mobj = obj()
|
||||
mobj.id = find['id']
|
||||
mobj.runPath = pinfo['run_path']
|
||||
siteObj.SetSiteRunPath(mobj)
|
||||
|
||||
#导入数据
|
||||
self.WriteLogs(json.dumps({'name':'Import database','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.WriteLogs(json.dumps({'name':'Import database','total':0,'used':0,'pre':0,'speed':0}))
|
||||
if os.path.exists(path+'/import.sql'):
|
||||
databaseInfo = public.M('databases').where('pid=?',(find['id'],)).field('username,password').find();
|
||||
databaseInfo = public.M('databases').where('pid=?',(find['id'],)).field('username,password').find()
|
||||
if databaseInfo:
|
||||
public.ExecShell('/www/server/mysql/bin/mysql -u' + databaseInfo['username'] + ' -p' + databaseInfo['password'] + ' ' + databaseInfo['username'] + ' < ' + path + '/import.sql');
|
||||
public.ExecShell('rm -f ' + path + '/import.sql');
|
||||
siteConfigFile = (path + '/' + pinfo['db_config']).replace('//','/');
|
||||
public.ExecShell('/www/server/mysql/bin/mysql -u' + databaseInfo['username'] + ' -p' + databaseInfo['password'] + ' ' + databaseInfo['username'] + ' < ' + path + '/import.sql')
|
||||
public.ExecShell('rm -f ' + path + '/import.sql')
|
||||
siteConfigFile = (path + '/' + pinfo['db_config']).replace('//','/')
|
||||
if os.path.exists(siteConfigFile):
|
||||
siteConfig = public.readFile(siteConfigFile)
|
||||
siteConfig = siteConfig.replace('BT_DB_USERNAME',databaseInfo['username'])
|
||||
@@ -391,7 +392,7 @@ class plugin_deployment:
|
||||
public.writeFile(siteConfigFile,siteConfig)
|
||||
|
||||
#清理文件和目录
|
||||
self.WriteLogs(json.dumps({'name':'清理多余的文件','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.WriteLogs(json.dumps({'name':'清理多余的文件','total':0,'used':0,'pre':0,'speed':0}))
|
||||
if type(pinfo['remove_file']) == str : pinfo['remove_file'] = pinfo['remove_file'].strip().split(',')
|
||||
print(pinfo['remove_file'])
|
||||
for f_path in pinfo['remove_file']:
|
||||
@@ -405,17 +406,17 @@ class plugin_deployment:
|
||||
else:
|
||||
public.ExecShell("rm -rf " + filename)
|
||||
|
||||
public.serviceReload();
|
||||
if id: self.depTotal(id);
|
||||
self.WriteLogs(json.dumps({'name':'Ready to deploy','total':0,'used':0,'pre':0,'speed':0}));
|
||||
return public.returnMsg(True,pinfo);
|
||||
public.serviceReload()
|
||||
if id: self.depTotal(id)
|
||||
self.WriteLogs(json.dumps({'name':'Ready to deploy','total':0,'used':0,'pre':0,'speed':0}))
|
||||
return public.returnMsg(True,pinfo)
|
||||
|
||||
|
||||
#处理临时文件
|
||||
def set_temp_file(self,filename,path):
|
||||
public.ExecShell("rm -rf " + self.__tmp + '/*')
|
||||
self.WriteLogs(json.dumps({'name':'Unpacking the package...','total':0,'used':0,'pre':0,'speed':0}));
|
||||
public.ExecShell('unzip -o '+filename+' -d ' + self.__tmp);
|
||||
self.WriteLogs(json.dumps({'name':'Unpacking the package...','total':0,'used':0,'pre':0,'speed':0}))
|
||||
public.ExecShell('unzip -o '+filename+' -d ' + self.__tmp)
|
||||
auto_config = 'auto_install.json'
|
||||
p_info = self.__tmp + '/' + auto_config
|
||||
p_tmp = self.__tmp
|
||||
@@ -475,33 +476,33 @@ class plugin_deployment:
|
||||
#获取进度
|
||||
def GetSpeed(self,get):
|
||||
try:
|
||||
if not os.path.exists(self.logPath):return public.returnMsg(False,'There are currently no deployment tasks!');
|
||||
return json.loads(public.readFile(self.logPath));
|
||||
if not os.path.exists(self.logPath):return public.returnMsg(False,'There are currently no deployment tasks!')
|
||||
return json.loads(public.readFile(self.logPath))
|
||||
except:
|
||||
return {'name':'Ready to deploy','total':0,'used':0,'pre':0,'speed':0}
|
||||
|
||||
#获取包信息
|
||||
def GetPackageInfo(self,name):
|
||||
data = self.GetDepList(None);
|
||||
if not data: return False;
|
||||
data = self.GetDepList(None)
|
||||
if not data: return False
|
||||
for info in data['list']:
|
||||
if info['name'] == name:
|
||||
return info;
|
||||
return False;
|
||||
return info
|
||||
return False
|
||||
|
||||
#检查指定包是否存在
|
||||
def CheckPackageExists(self,name):
|
||||
data = self.GetDepList(None);
|
||||
if not data: return False;
|
||||
data = self.GetDepList(None)
|
||||
if not data: return False
|
||||
for info in data['list']:
|
||||
if info['name'] == name: return True;
|
||||
if info['name'] == name: return True
|
||||
|
||||
return False;
|
||||
return False
|
||||
|
||||
#文件的MD5值
|
||||
def GetFileMd5(self,filename):
|
||||
if not os.path.isfile(filename): return False;
|
||||
import hashlib;
|
||||
if not os.path.isfile(filename): return False
|
||||
import hashlib
|
||||
myhash = hashlib.md5()
|
||||
f = open(filename,'rb')
|
||||
while True:
|
||||
@@ -510,8 +511,8 @@ class plugin_deployment:
|
||||
break
|
||||
myhash.update(b)
|
||||
f.close()
|
||||
return myhash.hexdigest();
|
||||
return myhash.hexdigest()
|
||||
|
||||
#获取站点标识
|
||||
def GetSiteId(self,get):
|
||||
return public.M('sites').where('name=?',(get.webname,)).getField('id');
|
||||
return public.M('sites').where('name=?',(get.webname,)).getField('id')
|
||||
|
||||
+326
-36
@@ -46,14 +46,6 @@ def HttpGet(url,timeout = 6,headers = {}):
|
||||
@return string
|
||||
"""
|
||||
if is_local(): return False
|
||||
home = 'www.bt.cn'
|
||||
host_home = 'data/home_host.pl'
|
||||
old_url = url
|
||||
if url.find(home) != -1:
|
||||
if os.path.exists(host_home):
|
||||
headers['host'] = home
|
||||
url = url.replace(home,readFile(host_home))
|
||||
|
||||
import http_requests
|
||||
res = http_requests.get(url,timeout=timeout,headers = headers)
|
||||
if res.status_code == 0:
|
||||
@@ -118,14 +110,6 @@ def HttpPost(url,data,timeout = 6,headers = {}):
|
||||
return string
|
||||
"""
|
||||
if is_local(): return False
|
||||
home = 'www.bt.cn'
|
||||
host_home = 'data/home_host.pl'
|
||||
old_url = url
|
||||
if url.find(home) != -1:
|
||||
if os.path.exists(host_home):
|
||||
headers['host'] = home
|
||||
url = url.replace(home, readFile(host_home))
|
||||
|
||||
import http_requests
|
||||
res = http_requests.post(url,data=data,timeout=timeout,headers = headers)
|
||||
if res.status_code == 0:
|
||||
@@ -343,8 +327,10 @@ def ReadFile(filename,mode = 'r'):
|
||||
fp = open(filename, mode,encoding="utf-8")
|
||||
f_body = fp.read()
|
||||
fp.close()
|
||||
except Exception as ex2:
|
||||
return False
|
||||
except:
|
||||
fp = open(filename, mode,encoding="GBK")
|
||||
f_body = fp.read()
|
||||
fp.close()
|
||||
else:
|
||||
return False
|
||||
return f_body
|
||||
@@ -544,7 +530,10 @@ def GetLocalIp():
|
||||
if not ipaddress:
|
||||
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
|
||||
m_str = HttpGet(url)
|
||||
ipaddress = re.search(r'\d+.\d+.\d+.\d+',m_str).group(0)
|
||||
if isinstance(m_str,bytes):
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', m_str.decode('utf-8')).group(0)
|
||||
else:
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', m_str).group(0)
|
||||
WriteFile(filename,ipaddress)
|
||||
c_ip = check_ip(ipaddress)
|
||||
if not c_ip: return GetHost()
|
||||
@@ -1356,11 +1345,18 @@ def get_page(count, p=1, rows=12, callback='', result='1,2,3,4,5,8'):
|
||||
# 取面板版本
|
||||
def version():
|
||||
try:
|
||||
from BTPanel import g
|
||||
return g.version
|
||||
except:
|
||||
comm = ReadFile('/www/server/panel/class/common.py')
|
||||
return re.search("g\.version\s*=\s*'(\d+\.\d+\.\d+)'", comm).groups()[0]
|
||||
return re.search("g\.version\s*=\s*'(\d+\.\d+\.\d+)'",comm).groups()[0]
|
||||
except:
|
||||
return get_panel_version()
|
||||
|
||||
def get_panel_version():
|
||||
comm = ReadFile('/www/server/panel/class/common.py')
|
||||
s_key = 'g.version = '
|
||||
s_len = len(s_key)
|
||||
s_leff = comm.find(s_key) + s_len
|
||||
version = comm[s_leff:s_leff+6].strip().strip("'")
|
||||
return version
|
||||
|
||||
|
||||
# 取文件或目录大小
|
||||
@@ -1544,7 +1540,9 @@ def check_ip_panel():
|
||||
iplist = ReadFile(ip_file)
|
||||
if iplist:
|
||||
iplist = iplist.strip()
|
||||
if not GetClientIp() in iplist.split(','):
|
||||
client_ip = GetClientIp()
|
||||
if client_ip in ['127.0.0.1','localhost','::1']: return False
|
||||
if not client_ip in iplist.split(','):
|
||||
errorStr = ReadFile('./BTPanel/templates/' + GetConfigValue('template') + '/error2.html')
|
||||
try:
|
||||
errorStr = errorStr.format(getMsg('PAGE_ERR_TITLE'),getMsg('PAGE_ERR_IP_H1'),getMsg('PAGE_ERR_IP_P1',(GetClientIp(),)),getMsg('PAGE_ERR_IP_P2'),getMsg('PAGE_ERR_IP_P3'),getMsg('NAME'),getMsg('PAGE_ERR_HELP'))
|
||||
@@ -1557,6 +1555,8 @@ def check_domain_panel():
|
||||
tmp = GetHost()
|
||||
domain = ReadFile('data/domain.conf')
|
||||
if domain:
|
||||
client_ip = GetClientIp()
|
||||
if client_ip in ['127.0.0.1','localhost','::1']: return False
|
||||
if tmp.strip().lower() != domain.strip().lower():
|
||||
errorStr = ReadFile('./BTPanel/templates/' + GetConfigValue('template') + '/error2.html')
|
||||
try:
|
||||
@@ -1586,15 +1586,16 @@ def auto_backup_panel():
|
||||
shutil.copytree(panel_paeh + '/data',backup_path + '/data')
|
||||
shutil.copytree(panel_paeh + '/config',backup_path + '/config')
|
||||
shutil.copytree(panel_paeh + '/vhost',backup_path + '/vhost')
|
||||
ExecShell("chmod -R 600 {path};chown -R root.root {path}".format(paht=b_path))
|
||||
ExecShell("chmod -R 600 {path};chown -R root.root {path}".format(path=b_path))
|
||||
time_now = time.time() - (86400 * 15)
|
||||
for f in os.listdir(b_path):
|
||||
try:
|
||||
if time.mktime(time.strptime(f, "%Y-%m-%d")) < time_now:
|
||||
path = b_path + '/' + f
|
||||
if os.path.exists(path): shutil.rmtree(path)
|
||||
except: continue
|
||||
except:pass
|
||||
if time.mktime(time.strptime(f, "%Y-%m-%d")) < time_now:
|
||||
path = b_path + '/' + f
|
||||
if os.path.exists(path): shutil.rmtree(path)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
#检查端口状态
|
||||
@@ -1818,6 +1819,7 @@ def sub_php_address(conf_file,rep,tsub,php_version):
|
||||
@param php_version string 指定PHP版本
|
||||
@return bool
|
||||
'''
|
||||
if not os.path.isfile(conf_file): return False
|
||||
if not os.path.exists(conf_file): return False
|
||||
conf = readFile(conf_file)
|
||||
if not conf: return False
|
||||
@@ -2020,10 +2022,7 @@ def get_linux_distribution():
|
||||
if os.path.exists(redhat_file):
|
||||
try:
|
||||
tmp = readFile(redhat_file).split()[3][0]
|
||||
if int(tmp) > 7:
|
||||
distribution = 'centos8'
|
||||
else:
|
||||
distribution = 'centos7'
|
||||
distribution = 'centos{}'.format(tmp)
|
||||
except:
|
||||
distribution = 'centos7'
|
||||
return distribution
|
||||
@@ -2053,6 +2052,17 @@ def ip2long(ip):
|
||||
iplong = 2 ** 24 * int(ips[0]) + 2 ** 16 * int(ips[1]) + 2 ** 8 * int(ips[2]) + int(ips[3])
|
||||
return iplong
|
||||
|
||||
def is_local_ip(ip):
|
||||
'''
|
||||
@name 判断是否为本地(内网)IP地址
|
||||
@author hwliang<2021-03-26>
|
||||
@param ip string(ipv4)
|
||||
@return bool
|
||||
'''
|
||||
patt = r"^(192\.168|127|10|172\.(16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31))\."
|
||||
if re.match(patt,ip): return True
|
||||
return False
|
||||
|
||||
#获取debug日志
|
||||
def get_debug_log():
|
||||
from BTPanel import request
|
||||
@@ -2362,6 +2372,26 @@ def run_thread(fun,args = (),daemon=False):
|
||||
p.start()
|
||||
return True
|
||||
|
||||
def check_domain_cloud(domain):
|
||||
run_thread(cloud_check_domain,(domain,))
|
||||
|
||||
def cloud_check_domain(domain):
|
||||
'''
|
||||
@name 从云端验证域名的可访问性,并将结果保存到文件
|
||||
@author hwliang<2020-12-10>
|
||||
@param domain {string} 被验证的域名
|
||||
@return void
|
||||
'''
|
||||
try:
|
||||
check_domain_path = '/www/server/panel/data/check_domain/'
|
||||
if not os.path.exists(check_domain_path):
|
||||
os.makedirs(check_domain_path,384)
|
||||
result = httpPost('https://www.aapanel.com/api/panel/checkDomain',{"domain":domain})
|
||||
cd_file = check_domain_path + domain +'.pl'
|
||||
writeFile(cd_file,result)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def send_file(data,fname='',mimetype = ''):
|
||||
'''
|
||||
@@ -2412,6 +2442,19 @@ def get_ipaddress():
|
||||
iplist = ipa_tmp.split('\n')
|
||||
return iplist
|
||||
|
||||
def get_oem_name():
|
||||
'''
|
||||
@name 获取OEM名称
|
||||
@author hwliang<2021-03-24>
|
||||
@return string
|
||||
'''
|
||||
oem = ''
|
||||
oem_file = '/www/server/panel/data/o.pl'
|
||||
if os.path.exists(oem_file):
|
||||
oem = readFile(oem_file)
|
||||
if oem: oem = oem.strip()
|
||||
return oem
|
||||
|
||||
def fetch_disk_SN():
|
||||
r,e = ExecShell("fdisk -l |grep 'Disk identifier' |awk {'print $3'}")
|
||||
if r:
|
||||
@@ -2428,7 +2471,7 @@ def get_hostname():
|
||||
|
||||
def get_platform():
|
||||
import platform
|
||||
return platform.version()
|
||||
return platform.platform()
|
||||
|
||||
def get_memory():
|
||||
import psutil
|
||||
@@ -2451,6 +2494,13 @@ def fetch_env_info():
|
||||
except:
|
||||
return {}
|
||||
|
||||
def arequests(method,url,data=None,timeout=3):
|
||||
import threading
|
||||
if method == 'post':
|
||||
method = httpPost
|
||||
else:
|
||||
method = httpGet
|
||||
threading.Thread(target=method, args=(url,data,timeout)).start()
|
||||
|
||||
#取通用对象
|
||||
class dict_obj:
|
||||
@@ -2461,6 +2511,98 @@ class dict_obj:
|
||||
def __delitem__(self,key): delattr(self,key)
|
||||
def __delattr__(self, key): delattr(self,key)
|
||||
def get_items(self): return self
|
||||
def get(self,key,default='',format='',limit = []):
|
||||
'''
|
||||
@name 获取指定参数
|
||||
@param key<string> 参数名称,允许在/后面限制参数格式,请参考参数值格式(format)
|
||||
@param default<string> 默认值,默认空字符串
|
||||
@param format<string> 参数值格式(int|str|float|json|xss|path|url|ip|ipv4|ipv6|letter|mail|phone|正则表达式|>1|<1|=1),默认为空
|
||||
@param limit<list> 限制参数值内容
|
||||
@param return mixed
|
||||
'''
|
||||
if key.find('/') != -1:
|
||||
key,format = key.split('/')
|
||||
result = getattr(self,key,default).strip()
|
||||
if format:
|
||||
if format in ['str','string','s']:
|
||||
result = str(result)
|
||||
elif format in ['int','d']:
|
||||
try:
|
||||
result = int(result)
|
||||
except:
|
||||
raise ValueError("Parameters: {}, requires int type data".format(key))
|
||||
elif format in ['float','f']:
|
||||
try:
|
||||
result = float(result)
|
||||
except:
|
||||
raise ValueError("Parameters: {}, float type data required".format(key))
|
||||
elif format in ['json','j']:
|
||||
try:
|
||||
result = json.loads(result)
|
||||
except:
|
||||
raise ValueError("Parameters: {}, requires JSON string".format(key))
|
||||
elif format in ['xss','x']:
|
||||
result = xssencode(result)
|
||||
elif format in ['path','p']:
|
||||
if not path_safe_check(result):
|
||||
raise ValueError("Parameters: {}, the correct path format is required".format(key))
|
||||
result = result.replace('//','/')
|
||||
elif format in ['url','u']:
|
||||
regex = re.compile(
|
||||
r'^(?:http|ftp)s?://'
|
||||
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
|
||||
r'localhost|'
|
||||
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
|
||||
r'(?::\d+)?'
|
||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||
if not re.match(regex,result):
|
||||
raise ValueError('Parameters: {}, the correct URL format is required'.format(key))
|
||||
elif format in ['ip','ipaddr','i','ipv4','ipv6']:
|
||||
if format is 'ipv4':
|
||||
if not is_ipv4(result):
|
||||
raise ValueError('Parameters: {}, the correct ipv4 address is required'.format(key))
|
||||
elif format is 'ipv6':
|
||||
if not is_ipv6(result):
|
||||
raise ValueError('Parameters: {}, the correct ipv6 address is required'.format(key))
|
||||
else:
|
||||
if not is_ipv4(result) and not is_ipv6(result):
|
||||
raise ValueError('Parameters: {}, the correct ipv4/ipv6 address is required'.format(key))
|
||||
elif format in ['w','letter']:
|
||||
if not re.match(r'^\w+$',result):
|
||||
raise ValueError('Parameters: {}, the requirement can only be composed of English letters'.format(key))
|
||||
elif format in ['email','mail','m']:
|
||||
if not re.match(r"^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$",result):
|
||||
raise ValueError("Parameters: {}, the correct email address format is required".format(key))
|
||||
elif format in ['phone','mobile','m']:
|
||||
if not re.match("^[0-9]{11,11}$",result):
|
||||
raise ValueError("Parameters: {}, mobile phone number format required".format(key))
|
||||
elif re.match(r"^[<>=]\d+$",result):
|
||||
operator = format[0]
|
||||
length = int(format[1:].strip())
|
||||
result_len = len(result)
|
||||
error_obj = ValueError("Parameters: {}, the required length is {}".format(key,format))
|
||||
if operator is '=':
|
||||
if result_len != length:
|
||||
raise error_obj
|
||||
elif operator is '>':
|
||||
if result_len < length:
|
||||
raise error_obj
|
||||
else:
|
||||
if result_len > length:
|
||||
raise error_obj
|
||||
elif format[0] in ['^','(','[','\\','.'] or format[-1] in ['$',')',']','+','}']:
|
||||
if not re.match(format,result):
|
||||
raise ValueError("The format of the specified parameter is incorrect, {}:{}".format(key,format))
|
||||
|
||||
if limit:
|
||||
if not result in limit:
|
||||
raise ValueError("The specified parameter value range is incorrect, {}:{}".format(key,limit))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2574,4 +2716,152 @@ def check_app(check='app'):
|
||||
if not app_info: return False
|
||||
return True
|
||||
|
||||
#宝塔邮件报警
|
||||
def send_mail(title,body,is_logs=False,is_type="aapanel login reminder"):
|
||||
if is_logs:
|
||||
try:
|
||||
import send_mail
|
||||
send_mail22 = send_mail.send_mail()
|
||||
tongdao = send_mail22.get_settings()
|
||||
if tongdao['user_mail']['mail_list']==0:return false
|
||||
if not tongdao['user_mail']['info']: return false
|
||||
if len(tongdao['user_mail']['mail_list'])==1:
|
||||
send_mail=tongdao['user_mail']['mail_list'][0]
|
||||
send_mail22.qq_smtp_send(send_mail, title=title, body=body)
|
||||
else:
|
||||
send_mail22.qq_smtp_send(tongdao['user_mail']['mail_list'], title=title, body=body)
|
||||
if is_logs:
|
||||
WriteLog2(is_type, body)
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
import send_mail
|
||||
send_mail22 = send_mail.send_mail()
|
||||
tongdao = send_mail22.get_settings()
|
||||
if tongdao['user_mail']['mail_list'] == 0: return false
|
||||
if not tongdao['user_mail']['info']: return false
|
||||
if len(tongdao['user_mail']['mail_list']) == 1:
|
||||
send_mail = tongdao['user_mail']['mail_list'][0]
|
||||
return send_mail22.qq_smtp_send(send_mail, title=title, body=body)
|
||||
else:
|
||||
return send_mail22.qq_smtp_send(tongdao['user_mail']['mail_list'], title=title, body=body)
|
||||
except:
|
||||
return False
|
||||
|
||||
#宝塔钉钉 or 微信告警
|
||||
def send_dingding(body,is_logs=False,is_type="aapanel login reminder"):
|
||||
if is_logs:
|
||||
try:
|
||||
import send_mail
|
||||
send_mail22 = send_mail.send_mail()
|
||||
tongdao = send_mail22.get_settings()
|
||||
if not tongdao['dingding']['info']: return false
|
||||
tongdao = send_mail22.get_settings()
|
||||
if is_logs:
|
||||
WriteLog2(is_type,body)
|
||||
return send_mail22.dingding_send(body)
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
import send_mail
|
||||
send_mail22 = send_mail.send_mail()
|
||||
tongdao = send_mail22.get_settings()
|
||||
if not tongdao['dingding']['info']: return false
|
||||
tongdao = send_mail22.get_settings()
|
||||
return send_mail22.dingding_send(body)
|
||||
except:return False
|
||||
|
||||
#获取服务器IP
|
||||
def get_ip():
|
||||
if os.path.exists('/www/server/panel/data/iplist.txt'):
|
||||
data=ReadFile('/www/server/panel/data/iplist.txt')
|
||||
return data.strip()
|
||||
else:return '127.0.0.1'
|
||||
|
||||
#获取服务器内网Ip
|
||||
def get_local_ip():
|
||||
try:
|
||||
ret=ExecShell("ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v \"^127\.|^255\.|^0\.\" | head -n 1")
|
||||
local_ip=ret[0].strip()
|
||||
return local_ip
|
||||
except:return '127.0.0.1'
|
||||
|
||||
def create_logs():
|
||||
import db
|
||||
sql = db.Sql()
|
||||
if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'logs2')).count():
|
||||
csql = '''CREATE TABLE `logs2` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`type` TEXT,
|
||||
`log` TEXT,
|
||||
`addtime` TEXT
|
||||
, uid integer DEFAULT '1', username TEXT DEFAULT 'system')'''
|
||||
sql.execute(csql, ())
|
||||
|
||||
def WriteLog2(type,logMsg,args=(),not_web = False):
|
||||
import db
|
||||
create_logs()
|
||||
username = 'system'
|
||||
uid = 1
|
||||
tmp_msg = ''
|
||||
sql = db.Sql()
|
||||
mDate = time.strftime('%Y-%m-%d %X',time.localtime())
|
||||
data = (uid,username,type,logMsg + tmp_msg,mDate)
|
||||
result = sql.table('logs2').add('uid,username,type,log,addtime',data)
|
||||
|
||||
def check_ip_white(path,ip):
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
path_json=json.loads(ReadFile(path))
|
||||
except:
|
||||
WriteFile(path,'[]')
|
||||
return False
|
||||
if ip in path_json:return True
|
||||
else:return False
|
||||
else:
|
||||
return False
|
||||
|
||||
#登陆告警
|
||||
def login_send_body(is_type,username,login_ip,port):
|
||||
if os.path.exists("/www/server/panel/data/login_send_mail.pl"):
|
||||
if check_ip_white('/www/server/panel/data/send_login_white.json',login_ip):return False
|
||||
send_mail("aapanel login reminder","aapanel login reminder:Your server "+get_ip()+" successfully logged in via "+is_type+", account number: "+username+", login IP: "+login_ip+":"+port+", login time: "+time.strftime('%Y -%m-%d %X',time.localtime()), True)
|
||||
if os.path.exists("/www/server/panel/data/login_send_dingding.pl"):
|
||||
if check_ip_white('/www/server/panel/data/send_login_white.json',login_ip):return False
|
||||
send_dingding("aapanel login reminder:Your server "+get_ip()+" successfully logged in via "+is_type+", account number: "+username+", login IP: "+login_ip+":"+port+", login time: "+time.strftime('%Y -%m-%d %X',time.localtime()), True)
|
||||
|
||||
#普通模式下调用发送消息【设置登陆告警后的设置】
|
||||
#title= 发送的title
|
||||
#body= 发送的body
|
||||
#is_logs= 是否记录日志
|
||||
#is_type=发送告警的类型
|
||||
def send_to_body(title,body,is_logs=False,is_type="aaPanel email alert"):
|
||||
if os.path.exists("/www/server/panel/data/login_send_mail.pl"):
|
||||
if is_logs:
|
||||
send_mail(title, body,True,is_type)
|
||||
send_mail(title,body)
|
||||
if os.path.exists("/www/server/panel/data/login_send_dingding.pl"):
|
||||
if is_logs:
|
||||
send_dingding(body,True,is_type)
|
||||
send_dingding(body)
|
||||
|
||||
#普通发送消息
|
||||
#send_type= ["mail","dingding"]
|
||||
#title =发送的头
|
||||
#body= 发送消息的内容
|
||||
def send_body_words(send_type,title,body):
|
||||
if send_type=='mail':
|
||||
return send_mail(title,body)
|
||||
if send_type=='dingding':
|
||||
return send_dingding(body)
|
||||
|
||||
def return_is_send_info():
|
||||
import send_mail
|
||||
send_mail22 = send_mail.send_mail()
|
||||
tongdao = send_mail22.get_settings()
|
||||
ret={}
|
||||
ret['mail']=tongdao['user_mail']['user_name']
|
||||
ret['dingding']=tongdao['dingding']['dingding']
|
||||
return ret
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: linxiao
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 数据库备份权限检测
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
import os, re, public, panelMysql
|
||||
|
||||
_title = 'Database backup permission detection'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Check whether the MySQL root user has database backup permissions" # 描述
|
||||
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-09-19' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_database_priv.pl")
|
||||
_tips = [
|
||||
"To temporarily access the database without authorization, it is recommended to restore all permissions of the root user.",
|
||||
]
|
||||
|
||||
_help = ''
|
||||
|
||||
|
||||
def check_run():
|
||||
"""检测root用户是否具备数据库备份权限
|
||||
|
||||
@author linxiao<2020-9-18>
|
||||
@return (bool, msg)
|
||||
"""
|
||||
mycnf_file = '/etc/my.cnf'
|
||||
if not os.path.exists(mycnf_file):
|
||||
return True, 'Risk-free'
|
||||
mycnf = public.readFile(mycnf_file)
|
||||
port_tmp = re.findall(r"port\s*=\s*(\d+)", mycnf)
|
||||
if not port_tmp:
|
||||
return True, 'Risk-free'
|
||||
if not public.ExecShell("lsof -i :{}".format(port_tmp[0]))[0]:
|
||||
return True, 'Risk-free'
|
||||
|
||||
base_backup_privs = ["Lock_tables_priv", "Select_priv"]
|
||||
select_sql = "Select {} FROM mysql.user WHERE user='root' and " \
|
||||
"host=SUBSTRING_INDEX((select current_user()),'@', " \
|
||||
"-1);".format(",".join(base_backup_privs))
|
||||
select_result = panelMysql.panelMysql().query(select_sql)
|
||||
if not select_result:
|
||||
return False, "The root user has insufficient authority to execute mysqldump backup."
|
||||
select_result = select_result[0]
|
||||
for priv in select_result:
|
||||
if priv.lower() != "y":
|
||||
return False, "The root user has insufficient authority to execute mysqldump backup."
|
||||
return True, 'Risk-free'
|
||||
@@ -18,7 +18,7 @@ import os,sys,re,public
|
||||
_title = 'System directory permissions'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Checks if the System directory permissions are correct" # 描述
|
||||
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-08-05' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_dir_mode.pl")
|
||||
_tips = [
|
||||
@@ -45,8 +45,8 @@ def check_run():
|
||||
['/usr/local',755,'root'],
|
||||
['/etc',755,'root'],
|
||||
['/etc/passwd',644,'root'],
|
||||
['/etc/shadow',000,'root'],
|
||||
['/etc/gshadow',000,'root'],
|
||||
['/etc/shadow',600,'root'],
|
||||
['/etc/gshadow',600,'root'],
|
||||
['/etc/cron.deny',600,'root'],
|
||||
['/etc/anacrontab',600,'root'],
|
||||
['/var',755,'root'],
|
||||
@@ -56,6 +56,7 @@ def check_run():
|
||||
['/var/spool/cron/crontabs/root',600,'root'],
|
||||
['/www',755,'root'],
|
||||
['/www/server',755,'root'],
|
||||
['/www/wwwroot',755,'root'],
|
||||
['/root',550,'root'],
|
||||
['/mnt',755,'root'],
|
||||
['/home',755,'root'],
|
||||
@@ -67,15 +68,15 @@ def check_run():
|
||||
]
|
||||
|
||||
not_mode_list = []
|
||||
for d in dir_list:
|
||||
if not os.path.exists(d[0]): continue
|
||||
u_mode = public.get_mode_and_user(d[0])
|
||||
if u_mode['user'] != d[2]:
|
||||
not_mode_list.append("{} Current permissions: {} : {} Security permissions: {} : {}".format(d[0],u_mode['mode'],u_mode['user'],d[1],d[2]))
|
||||
if int(u_mode['mode']) != d[1]:
|
||||
not_mode_list.append("{} Current permissions: {} : {} Security permissions: {} : {}".format(d[0],u_mode['mode'],u_mode['user'],d[1],d[2]))
|
||||
# for d in dir_list:
|
||||
# if not os.path.exists(d[0]): continue
|
||||
# u_mode = public.get_mode_and_user(d[0])
|
||||
# if u_mode['user'] != d[2]:
|
||||
# not_mode_list.append("{} 当前权限: {} : {} 安全权限: {} : {}".format(d[0],u_mode['mode'],u_mode['user'],d[1],d[2]))
|
||||
# if int(u_mode['mode']) != d[1]:
|
||||
# not_mode_list.append("{} 当前权限: {} : {} 安全权限: {} : {}".format(d[0],u_mode['mode'],u_mode['user'],d[1],d[2]))
|
||||
|
||||
if not_mode_list:
|
||||
return False,'The following system file or directory permissions are incorrect: <br />' + ("<br />".join(not_mode_list))
|
||||
# if not_mode_list:
|
||||
# return False,'以下关键文件或目录权限错误: <br />' + ("<br />".join(not_mode_list))
|
||||
|
||||
return True,'Risk-free'
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: linxiao
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# FTP弱口令检测
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
import os, re#, public
|
||||
|
||||
_title = 'FTP service weak password detection'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Detect weak passwords for the enabled FTP service" # 描述
|
||||
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-09-19' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_ftp_pass.pl")
|
||||
_tips = [
|
||||
"Please go to [FTP] page to change FTP password",
|
||||
"Note: Please do not use too simple account and password, so as not to cause security risks",
|
||||
"Use [Fail2ban] plug-in to protect FTP service"
|
||||
]
|
||||
|
||||
_help = ''
|
||||
_topic = "ftp"
|
||||
|
||||
|
||||
def check_run():
|
||||
"""检测FTP弱口令
|
||||
|
||||
@author linxiao<2020-9-19>
|
||||
@return (bool, msg)
|
||||
"""
|
||||
|
||||
ftp_list = public.M("ftps").field("name,password,status").select()
|
||||
if not ftp_list:
|
||||
return True, 'Risk-free'
|
||||
weak_pass_ftp = []
|
||||
for ftp_info in ftp_list:
|
||||
status = ftp_info["status"]
|
||||
if status == "0" or status == 0:
|
||||
continue
|
||||
login_name = ftp_info["name"]
|
||||
login_pass = ftp_info["password"]
|
||||
if not is_strong_password(login_pass):
|
||||
weak_pass_ftp.append(login_name)
|
||||
|
||||
if weak_pass_ftp:
|
||||
return False, "The following FTP service password settings are too simple and pose security risks: <br />" + \
|
||||
"<br />".join(weak_pass_ftp)
|
||||
return True, 'Risk-free'
|
||||
|
||||
|
||||
def is_strong_password(password):
|
||||
"""判断密码复杂度是否安全
|
||||
|
||||
非弱口令标准:长度大于等于7,分别包含数字、小写、大写、特殊字符。
|
||||
@password: 密码文本
|
||||
@return: True/False
|
||||
@author: linxiao<2020-9-19>
|
||||
"""
|
||||
|
||||
if len(password) < 7:
|
||||
return False
|
||||
|
||||
import re
|
||||
digit_reg = "[0-9]" # 匹配数字 +1
|
||||
lower_case_letters_reg = "[a-z]" # 匹配小写字母 +1
|
||||
upper_case_letters_reg = "[A-Z]" # 匹配大写字母 +1
|
||||
special_characters_reg = r"((?=[\x21-\x7e]+)[^A-Za-z0-9])" # 匹配特殊字符 +1
|
||||
|
||||
regs = [digit_reg,
|
||||
lower_case_letters_reg,
|
||||
upper_case_letters_reg,
|
||||
special_characters_reg]
|
||||
|
||||
grade = 0
|
||||
for reg in regs:
|
||||
if re.search(reg, password):
|
||||
grade += 1
|
||||
|
||||
if grade == 4 or (grade >= 2 and len(password) >= 9):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# passwords = ["000000", "aaaaaaa", "Ab2aaaaaa"]
|
||||
# for p in passwords:
|
||||
# if is_strong_password(p):
|
||||
# print("密码:{} 安全性高。".format(p))
|
||||
# else:
|
||||
# print("密码:{} 安全性弱, 建议更换密码。".format(p))
|
||||
@@ -18,7 +18,7 @@ import os,sys,re,public
|
||||
_title = 'SSH user login notification'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Check whether SSH user login notification is enabled" # 描述
|
||||
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-08-05' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_login_message.pl")
|
||||
_tips = [
|
||||
@@ -28,6 +28,12 @@ _tips = [
|
||||
_help = ''
|
||||
|
||||
|
||||
def return_bashrc():
|
||||
if os.path.exists('/root/.bashrc'):return '/root/.bashrc'
|
||||
if os.path.exists('/etc/bashrc'):return '/etc/bashrc'
|
||||
if os.path.exists('/etc/bash.bashrc'):return '/etc/bash.bashrc'
|
||||
return '/root/.bashrc'
|
||||
|
||||
def check_run():
|
||||
'''
|
||||
@name 开始检测
|
||||
@@ -35,9 +41,9 @@ def check_run():
|
||||
@return tuple (status<bool>,msg<string>)
|
||||
'''
|
||||
|
||||
data = public.ReadFile('/etc/bashrc')
|
||||
data = public.ReadFile(return_bashrc())
|
||||
if not data: return True,'Risk-free'
|
||||
if re.search('python /www/server/panel/class/ssh_security.py login', data):
|
||||
if re.search('ssh_security.py login', data):
|
||||
return True,'Risk-free'
|
||||
else:
|
||||
return False,'SSH user login notification is not configured, so it is impossible to know whether the server has been illegally logged in in the first place'
|
||||
@@ -18,7 +18,7 @@ import os,sys,re,public
|
||||
_title = 'Risk User'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Detect if there is a risk user in the system user list" # 描述
|
||||
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-08-05' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_login_user.pl")
|
||||
_tips = [
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# MySQL端口安全检测
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
import os,sys,re,public
|
||||
import os,sys,re,public,json
|
||||
|
||||
_title = 'MySQL security'
|
||||
_version = 1.0 # 版本
|
||||
@@ -50,9 +50,17 @@ def check_run():
|
||||
return True,'MySQL is not installed'
|
||||
if not public.ExecShell("lsof -i :{}".format(port_tmp[0]))[0]:
|
||||
return True,'MySQL is not installed'
|
||||
result = public.check_port_stat(int(port_tmp[0]),public.GetClientIp())
|
||||
result = public.check_port_stat(int(port_tmp[0]),public.GetLocalIp())
|
||||
if result == 0:
|
||||
return True,'Risk-free'
|
||||
|
||||
return False,'The current MySQL port: {}, which can be accessed by any server, which may cause MySQL to be cracked by brute force, posing security risks'.format(port_tmp[0])
|
||||
|
||||
fail2ban_file = '/www/server/panel/plugin/fail2ban/config.json'
|
||||
if os.path.exists(fail2ban_file):
|
||||
try:
|
||||
fail2ban_config = json.loads(public.readFile(fail2ban_file))
|
||||
if 'mysql' in fail2ban_config.keys():
|
||||
if fail2ban_config['mysql']['act'] == 'true':
|
||||
return True,'Fail2ban is enabled'
|
||||
except: pass
|
||||
|
||||
return False,'当前MySQL端口: {},可被任意服务器访问,这可能导致MySQL被暴力破解,存在安全隐患'.format(port_tmp[0])
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: linxiao
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 数据库备份权限检测
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
import os, re, public, panelMysql
|
||||
|
||||
_title = 'Database backup permission detection'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Check whether the MySQL root user has database backup permissions" # 描述
|
||||
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-09-19' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_database_priv.pl")
|
||||
_tips = [
|
||||
"To temporarily access the database without authorization, it is recommended to restore all permissions of the root user.",
|
||||
]
|
||||
|
||||
_help = ''
|
||||
|
||||
|
||||
def check_run():
|
||||
"""检测root用户是否具备数据库备份权限
|
||||
|
||||
@author linxiao<2020-9-18>
|
||||
@return (bool, msg)
|
||||
"""
|
||||
mycnf_file = '/etc/my.cnf'
|
||||
if not os.path.exists(mycnf_file):
|
||||
return True, 'Risk-free'
|
||||
mycnf = public.readFile(mycnf_file)
|
||||
port_tmp = re.findall(r"port\s*=\s*(\d+)", mycnf)
|
||||
if not port_tmp:
|
||||
return True, 'Risk-free'
|
||||
if not public.ExecShell("lsof -i :{}".format(port_tmp[0]))[0]:
|
||||
return True, 'Risk-free'
|
||||
|
||||
base_backup_privs = ["Lock_tables_priv", "Select_priv"]
|
||||
select_sql = "Select {} FROM mysql.user WHERE user='root' and " \
|
||||
"host=SUBSTRING_INDEX((select current_user()),'@', " \
|
||||
"-1);".format(",".join(base_backup_privs))
|
||||
select_result = panelMysql.panelMysql().query(select_sql)
|
||||
if not select_result:
|
||||
return False, "The root user has insufficient authority to execute mysqldump backup."
|
||||
select_result = select_result[0]
|
||||
for priv in select_result:
|
||||
if priv.lower() != "y":
|
||||
return False, "The root user has insufficient authority to execute mysqldump backup."
|
||||
return True, 'Risk-free'
|
||||
@@ -17,7 +17,7 @@ import os,sys,re,public
|
||||
_title = 'Panel password'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Check whether the panel account password is safe" # 描述
|
||||
_level = 3 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-08-04' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_panel_pass.pl")
|
||||
_tips = [
|
||||
@@ -44,6 +44,7 @@ def check_run():
|
||||
return False,'The default password of the panel has not been modified, and there is a security risk'
|
||||
|
||||
lower_pass_txt = '''12123
|
||||
china
|
||||
test
|
||||
test12
|
||||
test11
|
||||
@@ -1097,6 +1098,8 @@ winner
|
||||
p1 = password_salt(public.md5(lp),uid=1)
|
||||
if p1 == find['password']:
|
||||
return False,'The current panel password is too simple and there is a security risk'
|
||||
if not is_strong_password(find["password"]):
|
||||
return False, 'The current panel password is too simple and there is a security risk'
|
||||
return True,'Risk-free'
|
||||
|
||||
salt = None
|
||||
@@ -1113,5 +1116,41 @@ def password_salt(password,username=None,uid=None):
|
||||
global salt
|
||||
if not salt:
|
||||
salt = public.M('users').where('id=?',(uid,)).getField('salt')
|
||||
if salt:
|
||||
salt = salt[0]
|
||||
else:
|
||||
salt = ""
|
||||
return public.md5(public.md5(password+'_bt.cn')+salt)
|
||||
|
||||
|
||||
|
||||
def is_strong_password(password):
|
||||
"""判断密码复杂度是否安全
|
||||
|
||||
非弱口令标准:长度大于等于7,分别包含数字、小写、大写、特殊字符。
|
||||
@password: 密码文本
|
||||
@return: True/False
|
||||
@author: linxiao<2020-9-19>
|
||||
"""
|
||||
|
||||
if len(password) < 7:
|
||||
return False
|
||||
|
||||
import re
|
||||
digit_reg = "[0-9]" # 匹配数字 +1
|
||||
lower_case_letters_reg = "[a-z]" # 匹配小写字母 +1
|
||||
upper_case_letters_reg = "[A-Z]" # 匹配大写字母 +1
|
||||
special_characters_reg = r"((?=[\x21-\x7e]+)[^A-Za-z0-9])" # 匹配特殊字符 +1
|
||||
|
||||
regs = [digit_reg,
|
||||
lower_case_letters_reg,
|
||||
upper_case_letters_reg,
|
||||
special_characters_reg]
|
||||
|
||||
grade = 0
|
||||
for reg in regs:
|
||||
if re.search(reg, password):
|
||||
grade += 1
|
||||
|
||||
if grade == 4 or (grade == 3 and len(password) >= 9):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -18,7 +18,7 @@ import os,sys,re,public
|
||||
_title = 'ICMP detection'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Check whether ICMP access is allowed (Block ICMP)" # 描述
|
||||
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_level = 0 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-08-05' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_ping.pl")
|
||||
_tips = [
|
||||
|
||||
+33
-1046
File diff suppressed because it is too large
Load Diff
@@ -13,12 +13,12 @@
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
|
||||
import os,sys,re,public
|
||||
import os,sys,re,public,json
|
||||
|
||||
_title = 'SSH security'
|
||||
_version = 1.0 # 版本
|
||||
_ps = "Check whether the SSH port of the current server is safe" # 描述
|
||||
_level = 2 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_level = 1 # 风险级别: 1.提示(低) 2.警告(中) 3.危险(高)
|
||||
_date = '2020-08-04' # 最后更新时间
|
||||
_ignore = os.path.exists("data/warning/ignore/sw_ssh_port.pl")
|
||||
_tips = [
|
||||
@@ -72,7 +72,16 @@ def check_run():
|
||||
status = public.ExecShell("systemctl status sshd.service | grep 'dead'|grep -v grep")
|
||||
else:
|
||||
status = public.ExecShell("/etc/init.d/sshd status | grep -e 'stopped' -e '已停'|grep -v grep")
|
||||
|
||||
|
||||
fail2ban_file = '/www/server/panel/plugin/fail2ban/config.json'
|
||||
if os.path.exists(fail2ban_file):
|
||||
try:
|
||||
fail2ban_config = json.loads(public.readFile(fail2ban_file))
|
||||
if 'sshd' in fail2ban_config.keys():
|
||||
if fail2ban_config['sshd']['act'] == 'true':
|
||||
return True,'Fail2ban is enable'
|
||||
except: pass
|
||||
|
||||
if len(status[0]) > 3:
|
||||
status = False
|
||||
else:
|
||||
@@ -83,7 +92,7 @@ def check_run():
|
||||
if port != '22':
|
||||
return True,'The default SSH port has been modified'
|
||||
|
||||
result = public.check_port_stat(int(port),public.GetClientIp())
|
||||
result = public.check_port_stat(int(port),public.GetLocalIp())
|
||||
if result == 0:
|
||||
return True,'Rick-free'
|
||||
|
||||
|
||||
+17
-5
@@ -123,17 +123,22 @@ class send_mail:
|
||||
ret = True
|
||||
if not 'port' in self.__qq_mail_user: self.__qq_mail_user['port'] = 465
|
||||
try:
|
||||
|
||||
msg = MIMEText(body, 'html', 'utf-8')
|
||||
msg['From'] = formataddr([self.__qq_mail_user['qq_mail'], self.__qq_mail_user['qq_mail']])
|
||||
msg['To'] = formataddr([self.__qq_mail_user['qq_mail'], email.strip()])
|
||||
if type(email)==str:
|
||||
msg['To'] = formataddr([self.__qq_mail_user['qq_mail'], email.strip()])
|
||||
elif type(email)==list:
|
||||
msg['To']=formataddr(email)
|
||||
msg['Subject'] = title
|
||||
if int(self.__qq_mail_user['port']) == 465:
|
||||
server = smtplib.SMTP_SSL(str(self.__qq_mail_user['hosts']), str(self.__qq_mail_user['port']))
|
||||
else:
|
||||
server = smtplib.SMTP(str(self.__qq_mail_user['hosts']), str(self.__qq_mail_user['port']))
|
||||
server.login(self.__qq_mail_user['qq_mail'], self.__qq_mail_user['qq_stmp_pwd'])
|
||||
server.sendmail(self.__qq_mail_user['qq_mail'], [email.strip(), ], msg.as_string())
|
||||
if type(email)==str:
|
||||
server.sendmail(self.__qq_mail_user['qq_mail'], [email.strip()], msg.as_string())
|
||||
elif type(email)==list:
|
||||
server.sendmail(self.__qq_mail_user['qq_mail'], email, msg.as_string())
|
||||
server.quit()
|
||||
except Exception:
|
||||
ret = False
|
||||
@@ -166,11 +171,18 @@ class send_mail:
|
||||
filename = '/www/server/panel/data/iplist.txt'
|
||||
ipaddress = public.readFile(filename)
|
||||
if not ipaddress:
|
||||
import urllib2
|
||||
try:
|
||||
import urllib2
|
||||
except:
|
||||
import urllib as urllib2
|
||||
urllib2 = urllib2.request
|
||||
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
|
||||
opener = urllib2.urlopen(url)
|
||||
m_str = opener.read()
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', m_str).group(0)
|
||||
if isinstance(m_str, bytes):
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', m_str.decode('utf-8')).group(0)
|
||||
else:
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', m_str).group(0)
|
||||
public.WriteFile(filename, ipaddress)
|
||||
c_ip = public.check_ip(ipaddress)
|
||||
if not c_ip:
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
# coding: utf-8
|
||||
# +-------------------------------------------------------------------
|
||||
# | 宝塔Linux面板 x3
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2017 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: lkq <1249648969@qq.com>
|
||||
# +-------------------------------------------------------------------
|
||||
# +--------------------------------------------------------------------
|
||||
# | 告警消息队列
|
||||
# +--------------------------------------------------------------------
|
||||
import public,send_mail
|
||||
import time,os,sys,json
|
||||
class send_to_user:
|
||||
'''
|
||||
建立数据库
|
||||
'''
|
||||
def __init__(self):
|
||||
self.mail = send_mail.send_mail()
|
||||
if not public.M('sqlite_master').where('type=? AND name=?', ('table', 'send_settings')).count():
|
||||
public.M('').execute('''CREATE TABLE "send_settings" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,"name" TEXT,"type" TEXT,"path" TEXT,"send_type" TEXT,"last_time" TEXT ,"time_frame" TEXT,"inser_time" TEXT DEFAULT'');''')
|
||||
if not public.M('sqlite_master').where('type=? AND name=?', ('table', 'send_msg')).count():
|
||||
public.M('').execute('''CREATE TABLE "send_msg" ("id" INTEGER PRIMARY KEY AUTOINCREMENT,"name" TEXT,"send_type" TEXT,"msg" TEXT,"is_send" TEXT,"type" TEXT,"inser_time" TEXT DEFAULT '');''')
|
||||
|
||||
'''设置表插入数据'''
|
||||
def insert_settings(self,name,type,path,send_type,time_frame=180):
|
||||
inser_time = self.dtchg(int(time.time()))
|
||||
last_time=int(time.time())
|
||||
if public.M('send_settings').where('name=?',(name,)).count(): return False
|
||||
data={"name":name,"type":type,"path":path,"send_type":send_type,"time_frame":time_frame,"inser_time":inser_time,"last_time":last_time}
|
||||
return public.M('send_settings').insert(data)
|
||||
|
||||
'''数据库插入'''
|
||||
def inser_send_msg(self,name,send_type,msg,type,inser_time):
|
||||
inser_time=self.dtchg(inser_time)
|
||||
if not inser_time:return False
|
||||
if public.M('send_msg').where('name=? and send_type=? and type=? and inser_time=?',(name,send_type,type,inser_time)).count():return False
|
||||
data={"name":name,"send_type":send_type,"msg":msg,"is_send":False,"type":type,"inser_time":inser_time}
|
||||
return public.M('send_msg').insert(data)
|
||||
|
||||
def dtchg(self,x):
|
||||
try:
|
||||
time_local = time.localtime(float(x))
|
||||
dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
|
||||
return dt
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_ip(self):
|
||||
if os.path.exists('/www/server/panel/data/iplist.txt'):
|
||||
data=public.ReadFile('/www/server/panel/data/iplist.txt')
|
||||
return data.strip()
|
||||
else:return '127.0.0.1'
|
||||
|
||||
def get_safe_logs(self, path,p=1,num=11):
|
||||
try:
|
||||
import cgi
|
||||
pythonV = sys.version_info[0]
|
||||
if not os.path.exists(path): return '111';
|
||||
start_line = (p - 1) * num
|
||||
count = start_line + num
|
||||
fp = open(path, 'rb')
|
||||
buf = ""
|
||||
try:
|
||||
fp.seek(-1, 2)
|
||||
except:
|
||||
return []
|
||||
if fp.read(1) == "\n": fp.seek(-1, 2)
|
||||
data = []
|
||||
b = True
|
||||
n = 0
|
||||
for i in range(count):
|
||||
while True:
|
||||
newline_pos = str.rfind(buf, "\n")
|
||||
pos = fp.tell()
|
||||
if newline_pos != -1:
|
||||
if n >= start_line:
|
||||
line = buf[newline_pos + 1:]
|
||||
try:
|
||||
tmp_data = json.loads(cgi.escape(line))
|
||||
data.append(tmp_data)
|
||||
except:
|
||||
pass
|
||||
buf = buf[:newline_pos]
|
||||
n += 1
|
||||
break
|
||||
else:
|
||||
if pos == 0:
|
||||
b = False
|
||||
break
|
||||
to_read = min(4096, pos)
|
||||
fp.seek(-to_read, 1)
|
||||
t_buf = fp.read(to_read)
|
||||
if pythonV == 3: t_buf = t_buf.decode('utf-8')
|
||||
buf = t_buf + buf
|
||||
fp.seek(-to_read, 1)
|
||||
if pos - to_read == 0:
|
||||
buf = "\n" + buf
|
||||
if not b: break;
|
||||
fp.close()
|
||||
except:
|
||||
data = []
|
||||
return data
|
||||
|
||||
'''
|
||||
读取数据库中的值、写入到数据库中
|
||||
'''
|
||||
def read_thread(self):
|
||||
if not public.M('send_settings').count():return False
|
||||
send_data=public.M('send_settings').field('id,name,type,path,send_type,inser_time,last_time,time_frame').select()
|
||||
print(send_data)
|
||||
for i in send_data:
|
||||
if (int(time.time())-int(i['last_time']))<int(i['time_frame']):continue
|
||||
if i['type']=='json':
|
||||
if os.path.exists(i['path']):
|
||||
read_file=self.get_safe_logs(i['path'],p=1,num=100)
|
||||
if not read_file:continue
|
||||
if not read_file[0]:continue
|
||||
for i2 in read_file:
|
||||
self.inser_send_msg(i['name'],i['send_type'],self.get_ip()+'服务器存在问题-->'+i2[1]+',触发告警时间:'+self.dtchg(int(time.time())),'json',i2[0])
|
||||
public.writeFile(i['path'], '')
|
||||
public.M('send_settings').where("id=?", (i['id'],)).update({"last_time": int(time.time())})
|
||||
continue
|
||||
if i['type']=='file':
|
||||
if os.path.exists(i['path']):
|
||||
self.inser_send_msg(i['name'], i['send_type'], '堡塔'+i['name']+'提醒您服务器'+self.get_ip()+'存在异常,详情请登陆面板查看'+i['name']+',触发告警时间:'+self.dtchg(int(time.time())), 'file', int(time.time()))
|
||||
public.M('send_settings').where("id=?", (i['id'],)).update({"last_time": int(time.time())})
|
||||
os.system('rm -rf %s'%i['path'])
|
||||
if os.path.exists(i['path']):os.system('rm -rf %s'%i['path'])
|
||||
else:
|
||||
continue
|
||||
def send(self,title,body):
|
||||
tongdao = self.mail.get_settings()
|
||||
return self.mail.qq_smtp_send(tongdao['user_mail']['mail_list'], title=title, body=body)
|
||||
def send_dingding(self,count):
|
||||
return self.mail.dingding_send(count)
|
||||
|
||||
def __write_log(self,name, msg):
|
||||
public.WriteLog(name+'告警', msg)
|
||||
|
||||
'''发送消息线程'''
|
||||
def send_msg(self):
|
||||
if not public.M('send_msg').count(): return False
|
||||
send_msg=public.M('send_msg').where("is_send=?",(False,)).field('id,name,send_type,msg,is_send,type,inser_time').select()
|
||||
count=1
|
||||
for i in send_msg:
|
||||
if count>=4:break
|
||||
settings=self.mail.get_settings()
|
||||
if i['send_type']=='mail':
|
||||
if not settings['user_mail']['user_name']:continue
|
||||
if i['name']=='Nginx防火墙' or i['name'] == 'Apache防火墙':
|
||||
if self.send(i['name'] + '提醒您' + self.get_ip() + '服务器正在遭受攻击', i['msg']):
|
||||
self.__write_log(i['name'], i['msg'])
|
||||
public.M('send_msg').where("id=?", (i['id'],)).update({"is_send": True})
|
||||
else:
|
||||
if self.send(i['name']+'提醒您'+self.get_ip()+'服务器存在风险', i['msg']):
|
||||
self.__write_log(i['name'],i['msg'])
|
||||
public.M('send_msg').where("id=?", (i['id'],)).update({"is_send":True})
|
||||
if i['send_type']=='dingding':
|
||||
if not settings['dingding']['dingding']: continue
|
||||
if i['name'] == 'Nginx防火墙' or i['name'] == 'Apache防火墙':
|
||||
if self.send(i['name'] + '提醒您' + self.get_ip() + '服务器正在遭受攻击', i['msg']):
|
||||
self.__write_log(i['name'], i['msg'])
|
||||
public.M('send_msg').where("id=?", (i['id'],)).update({"is_send": True})
|
||||
else:
|
||||
if self.send_dingding(i['msg']):
|
||||
self.__write_log(i['name'], i['msg'])
|
||||
public.M('send_msg').where("id=?", (i['id'],)).update({"is_send": True})
|
||||
count += 1
|
||||
public.M('send_msg').where("is_send=?", (True,)).delete()
|
||||
|
||||
def main(self):
|
||||
try:
|
||||
self.read_thread()
|
||||
self.send_msg()
|
||||
except:
|
||||
pass
|
||||
|
||||
+16
-8
@@ -84,18 +84,26 @@ class setPanelLets:
|
||||
pssl = panelSSL.panelSSL()
|
||||
gcl = pssl.GetCertList(get)
|
||||
for i in gcl:
|
||||
if get.domain in i.values():
|
||||
time_array = time.strptime(i['notAfter'],"%Y-%m-%d")
|
||||
time_stamp = int(time.mktime(time_array))
|
||||
now = time.time()
|
||||
if time_stamp > int(now):
|
||||
return i
|
||||
for v in i.values():
|
||||
if get.domain in v:
|
||||
try:
|
||||
time_stamp = int(i['notAfter'])
|
||||
except:
|
||||
time_array = time.strptime(i['notAfter'],"%Y-%m-%d")
|
||||
time_stamp = int(time.mktime(time_array))
|
||||
now = time.time()
|
||||
if time_stamp > int(now):
|
||||
return i
|
||||
|
||||
# 读取可用站点证书
|
||||
def __read_site_cert(self,domain_cert):
|
||||
key_file = "{path}{domain}/{key}".format(path=self.__vhost_cert_path,domain=domain_cert["subject"],key="privkey.pem")
|
||||
cert_file = "{path}{domain}/{cert}".format(path=self.__vhost_cert_path, domain=domain_cert["subject"],
|
||||
try:
|
||||
key_file = "{path}{domain}/{key}".format(path=self.__vhost_cert_path,domain=domain_cert["subject"],key="privkey.pem")
|
||||
cert_file = "{path}{domain}/{cert}".format(path=self.__vhost_cert_path, domain=domain_cert["subject"],
|
||||
cert="fullchain.pem")
|
||||
except:
|
||||
key_file = "/www/server/panel/{}/privkey.pem".format(domain_cert['save_path'])
|
||||
cert_file = "/www/server/panel/{}/fullchain.pem".format(domain_cert['save_path'])
|
||||
if not os.path.exists(key_file):
|
||||
key_file = "{path}{domain}/{key}".format(path="/www/server/panel/vhost/ssl/",domain=domain_cert["subject"],key="privkey.pem")
|
||||
cert_file = "{path}{domain}/{cert}".format(path="/www/server/panel/vhost/ssl/", domain=domain_cert["subject"],
|
||||
|
||||
+16
-2
@@ -139,6 +139,16 @@ class SiteDirAuth:
|
||||
site_info = public.M('sites').where('id=?', (id,)).field('name,path').find()
|
||||
return {"site_name":site_info["name"],"site_path":site_info["path"]}
|
||||
|
||||
def change_dir_auth_file_nginx_phpver(self,site_name,phpv,auth_name):
|
||||
file_path = "{setup_path}/panel/vhost/nginx/dir_auth/{site_name}/{auth_name}.conf".format(
|
||||
setup_path=self.setup_path,site_name=site_name,auth_name=auth_name)
|
||||
conf = public.readFile(file_path)
|
||||
if not conf:
|
||||
return False
|
||||
rep = "include\s+enable-php-\d+\.conf;"
|
||||
conf = re.sub(rep,'include enable-php-{}.conf;'.format(phpv),conf)
|
||||
public.writeFile(file_path,conf)
|
||||
|
||||
# 设置独立认证文件
|
||||
def set_dir_auth_file(self,site_path,site_name,name,username,site_dir,auth_file):
|
||||
php_ver = self.get_site_php_version(site_name)
|
||||
@@ -277,11 +287,15 @@ class SiteDirAuth:
|
||||
def get_dir_auth(self,get):
|
||||
'''
|
||||
get.id
|
||||
get.sitename
|
||||
:param get:
|
||||
:return:
|
||||
'''
|
||||
site_info = self.get_site_info(get.id)
|
||||
site_name = site_info["site_name"]
|
||||
if not hasattr(get, 'siteName'):
|
||||
site_info = self.get_site_info(get.id)
|
||||
site_name = site_info["site_name"]
|
||||
else:
|
||||
site_name = get.siteName
|
||||
conf = self._read_conf()
|
||||
if site_name in conf:
|
||||
return {site_name:conf[site_name]}
|
||||
|
||||
+68
-9
@@ -99,6 +99,19 @@ class ssh_security:
|
||||
if os.path.exists('/www/server/panel/pyenv'):
|
||||
self.__pyenv = 'btpython'
|
||||
|
||||
def return_python(self):
|
||||
if os.path.exists('/www/server/panel/pyenv/bin/python'):return '/www/server/panel/pyenv/bin/python'
|
||||
if os.path.exists('/usr/bin/python'):return '/usr/bin/python'
|
||||
if os.path.exists('/usr/bin/python3'):return '/usr/bin/python3'
|
||||
return 'python'
|
||||
|
||||
def return_bashrc(self):
|
||||
if os.path.exists('/root/.bashrc'):return '/root/.bashrc'
|
||||
if os.path.exists('/etc/bashrc'):return '/etc/bashrc'
|
||||
if os.path.exists('/etc/bash.bashrc'):return '/etc/bash.bashrc'
|
||||
fd = open('/root/.bashrc', mode="w", encoding="utf-8")
|
||||
fd.close()
|
||||
return '/root/.bashrc'
|
||||
|
||||
def check_files(self):
|
||||
try:
|
||||
@@ -230,7 +243,7 @@ class ssh_security:
|
||||
|
||||
#获取ROOT当前登陆的IP
|
||||
def get_ip(self):
|
||||
data = public.ExecShell(''' echo $SSH_CLIENT |awk ' { print $1 }' ''')
|
||||
data = public.ExecShell(''' who am i |awk ' {print $5 }' ''')
|
||||
data = re.findall("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",data[0])
|
||||
return data
|
||||
|
||||
@@ -278,24 +291,27 @@ class ssh_security:
|
||||
|
||||
#开启监控
|
||||
def start_jian(self,get):
|
||||
data=public.ReadFile('/etc/bashrc')
|
||||
data=public.ReadFile(self.return_bashrc())
|
||||
if not re.search('{}\/www\/server\/panel\/class\/ssh_security.py'.format(".*python\s+"),data):
|
||||
public.WriteFile('/etc/bashrc',data.strip()+'\n{} /www/server/panel/class/ssh_security.py login\n'.format(self.__pyenv))
|
||||
public.WriteFile(self.return_bashrc(),data.strip()+'\n'+self.return_python()+ ' /www/server/panel/class/ssh_security.py login\n')
|
||||
return public.returnMsg(True, 'Open successfully')
|
||||
return public.returnMsg(False, 'Open failed')
|
||||
|
||||
#关闭监控
|
||||
def stop_jian(self,get):
|
||||
data = public.ReadFile('/etc/bashrc')
|
||||
if re.search('{}\/www\/server\/panel\/class\/ssh_security.py'.format(".*python\s+"), data):
|
||||
public.WriteFile('/etc/bashrc',data.replace('python /www/server/panel/class/ssh_security.py login',''))
|
||||
data = public.ReadFile(self.return_bashrc())
|
||||
if re.search(self.return_python()+' /www/server/panel/class/ssh_security.py', data):
|
||||
public.WriteFile(self.return_bashrc(),data.replace(self.return_python()+' /www/server/panel/class/ssh_security.py login',''))
|
||||
if os.path.exists('/etc/bashrc'):
|
||||
if re.search('python /www/server/panel/class/ssh_security.py', data):
|
||||
public.WriteFile(self.return_bashrc(),data.replace(self.return_python()+' /www/server/panel/class/ssh_security.py login',''))
|
||||
return public.returnMsg(True, 'Closed successfully')
|
||||
else:
|
||||
return public.returnMsg(True, 'Closed successfully')
|
||||
|
||||
#监控状态
|
||||
def get_jian(self,get):
|
||||
data = public.ReadFile('/etc/bashrc')
|
||||
data = public.ReadFile(self.return_bashrc())
|
||||
if re.search('{}\/www\/server\/panel\/class\/ssh_security.py\s+login'.format(".*python\s+"), data):
|
||||
return public.returnMsg(True, '1')
|
||||
else:
|
||||
@@ -362,8 +378,8 @@ class ssh_security:
|
||||
rec = '\n#?RSAAuthentication\s\w+'
|
||||
rec2 = '\n#?PubkeyAuthentication\s\w+'
|
||||
file = public.readFile(self.__SSH_CONFIG)
|
||||
file_ssh = re.sub(rec, '\n#RSAAuthentication no', file)
|
||||
file_result = re.sub(rec2, '\n#PubkeyAuthentication no', file_ssh)
|
||||
file_ssh = re.sub(rec, '\nRSAAuthentication no', file)
|
||||
file_result = re.sub(rec2, '\nPubkeyAuthentication no', file_ssh)
|
||||
self.wirte(self.__SSH_CONFIG, file_result)
|
||||
self.set_password(get)
|
||||
self.restart_ssh()
|
||||
@@ -379,6 +395,9 @@ class ssh_security:
|
||||
rec = '\n#?RSAAuthentication\s\w+'
|
||||
pubkey = '\n#?PubkeyAuthentication\s\w+'
|
||||
ssh_password = '\nPasswordAuthentication\s\w+'
|
||||
#是否运行root登录
|
||||
root_is_login='\n#?PermitRootLogin\s\w+'
|
||||
|
||||
ret = re.findall(ssh_password, file)
|
||||
if not ret:
|
||||
result['password'] = 'no'
|
||||
@@ -403,8 +422,48 @@ class ssh_security:
|
||||
result['rsa_auth'] = 'no'
|
||||
else:
|
||||
result['rsa_auth'] = 'yes'
|
||||
|
||||
is_root=re.findall(root_is_login, file)
|
||||
if not is_root:
|
||||
result['root_is_login'] = 'no'
|
||||
else:
|
||||
if is_root[-1].split()[-1] == 'no':
|
||||
result['root_is_login'] = 'no'
|
||||
else:
|
||||
result['root_is_login'] = 'yes'
|
||||
return result
|
||||
|
||||
|
||||
def set_root(self, get):
|
||||
'''
|
||||
开启密码登陆
|
||||
get: 无需传递参数
|
||||
'''
|
||||
ssh_password = '\n#?PermitRootLogin\s\w+'
|
||||
file = public.readFile(self.__SSH_CONFIG)
|
||||
if len(re.findall(ssh_password, file)) == 0:
|
||||
file_result = file + '\nPermitRootLogin yes'
|
||||
else:
|
||||
file_result = re.sub(ssh_password, '\nPermitRootLogin yes', file)
|
||||
self.wirte(self.__SSH_CONFIG, file_result)
|
||||
self.restart_ssh()
|
||||
return public.returnMsg(True, 'Successfully opened')
|
||||
|
||||
def stop_root(self, get):
|
||||
'''
|
||||
开启密码登陆
|
||||
get: 无需传递参数
|
||||
'''
|
||||
ssh_password = '\n#?PermitRootLogin\s\w+'
|
||||
file = public.readFile(self.__SSH_CONFIG)
|
||||
if len(re.findall(ssh_password, file)) == 0:
|
||||
file_result = file + '\nPermitRootLogin no'
|
||||
else:
|
||||
file_result = re.sub(ssh_password, '\nPermitRootLogin no', file)
|
||||
self.wirte(self.__SSH_CONFIG, file_result)
|
||||
self.restart_ssh()
|
||||
return public.returnMsg(True, 'Closed successfully')
|
||||
|
||||
def stop_password(self, get):
|
||||
'''
|
||||
关闭密码访问
|
||||
|
||||
@@ -94,7 +94,6 @@ class ssh_terminal:
|
||||
|
||||
try:
|
||||
self._tp.start_client()
|
||||
self.debug(self._pkey)
|
||||
if not self._pass and not self._pkey:
|
||||
self.set_sshd_config(True)
|
||||
return public.returnMsg(False,'SSH_LOGIN_INFO_ERR',(self._host,str(self._port)))
|
||||
@@ -449,7 +448,7 @@ class ssh_terminal:
|
||||
resp_line = self._ssh.recv(1024)
|
||||
if not resp_line:
|
||||
if not self._tp.is_active():
|
||||
self.debug('SSH_LOGIN_ERR14')
|
||||
self.debug(public.getMsg('SSH_LOGIN_ERR14'))
|
||||
self._ws.send(public.getMsg('RECONNECT_SSH'))
|
||||
self.close()
|
||||
return
|
||||
@@ -480,7 +479,7 @@ class ssh_terminal:
|
||||
self.debug(public.getMsg('SSH_LOGIN_ERR15',(str(e),)))
|
||||
|
||||
if self._ws.closed:
|
||||
self.debug('SSH_LOGIN_INFO1')
|
||||
self.debug(public.getMsg('SSH_LOGIN_INFO1'))
|
||||
self.close()
|
||||
|
||||
def send(self):
|
||||
@@ -513,7 +512,7 @@ class ssh_terminal:
|
||||
self.debug(public.getMsg('SSH_LOGIN_ERR17',(str(ex),)))
|
||||
|
||||
if self._ws.closed:
|
||||
self.debug('SSH_LOGIN_INFO1')
|
||||
self.debug(public.getMsg('SSH_LOGIN_INFO1'))
|
||||
self.close()
|
||||
|
||||
|
||||
|
||||
+114
-24
@@ -25,7 +25,6 @@ class system:
|
||||
session['config'] = public.M('config').where("id=?",('1',)).field('webserver,sites_path,backup_path,status,mysql_root').find()
|
||||
if not 'email' in session['config']:
|
||||
session['config']['email'] = public.M('users').where("id=?",('1',)).getField('email')
|
||||
data = {}
|
||||
data = session['config']
|
||||
data['webserver'] = public.get_webserver()
|
||||
#PHP版本
|
||||
@@ -100,7 +99,7 @@ class system:
|
||||
elif os.path.exists('/usr/local/lsws/bin/lswsctrl'):
|
||||
data['webserver'] = 'openlitespeed'
|
||||
serviceName = 'openlitespeed'
|
||||
tmp['setup'] = os.path.exists(self.setupPath +'/apache/bin/httpd')
|
||||
tmp['setup'] = os.path.exists('/usr/local/lsws/bin/lswsctrl')
|
||||
configFile = '/usr/local/lsws/bin/lswsctrl'
|
||||
try:
|
||||
if os.path.exists(configFile):
|
||||
@@ -234,18 +233,18 @@ class system:
|
||||
|
||||
def GetSystemTotal(self,get,interval = 1):
|
||||
#取系统统计信息
|
||||
data = self.GetMemInfo();
|
||||
cpu = self.GetCpuInfo(interval);
|
||||
data['cpuNum'] = cpu[1];
|
||||
data['cpuRealUsed'] = cpu[0];
|
||||
data['time'] = self.GetBootTime();
|
||||
data['system'] = self.GetSystemVersion();
|
||||
data['isuser'] = public.M('users').where('username=?',('admin',)).count();
|
||||
data = self.GetMemInfo()
|
||||
cpu = self.GetCpuInfo(interval)
|
||||
data['cpuNum'] = cpu[1]
|
||||
data['cpuRealUsed'] = cpu[0]
|
||||
data['time'] = self.GetBootTime()
|
||||
data['system'] = self.GetSystemVersion()
|
||||
data['isuser'] = public.M('users').where('username=?',('admin',)).count()
|
||||
try:
|
||||
data['isport'] = public.GetHost(True) == '8888'
|
||||
except:data['isport'] = False
|
||||
|
||||
data['version'] = session['version'];
|
||||
data['version'] = session['version']
|
||||
return data
|
||||
|
||||
def GetLoadAverage(self,get):
|
||||
@@ -253,14 +252,14 @@ class system:
|
||||
c = os.getloadavg()
|
||||
except:
|
||||
c = [0,0,0]
|
||||
data = {};
|
||||
data['one'] = float(c[0]);
|
||||
data['five'] = float(c[1]);
|
||||
data['fifteen'] = float(c[2]);
|
||||
data['max'] = psutil.cpu_count() * 2;
|
||||
data['limit'] = data['max'];
|
||||
data['safe'] = data['max'] * 0.75;
|
||||
return data;
|
||||
data = {}
|
||||
data['one'] = float(c[0])
|
||||
data['five'] = float(c[1])
|
||||
data['fifteen'] = float(c[2])
|
||||
data['max'] = psutil.cpu_count() * 2
|
||||
data['limit'] = data['max']
|
||||
data['safe'] = data['max'] * 0.75
|
||||
return data
|
||||
|
||||
def GetAllInfo(self,get):
|
||||
data = {}
|
||||
@@ -306,7 +305,7 @@ class system:
|
||||
days = math.floor(hours / 24)
|
||||
hours = math.floor(hours - (days * 24))
|
||||
min = math.floor(min - (days * 60 * 24) - (hours * 60))
|
||||
sys_time = "{} Days".format(int(days))
|
||||
sys_time = "{} Day(s)".format(int(days))
|
||||
cache.set(key,sys_time,1800)
|
||||
return sys_time
|
||||
#return public.getMsg('SYS_BOOT_TIME',(str(int(days)),str(int(hours)),str(int(min))))
|
||||
@@ -328,6 +327,7 @@ class system:
|
||||
|
||||
used_all = psutil.cpu_percent(percpu=True)
|
||||
cpu_name = public.getCpuType() + " * {}".format(cpuW)
|
||||
|
||||
return used,cpuCount,used_all,cpu_name,cpuNum,cpuW
|
||||
|
||||
def get_cpu_percent_thead(self,interval):
|
||||
@@ -408,7 +408,7 @@ class system:
|
||||
n += 1
|
||||
try:
|
||||
inodes = tempInodes1[n-1].split()
|
||||
disk = re.findall(r"^(.+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\d%]{2,4})\s+(/.{0,50})$",tmp.strip())
|
||||
disk = re.findall(r"^(.+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\d%]{2,4})\s+(/.{0,100})$",tmp.strip())
|
||||
if disk: disk = disk[0]
|
||||
if len(disk) < 6: continue
|
||||
if disk[2].find('M') != -1: continue
|
||||
@@ -420,7 +420,7 @@ class system:
|
||||
arr = {}
|
||||
arr['filesystem'] = disk[0].strip()
|
||||
arr['type'] = disk[1].strip()
|
||||
arr['path'] = disk[6]
|
||||
arr['path'] = disk[6].replace('/usr/local/lighthouse/softwares/btpanel','/www')
|
||||
tmp1 = [disk[2],disk[3],disk[4],disk[5]]
|
||||
arr['size'] = tmp1
|
||||
arr['inodes'] = [inodes[1],inodes[2],inodes[3],inodes[4]]
|
||||
@@ -431,6 +431,63 @@ class system:
|
||||
cache.set(key,diskInfo,360)
|
||||
return diskInfo
|
||||
|
||||
|
||||
# 获取磁盘IO开销数据
|
||||
def get_disk_iostat(self):
|
||||
iokey = 'iostat'
|
||||
diskio = cache.get(iokey)
|
||||
mtime = int(time.time())
|
||||
if not diskio:
|
||||
diskio = {}
|
||||
diskio['info'] = None
|
||||
diskio['time'] = mtime
|
||||
diskio_1 = diskio['info']
|
||||
stime = mtime - diskio['time']
|
||||
if not stime: stime = 1
|
||||
diskInfo = {}
|
||||
diskInfo['ALL'] = {}
|
||||
diskInfo['ALL']['read_count'] = 0
|
||||
diskInfo['ALL']['write_count'] = 0
|
||||
diskInfo['ALL']['read_bytes'] = 0
|
||||
diskInfo['ALL']['write_bytes'] = 0
|
||||
diskInfo['ALL']['read_time'] = 0
|
||||
diskInfo['ALL']['write_time'] = 0
|
||||
diskInfo['ALL']['read_merged_count'] = 0
|
||||
diskInfo['ALL']['write_merged_count'] = 0
|
||||
try:
|
||||
if os.path.exists('/proc/diskstats'):
|
||||
diskio_2 = psutil.disk_io_counters(perdisk=True)
|
||||
if not diskio_1:
|
||||
diskio_1 = diskio_2
|
||||
for disk_name in diskio_2.keys():
|
||||
diskInfo[disk_name] = {}
|
||||
diskInfo[disk_name]['read_count'] = int((diskio_2[disk_name].read_count - diskio_1[disk_name].read_count) / stime)
|
||||
diskInfo[disk_name]['write_count'] = int((diskio_2[disk_name].write_count - diskio_1[disk_name].write_count) / stime)
|
||||
diskInfo[disk_name]['read_bytes'] = int((diskio_2[disk_name].read_bytes - diskio_1[disk_name].read_bytes) / stime)
|
||||
diskInfo[disk_name]['write_bytes'] = int((diskio_2[disk_name].write_bytes - diskio_1[disk_name].write_bytes) / stime)
|
||||
diskInfo[disk_name]['read_time'] = int((diskio_2[disk_name].read_time - diskio_1[disk_name].read_time) / stime)
|
||||
diskInfo[disk_name]['write_time'] = int((diskio_2[disk_name].write_time - diskio_1[disk_name].write_time) / stime)
|
||||
diskInfo[disk_name]['read_merged_count'] = int((diskio_2[disk_name].read_merged_count - diskio_1[disk_name].read_merged_count) / stime)
|
||||
diskInfo[disk_name]['write_merged_count'] = int((diskio_2[disk_name].write_merged_count - diskio_1[disk_name].write_merged_count) / stime)
|
||||
|
||||
diskInfo['ALL']['read_count'] += diskInfo[disk_name]['read_count']
|
||||
diskInfo['ALL']['write_count'] += diskInfo[disk_name]['write_count']
|
||||
diskInfo['ALL']['read_bytes'] += diskInfo[disk_name]['read_bytes']
|
||||
diskInfo['ALL']['write_bytes'] += diskInfo[disk_name]['write_bytes']
|
||||
if diskInfo['ALL']['read_time'] < diskInfo[disk_name]['read_time']:
|
||||
diskInfo['ALL']['read_time'] = diskInfo[disk_name]['read_time']
|
||||
if diskInfo['ALL']['write_time'] < diskInfo[disk_name]['write_time']:
|
||||
diskInfo['ALL']['write_time'] = diskInfo[disk_name]['write_time']
|
||||
diskInfo['ALL']['read_merged_count'] += diskInfo[disk_name]['read_merged_count']
|
||||
diskInfo['ALL']['write_merged_count'] += diskInfo[disk_name]['write_merged_count']
|
||||
|
||||
cache.set(iokey,{'info':diskio_2,'time':mtime})
|
||||
except:
|
||||
public.writeFile('/tmp/2',str(public.get_error_info()))
|
||||
return diskInfo
|
||||
return diskInfo
|
||||
|
||||
|
||||
#清理系统垃圾
|
||||
def ClearSystem(self,get):
|
||||
count = total = 0
|
||||
@@ -545,6 +602,7 @@ class system:
|
||||
|
||||
if get != False:
|
||||
networkInfo['cpu'] = self.GetCpuInfo(1)
|
||||
networkInfo['cpu_times'] = self.get_cpu_times()
|
||||
networkInfo['load'] = self.GetLoadAverage(get)
|
||||
networkInfo['mem'] = self.GetMemInfo(get)
|
||||
networkInfo['version'] = session['version']
|
||||
@@ -561,9 +619,41 @@ class system:
|
||||
networkInfo['user_info'] = panelSSL.panelSSL().GetUserInfo(None)
|
||||
networkInfo['up'] = round(float(networkInfo['up']),2)
|
||||
networkInfo['down'] = round(float(networkInfo['down']),2)
|
||||
networkInfo['iostat'] = self.get_disk_iostat()
|
||||
|
||||
return networkInfo
|
||||
|
||||
|
||||
|
||||
def get_cpu_times(self):
|
||||
data = {}
|
||||
try:
|
||||
cpu_times_p = psutil.cpu_times_percent()
|
||||
data['user'] = cpu_times_p.user
|
||||
data['nice'] = cpu_times_p.nice
|
||||
data['system'] = cpu_times_p.system
|
||||
data['idle'] = cpu_times_p.idle
|
||||
data['iowait'] = cpu_times_p.iowait
|
||||
data['irq'] = cpu_times_p.irq
|
||||
data['softirq'] = cpu_times_p.softirq
|
||||
data['steal'] = cpu_times_p.steal
|
||||
data['guest'] = cpu_times_p.guest
|
||||
data['guest_nice'] = cpu_times_p.guest_nice
|
||||
data['total_processes'] = 0
|
||||
data['active_processes'] = 0
|
||||
for pid in psutil.pids():
|
||||
try:
|
||||
p = psutil.Process(pid)
|
||||
if p.status() == 'running':
|
||||
data['active_processes'] += 1
|
||||
except:
|
||||
continue
|
||||
data['total_processes'] += 1
|
||||
|
||||
except: pass
|
||||
return data
|
||||
|
||||
|
||||
|
||||
|
||||
def GetNetWorkApi(self,get=None):
|
||||
return self.GetNetWork()
|
||||
@@ -852,9 +942,9 @@ class system:
|
||||
self.ssh.connect('localhost', public.GetSSHPort())
|
||||
except:
|
||||
return False
|
||||
import firewalls,common
|
||||
import firewalls
|
||||
fw = firewalls.firewalls()
|
||||
get = common.dict_obj()
|
||||
get = public.dict_obj()
|
||||
get.status = '0'
|
||||
fw.SetSshStatus(get)
|
||||
self.ssh.connect('127.0.0.1', public.GetSSHPort())
|
||||
|
||||
@@ -45,6 +45,8 @@ class userlogin:
|
||||
num = self.limit_address('+')
|
||||
return public.returnJson(False,'LOGIN_USER_ERR',(str(num),)),json_header
|
||||
_key_file = "/www/server/panel/data/two_step_auth.txt"
|
||||
#登陆告警
|
||||
public.login_send_body("Userinfo",userInfo['username'],public.GetClientIp(),str(request.environ.get('REMOTE_PORT')))
|
||||
if hasattr(post,'vcode'):
|
||||
if self.limit_address('?',v="vcode") < 1: return public.returnJson(False,'You have failed verification many times, forbidden for 10 minutes'),json_header
|
||||
import pyotp
|
||||
@@ -119,6 +121,7 @@ class userlogin:
|
||||
|
||||
def request_temp(self,get):
|
||||
try:
|
||||
if len(get.__dict__.keys()) > 2: return public.getMsg('INIT_ARGS_ERR')
|
||||
if not hasattr(get,'tmp_token'): return public.getMsg('INIT_ARGS_ERR')
|
||||
if len(get.tmp_token) != 48: return public.getMsg('INIT_ARGS_ERR')
|
||||
if not re.match(r"^\w+$",get.tmp_token):return public.getMsg('INIT_ARGS_ERR')
|
||||
@@ -159,6 +162,7 @@ class userlogin:
|
||||
self.set_request_token()
|
||||
self.login_token()
|
||||
self.set_cdn_host(get)
|
||||
public.login_send_body("Temporary authorization",userInfo['username'],public.GetClientIp(),str(request.environ.get('REMOTE_PORT')))
|
||||
return redirect('/')
|
||||
except:
|
||||
return public.getMsg('LOGIN_FAIL')
|
||||
|
||||
+38
-20
@@ -42,6 +42,8 @@ class ScanLogin(object):
|
||||
def login_qrcode(self, get):
|
||||
tid = public.GetRandomString(12)
|
||||
qrcode_str = 'https://app.bt.cn/app.html?&panel_url='+public.getPanelAddr()+'&v=' + public.GetRandomString(3)+'?login&tid=' + tid
|
||||
data = public.get_session_id() + ':' + str(time.time())
|
||||
public.writeFile(self.app_path + "app_login_check.pl", data)
|
||||
cache.set(tid,public.get_session_id(),360)
|
||||
cache.set(public.get_session_id(),tid,360)
|
||||
return public.returnMsg(True, qrcode_str)
|
||||
@@ -75,31 +77,47 @@ class ScanLogin(object):
|
||||
import config
|
||||
config.config().reload_session()
|
||||
public.writeFile(login_type,'True')
|
||||
public.login_send_body("Wechat program",userInfo['username'],public.GetClientIp(),str(request.environ.get('REMOTE_PORT')))
|
||||
return public.returnMsg(True, 'login successful')
|
||||
return public.returnMsg(False, 'Login failed')
|
||||
|
||||
|
||||
#验证APP是否登录成功
|
||||
def check_app_login(self,get):
|
||||
session_id = public.get_session_id()
|
||||
if cache.get(session_id) != 'True':
|
||||
return public.returnMsg(False,'Wait for the app to scan the code and log in')
|
||||
cache.delete(session_id)
|
||||
userInfo = public.M('users').where("id=?",(1,)).field('id,username').find()
|
||||
session['login'] = True
|
||||
session['username'] = userInfo['username']
|
||||
session['tmp_login'] = True
|
||||
public.WriteLog('TYPE_LOGIN','APP scan code login, account: {}, login IP: {}'.format(userInfo['username'],public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT'))))
|
||||
cache.delete('panelNum')
|
||||
cache.delete('dologin')
|
||||
sess_input_path = 'data/session_last.pl'
|
||||
public.writeFile(sess_input_path,str(int(time.time())))
|
||||
login_type = 'data/app_login.pl'
|
||||
self.set_request_token()
|
||||
import config
|
||||
config.config().reload_session()
|
||||
public.writeFile(login_type,'True')
|
||||
return public.returnMsg(True,'login successful!')
|
||||
#判断是否存在绑定
|
||||
btapp_info = json.loads(public.readFile('/www/server/panel/config/api.json'))
|
||||
if not btapp_info:return public.returnMsg(False,'Unbound')
|
||||
if not btapp_info['open']:return public.returnMsg(False,'API not open')
|
||||
if not 'apps' in btapp_info:return public.returnMsg(False,'Unbound phone')
|
||||
if not btapp_info['apps']:return public.returnMsg(False,'Unbound phone')
|
||||
try:
|
||||
session_id=public.get_session_id()
|
||||
if not os.path.exists(self.app_path+'app_login_check.pl'):return public.returnMsg(False,'Wait for the app to scan the code and log in 1')
|
||||
data = public.readFile(self.app_path+'app_login_check.pl')
|
||||
public.ExecShell('rm ' + self.app_path+"app_login_check.pl")
|
||||
secret_key, init_time = data.split(':')
|
||||
if len(session_id)!=64:return public.returnMsg(False,'Wait for the app to scan the code and log in 2')
|
||||
if time.time() - float(init_time) < 180 and session_id != secret_key:
|
||||
return public.returnMsg(False,'Wait for the app to scan the code and log in')
|
||||
cache.delete(session_id)
|
||||
userInfo = public.M('users').where("id=?",(1,)).field('id,username').find()
|
||||
session['login'] = True
|
||||
session['username'] = userInfo['username']
|
||||
session['tmp_login'] = True
|
||||
public.WriteLog('TYPE_LOGIN','APP scan code login, account: {}, login IP: {}'.format(userInfo['username'],public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT'))))
|
||||
cache.delete('panelNum')
|
||||
cache.delete('dologin')
|
||||
sess_input_path = 'data/session_last.pl'
|
||||
public.writeFile(sess_input_path,str(int(time.time())))
|
||||
login_type = 'data/app_login.pl'
|
||||
self.set_request_token()
|
||||
import config
|
||||
config.config().reload_session()
|
||||
public.writeFile(login_type,'True')
|
||||
public.login_send_body("aaPanel Mobile",userInfo['username'],public.GetClientIp(),str(request.environ.get('REMOTE_PORT')))
|
||||
return public.returnMsg(True,'login successful!')
|
||||
except:
|
||||
return public.returnMsg(False, 'login fail')
|
||||
|
||||
class SelfModule():
|
||||
'''
|
||||
@@ -198,7 +216,7 @@ class wxapp(SelfModule, ScanLogin):
|
||||
if type(encryption_str) == str:
|
||||
encryption_str = encryption_str.encode()
|
||||
if get['sgin'] == public.md5(binascii.hexlify(base64.b64encode(encryption_str))):
|
||||
if public.GetClientIp() in ['118.24.150.167', '103.224.251.67', '125.88.182.170', '47.52.194.186', '39.104.53.226','119.147.144.162']:
|
||||
if public.GetClientIp() in ['47.52.194.186']:
|
||||
return True
|
||||
return public.returnMsg(False, 'UNAUTHORIZED')
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"product": "Linux panel", "setup_path": "/www/server", "openlitespeed_path": "/usr/local", "language": "English", "title": "aaPanel Linux panel", "brand": "aaPanel", "root_path": "/www", "template": "default", "logs_path": "/www/wwwlogs", "home": "https://console.aapanel.com", "recycle_bin": true}
|
||||
{"product": "Linux panel", "setup_path": "/www/server", "openlitespeed_path": "/usr/local", "language": "English", "title": "aaPanel Linux panel", "brand": "aaPanel", "root_path": "/www", "template": "default", "logs_path": "/www/wwwlogs", "home": "https://www.aapanel.com", "recycle_bin": true}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
"key": "SAVED_CF_KEY",
|
||||
"name": "API Key"
|
||||
}],
|
||||
"help": "CloudFlare Get in the background Global API Key",
|
||||
"help": "How to get API Token",
|
||||
"name": "CloudFlareDns"
|
||||
},
|
||||
{
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
[ "119.147.144.34", "103.224.251.67","45.76.53.20","120.206.184.160","[2001:19f0:7001:54fc:5400:2ff:fe9b:97f9]", "45.32.116.160", "[240e:ff:9000:1100:0:3:0:34]" ]
|
||||
[ "103.224.251.67","128.1.164.196","45.76.53.20","[2001:19f0:7001:54fc:5400:2ff:fe9b:97f9]", "158.247.208.19"]
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
{
|
||||
"protocol": "http://",
|
||||
"address": "103.224.251.67",
|
||||
"port": "80",
|
||||
"port": "5880",
|
||||
"ping": 500
|
||||
},
|
||||
{
|
||||
|
||||
+3
-1
@@ -4,4 +4,6 @@
|
||||
{"name":"Pure-Ftpd","versions":[{"status":false,"version":"1.0.47"}],"type":"FTP服务器","msg":"PureFTPd是一款专注于程序健壮和软件安全的免费FTP服务器软件","shell":"pure-ftpd.sh","check":"server/pure-ftpd/bin/pure-pw"},
|
||||
{"name":"PHP","versions":[{"status":false,"version":"5.2"},{"status":false,"version":"5.3"},{"status":false,"version":"5.4"},{"status":false,"version":"5.5"},{"status":false,"version":"5.6"},{"status":false,"version":"7.0"},{"status":false,"version":"7.1"},{"status":false,"version":"7.2"},{"status":false,"version":"7.3"},{"status":false,"version":"7.4"},{"status":false,"version":"8.0"}],"type":"语言解释器","msg":"若非必要,请安装更新的版本!","shell":"php.sh","check":"server/php/VERSION/bin/php"},
|
||||
{"name":"Tomcat","versions":[{"status":false,"version":"7"},{"status":false,"version":"8"},{"status":false,"version":"9"}],"type":"语言解释器","msg":"java-ee解释器","shell":"tomcat.sh","check":"server/tomcat/bin/catalina.sh"},
|
||||
{"name":"phpMyAdmin","versions":[{"status":false,"version":"4.0"},{"status":false,"version":"4.4"},{"status":false,"version":"4.7"},{"status":false,"version":"4.8"},{"status":false,"version":"4.9"},{"status":false,"version":"5.0"}],"type":"数据库工具","msg":"Web端MySQL管理工具","shell":"phpmyadmin.sh","check":"server/phpmyadmin/version.pl"}]
|
||||
{"name":"phpMyAdmin","versions":[{"status":false,"version":"4.0"},{"status":false,"version":"4.4"},{"status":false,"version":"4.7"},{"status":false,"version":"4.8"},{"status":false,"version":"4.9"},{"status":false,"version":"5.0"}],"type":"数据库工具","msg":"Web端MySQL管理工具","shell":"phpmyadmin.sh","check":"server/phpmyadmin/version.pl"},
|
||||
{"name":"DNS-Server","versions":[{"status":false,"version":"3"}],"type":"DNS server","msg":"DNS Manager","shell":"dns.sh","check":"server/panel/plugin/dns_manager/dns_manager_main.py"},
|
||||
{"name":"Mail-Server","versions":[{"status":false,"version":"4"}],"type":"Mail Server","msg":"Mail Server","shell":"mail.sh","check":"server/panel/plugin/mail_sys/mail_sys_main.py"}]
|
||||
+2
-2
@@ -5,7 +5,7 @@ export LANG=en_US.UTF-8
|
||||
export LANGUAGE=en_US:en
|
||||
|
||||
get_node_url(){
|
||||
nodes=(http://183.235.223.101:3389 http://125.88.182.172:5880 http://128.1.164.196 http://103.224.251.67 http://download.bt.cn);
|
||||
nodes=(http://183.235.223.101:3389 http://125.88.182.172:5880 http://128.1.164.196 http://103.224.251.67:5880 http://download.bt.cn);
|
||||
i=1;
|
||||
for node in ${nodes[@]};
|
||||
do
|
||||
@@ -78,6 +78,6 @@ else
|
||||
fi
|
||||
GetPackManager
|
||||
if [ ! $NODE_URL ];then
|
||||
echo '正在选择下载节点...';
|
||||
echo 'Selecting download node...';
|
||||
get_node_url
|
||||
fi
|
||||
|
||||
@@ -8,75 +8,86 @@
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# ------------------------------
|
||||
# 计划任务
|
||||
#------------------------------
|
||||
# ------------------------------
|
||||
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
from json import dumps,loads
|
||||
from psutil import Process,pids,cpu_count,cpu_percent,net_io_counters,disk_io_counters,virtual_memory
|
||||
sys.path.insert(0,"/www/server/panel/class/")
|
||||
import db
|
||||
import public
|
||||
from json import dumps, loads
|
||||
from psutil import Process, pids, cpu_count, cpu_percent, net_io_counters, disk_io_counters, virtual_memory
|
||||
os.environ['BT_TASK'] = '1'
|
||||
base_path = "/www/server/panel"
|
||||
sys.path.insert(0, "/www/server/panel/class/")
|
||||
import time
|
||||
import panelTask
|
||||
global pre,timeoutCount,logPath,isTask,oldEdate,isCheck
|
||||
import public
|
||||
import db
|
||||
global pre, timeoutCount, logPath, isTask, oldEdate, isCheck
|
||||
pre = 0
|
||||
timeoutCount = 0
|
||||
isCheck = 0
|
||||
oldEdate = None
|
||||
logPath = '/tmp/panelExec.log'
|
||||
isTask = '/tmp/panelTask.pl'
|
||||
python_bin = None
|
||||
|
||||
def get_python_bin():
|
||||
global python_bin
|
||||
if python_bin: return python_bin
|
||||
bin_file = '/www/server/panel/pyenv/bin/python'
|
||||
bin_file2 = '/usr/bin/python'
|
||||
if os.path.exists(bin_file):
|
||||
python_bin = bin_file
|
||||
return bin_file
|
||||
return '/usr/bin/python'
|
||||
python_bin = bin_file2
|
||||
return bin_file2
|
||||
|
||||
def ReadFile(filename,mode = 'r'):
|
||||
|
||||
def ReadFile(filename, mode='r'):
|
||||
"""
|
||||
读取文件内容
|
||||
@filename 文件名
|
||||
return string(bin) 若文件不存在,则返回None
|
||||
"""
|
||||
if not os.path.exists(filename): return False
|
||||
if not os.path.exists(filename):
|
||||
return False
|
||||
f_body = None
|
||||
with open(filename, mode) as fp:
|
||||
f_body = fp.read()
|
||||
return f_body
|
||||
|
||||
#下载文件
|
||||
def DownloadFile(url,filename):
|
||||
# 下载文件
|
||||
def DownloadFile(url, filename):
|
||||
try:
|
||||
import urllib,socket
|
||||
import urllib
|
||||
import socket
|
||||
socket.setdefaulttimeout(10)
|
||||
urllib.urlretrieve(url,filename=filename ,reporthook= DownloadHook)
|
||||
urllib.urlretrieve(url, filename=filename, reporthook=DownloadHook)
|
||||
os.system('chown www.www ' + filename)
|
||||
WriteLogs('done')
|
||||
except:
|
||||
WriteLogs('done')
|
||||
|
||||
|
||||
|
||||
#下载文件进度回调
|
||||
# 下载文件进度回调
|
||||
def DownloadHook(count, blockSize, totalSize):
|
||||
global pre
|
||||
used = count * blockSize
|
||||
pre1 = int((100.0 * used / totalSize))
|
||||
if pre == pre1:
|
||||
return
|
||||
speed = {'total':totalSize,'used':used,'pre':pre}
|
||||
speed = {'total': totalSize, 'used': used, 'pre': pre}
|
||||
WriteLogs(dumps(speed))
|
||||
pre = pre1
|
||||
|
||||
#写输出日志
|
||||
# 写输出日志
|
||||
|
||||
|
||||
def WriteLogs(logMsg):
|
||||
try:
|
||||
global logPath
|
||||
with open(logPath,'w+') as fp:
|
||||
with open(logPath, 'w+') as fp:
|
||||
fp.write(logMsg)
|
||||
fp.close()
|
||||
except:
|
||||
@@ -90,7 +101,8 @@ def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
import datetime
|
||||
import subprocess
|
||||
import time
|
||||
sub = subprocess.Popen(cmdstring+' &> '+logPath, cwd=cwd, stdin=subprocess.PIPE,shell=shell,bufsize=4096)
|
||||
sub = subprocess.Popen(cmdstring+' &> '+logPath, cwd=cwd,
|
||||
stdin=subprocess.PIPE, shell=shell, bufsize=4096)
|
||||
|
||||
while sub.poll() is None:
|
||||
time.sleep(0.1)
|
||||
@@ -100,7 +112,7 @@ def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
return None
|
||||
|
||||
|
||||
#任务队列
|
||||
# 任务队列
|
||||
def startTask():
|
||||
global isTask
|
||||
try:
|
||||
@@ -108,21 +120,27 @@ def startTask():
|
||||
try:
|
||||
if os.path.exists(isTask):
|
||||
with db.Sql() as sql:
|
||||
sql.table('tasks').where("status=?",('-1',)).setField('status','0')
|
||||
taskArr = sql.table('tasks').where("status=?",('0',)).field('id,type,execstr').order("id asc").select()
|
||||
sql.table('tasks').where(
|
||||
"status=?", ('-1',)).setField('status', '0')
|
||||
taskArr = sql.table('tasks').where("status=?", ('0',)).field(
|
||||
'id,type,execstr').order("id asc").select()
|
||||
for value in taskArr:
|
||||
start = int(time.time())
|
||||
if not sql.table('tasks').where("id=?",(value['id'],)).count(): continue
|
||||
sql.table('tasks').where("id=?",(value['id'],)).save('status,start',('-1',start))
|
||||
if not sql.table('tasks').where("id=?", (value['id'],)).count():
|
||||
continue
|
||||
sql.table('tasks').where("id=?", (value['id'],)).save(
|
||||
'status,start', ('-1', start))
|
||||
if value['type'] == 'download':
|
||||
argv = value['execstr'].split('|bt|')
|
||||
DownloadFile(argv[0],argv[1])
|
||||
DownloadFile(argv[0], argv[1])
|
||||
elif value['type'] == 'execshell':
|
||||
ExecShell(value['execstr'])
|
||||
end = int(time.time())
|
||||
sql.table('tasks').where("id=?",(value['id'],)).save('status,end',('1',end))
|
||||
if(sql.table('tasks').where("status=?",('0')).count() < 1):
|
||||
if os.path.exists(isTask): os.remove(isTask)
|
||||
sql.table('tasks').where("id=?", (value['id'],)).save(
|
||||
'status,end', ('1', end))
|
||||
if(sql.table('tasks').where("status=?", ('0')).count() < 1):
|
||||
if os.path.exists(isTask):
|
||||
os.remove(isTask)
|
||||
#ExecShell('rm -f ' + isTask)
|
||||
sql.close()
|
||||
taskArr = None
|
||||
@@ -131,23 +149,26 @@ def startTask():
|
||||
siteEdate()
|
||||
time.sleep(2)
|
||||
except Exception as ex:
|
||||
logging.debug(ex)
|
||||
logging.info(ex)
|
||||
time.sleep(60)
|
||||
startTask()
|
||||
|
||||
#网站到期处理
|
||||
|
||||
# 网站到期处理
|
||||
|
||||
|
||||
def siteEdate():
|
||||
global oldEdate
|
||||
try:
|
||||
if not oldEdate: oldEdate = ReadFile('data/edate.pl')
|
||||
if not oldEdate: oldEdate = ReadFile('{}/data/edate.pl'.format(base_path))
|
||||
if not oldEdate: oldEdate = '0000-00-00'
|
||||
mEdate = time.strftime('%Y-%m-%d',time.localtime())
|
||||
mEdate = time.strftime('%Y-%m-%d', time.localtime())
|
||||
if oldEdate == mEdate: return False
|
||||
os.system(get_python_bin() + " /www/server/panel/script/site_task.py > /dev/null")
|
||||
os.system(get_python_bin() + " {}/script/site_task.py > /dev/null".format(base_path))
|
||||
except Exception as ex:
|
||||
logging.debug(ex)
|
||||
logging.info(ex)
|
||||
pass
|
||||
|
||||
|
||||
def GetLoadAverage():
|
||||
c = os.getloadavg()
|
||||
data = {}
|
||||
@@ -158,12 +179,12 @@ def GetLoadAverage():
|
||||
data['limit'] = data['max']
|
||||
data['safe'] = data['max'] * 0.75
|
||||
return data
|
||||
|
||||
|
||||
#系统监控任务
|
||||
|
||||
# 系统监控任务
|
||||
def systemTask():
|
||||
try:
|
||||
filename = 'data/control.conf'
|
||||
filename = '{}/data/control.conf'.format(base_path)
|
||||
with db.Sql() as sql:
|
||||
sql = sql.dbfile('system')
|
||||
csql = '''CREATE TABLE IF NOT EXISTS `load_average` (
|
||||
@@ -174,17 +195,19 @@ def systemTask():
|
||||
`fifteen` REAL,
|
||||
`addtime` INTEGER
|
||||
)'''
|
||||
sql.execute(csql,())
|
||||
sql.execute(csql, ())
|
||||
sql.close()
|
||||
|
||||
count = 0
|
||||
reloadNum=0
|
||||
network_up = network_down = diskio_1 = diskio_2 = networkInfo = cpuInfo = diskInfo = None
|
||||
diskio_1 = diskio_2 = networkInfo = cpuInfo = diskInfo = None
|
||||
network_up = {}
|
||||
network_down = {}
|
||||
while True:
|
||||
if not os.path.exists(filename):
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
|
||||
day = 30
|
||||
try:
|
||||
day = int(ReadFile(filename))
|
||||
@@ -192,97 +215,108 @@ def systemTask():
|
||||
time.sleep(10)
|
||||
continue
|
||||
except:
|
||||
day = 30
|
||||
|
||||
|
||||
day = 30
|
||||
|
||||
tmp = {}
|
||||
#取当前CPU Io
|
||||
# 取当前CPU Io
|
||||
tmp['used'] = cpu_percent(interval=1)
|
||||
|
||||
|
||||
if not cpuInfo:
|
||||
tmp['mem'] = GetMemUsed()
|
||||
cpuInfo = tmp
|
||||
|
||||
cpuInfo = tmp
|
||||
|
||||
if cpuInfo['used'] < tmp['used']:
|
||||
tmp['mem'] = GetMemUsed()
|
||||
cpuInfo = tmp
|
||||
|
||||
|
||||
|
||||
#取当前网络Io
|
||||
networkIo = net_io_counters()[:4]
|
||||
if not network_up:
|
||||
network_up = networkIo[0]
|
||||
network_down = networkIo[1]
|
||||
cpuInfo = tmp
|
||||
|
||||
# 取当前网络Io
|
||||
networkIo_list = net_io_counters(pernic=True)
|
||||
tmp = {}
|
||||
tmp['upTotal'] = networkIo[0]
|
||||
tmp['downTotal'] = networkIo[1]
|
||||
tmp['up'] = round(float((networkIo[0] - network_up) / 1024),2)
|
||||
tmp['down'] = round(float((networkIo[1] - network_down) / 1024),2)
|
||||
tmp['downPackets'] = networkIo[3]
|
||||
tmp['upPackets'] = networkIo[2]
|
||||
|
||||
network_up = networkIo[0]
|
||||
network_down = networkIo[1]
|
||||
|
||||
if not networkInfo: networkInfo = tmp
|
||||
if (tmp['up'] + tmp['down']) > (networkInfo['up'] + networkInfo['down']): networkInfo = tmp
|
||||
|
||||
#取磁盘Io
|
||||
tmp['upTotal'] = 0
|
||||
tmp['downTotal'] = 0
|
||||
tmp['up'] = 0
|
||||
tmp['down'] = 0
|
||||
tmp['downPackets'] = {}
|
||||
tmp['upPackets'] = {}
|
||||
|
||||
for k in networkIo_list.keys():
|
||||
networkIo = networkIo_list[k][:4]
|
||||
if not k in network_up.keys():
|
||||
network_up[k] = networkIo[0]
|
||||
network_down[k] = networkIo[1]
|
||||
|
||||
tmp['upTotal'] += networkIo[0]
|
||||
tmp['downTotal'] += networkIo[1]
|
||||
tmp['downPackets'][k] = round(
|
||||
float((networkIo[1] - network_down[k]) / 1024)/5, 2)
|
||||
tmp['upPackets'][k] = round(
|
||||
float((networkIo[0] - network_up[k]) / 1024)/5, 2)
|
||||
tmp['up'] += tmp['upPackets'][k]
|
||||
tmp['down'] += tmp['downPackets'][k]
|
||||
|
||||
network_up[k] = networkIo[0]
|
||||
network_down[k] = networkIo[1]
|
||||
|
||||
if not networkInfo:
|
||||
networkInfo = tmp
|
||||
if (tmp['up'] + tmp['down']) > (networkInfo['up'] + networkInfo['down']):
|
||||
networkInfo = tmp
|
||||
|
||||
# 取磁盘Io
|
||||
disk_ios = True
|
||||
try:
|
||||
if os.path.exists('/proc/diskstats'):
|
||||
diskio_2 = disk_io_counters()
|
||||
if not diskio_1: diskio_1 = diskio_2
|
||||
if not diskio_1:
|
||||
diskio_1 = diskio_2
|
||||
tmp = {}
|
||||
tmp['read_count'] = diskio_2.read_count - diskio_1.read_count
|
||||
tmp['write_count'] = diskio_2.write_count - diskio_1.write_count
|
||||
tmp['read_bytes'] = diskio_2.read_bytes - diskio_1.read_bytes
|
||||
tmp['write_bytes'] = diskio_2.write_bytes - diskio_1.write_bytes
|
||||
tmp['read_time'] = diskio_2.read_time - diskio_1.read_time
|
||||
tmp['write_time'] = diskio_2.write_time - diskio_1.write_time
|
||||
|
||||
if not diskInfo:
|
||||
tmp['read_count'] = diskio_2.read_count - diskio_1.read_count
|
||||
tmp['write_count'] = diskio_2.write_count - diskio_1.write_count
|
||||
tmp['read_bytes'] = diskio_2.read_bytes - diskio_1.read_bytes
|
||||
tmp['write_bytes'] = diskio_2.write_bytes - diskio_1.write_bytes
|
||||
tmp['read_time'] = diskio_2.read_time - diskio_1.read_time
|
||||
tmp['write_time'] = diskio_2.write_time - diskio_1.write_time
|
||||
|
||||
if not diskInfo:
|
||||
diskInfo = tmp
|
||||
else:
|
||||
diskInfo['read_count'] += tmp['read_count']
|
||||
diskInfo['write_count'] += tmp['write_count']
|
||||
diskInfo['read_bytes'] += tmp['read_bytes']
|
||||
diskInfo['write_bytes'] += tmp['write_bytes']
|
||||
diskInfo['read_time'] += tmp['read_time']
|
||||
diskInfo['write_time'] += tmp['write_time']
|
||||
|
||||
diskInfo['read_count'] += tmp['read_count']
|
||||
diskInfo['write_count'] += tmp['write_count']
|
||||
diskInfo['read_bytes'] += tmp['read_bytes']
|
||||
diskInfo['write_bytes'] += tmp['write_bytes']
|
||||
diskInfo['read_time'] += tmp['read_time']
|
||||
diskInfo['write_time'] += tmp['write_time']
|
||||
|
||||
diskio_1 = diskio_2
|
||||
except:
|
||||
logging.info(public.get_error_info())
|
||||
disk_ios = False
|
||||
|
||||
|
||||
#print diskInfo
|
||||
|
||||
# print diskInfo
|
||||
|
||||
if count >= 12:
|
||||
try:
|
||||
sql = db.Sql().dbfile('system')
|
||||
addtime = int(time.time())
|
||||
deltime = addtime - (day * 86400)
|
||||
|
||||
|
||||
data = (cpuInfo['used'],cpuInfo['mem'],addtime)
|
||||
sql.table('cpuio').add('pro,mem,addtime',data)
|
||||
sql.table('cpuio').where("addtime<?",(deltime,)).delete()
|
||||
|
||||
data = (networkInfo['up'] / 5,networkInfo['down'] / 5,networkInfo['upTotal'],networkInfo['downTotal'],networkInfo['downPackets'],networkInfo['upPackets'],addtime)
|
||||
data = (networkInfo['up'],networkInfo['down'],networkInfo['upTotal'],networkInfo['downTotal'],dumps(networkInfo['downPackets']),dumps(networkInfo['upPackets']),addtime)
|
||||
sql.table('network').add('up,down,total_up,total_down,down_packets,up_packets,addtime',data)
|
||||
sql.table('network').where("addtime<?",(deltime,)).delete()
|
||||
if os.path.exists('/proc/diskstats') and disk_ios:
|
||||
data = (diskInfo['read_count'],diskInfo['write_count'],diskInfo['read_bytes'],diskInfo['write_bytes'],diskInfo['read_time'],diskInfo['write_time'],addtime)
|
||||
sql.table('diskio').add('read_count,write_count,read_bytes,write_bytes,read_time,write_time,addtime',data)
|
||||
sql.table('diskio').where("addtime<?",(deltime,)).delete()
|
||||
|
||||
|
||||
#LoadAverage
|
||||
load_average = GetLoadAverage()
|
||||
lpro = round((load_average['one'] / load_average['max']) * 100,2)
|
||||
lpro = round((load_average['one'] / load_average['max']) * 100, 2)
|
||||
if lpro > 100: lpro = 100
|
||||
sql.table('load_average').add('pro,one,five,fifteen,addtime',(lpro,load_average['one'],load_average['five'],load_average['fifteen'],addtime))
|
||||
sql.table('load_average').add('pro,one,five,fifteen,addtime', (
|
||||
lpro, load_average['one'], load_average['five'], load_average['fifteen'], addtime))
|
||||
sql.close()
|
||||
|
||||
lpro = None
|
||||
@@ -296,125 +330,149 @@ def systemTask():
|
||||
if reloadNum > 1440:
|
||||
reloadNum = 0
|
||||
except Exception as ex:
|
||||
logging.debug(str(ex))
|
||||
logging.info(str(ex))
|
||||
del(tmp)
|
||||
|
||||
time.sleep(5)
|
||||
count +=1
|
||||
count += 1
|
||||
except Exception as ex:
|
||||
logging.debug(ex)
|
||||
logging.info(ex)
|
||||
time.sleep(30)
|
||||
systemTask()
|
||||
|
||||
|
||||
#取内存使用率
|
||||
|
||||
# 取内存使用率
|
||||
def GetMemUsed():
|
||||
try:
|
||||
mem = virtual_memory()
|
||||
memInfo = {'memTotal':mem.total/1024/1024,'memFree':mem.free/1024/1024,'memBuffers':mem.buffers/1024/1024,'memCached':mem.cached/1024/1024}
|
||||
memInfo = {'memTotal': mem.total / 1024 / 1024, 'memFree': mem.free / 1024 / 1024,
|
||||
'memBuffers': mem.buffers / 1024 / 1024, 'memCached': mem.cached / 1024 / 1024}
|
||||
tmp = memInfo['memTotal'] - memInfo['memFree'] - memInfo['memBuffers'] - memInfo['memCached']
|
||||
tmp1 = memInfo['memTotal'] / 100
|
||||
return (tmp / tmp1)
|
||||
except:
|
||||
return 1
|
||||
|
||||
#检查502错误
|
||||
# 检查502错误
|
||||
|
||||
|
||||
def check502():
|
||||
try:
|
||||
phpversions = ['53','54','55','56','70','71','72','73','74','80']
|
||||
phpversions = ['53', '54', '55', '56','70', '71', '72', '73', '74', '80']
|
||||
for version in phpversions:
|
||||
php_path = '/www/server/php/' + version + '/sbin/php-fpm'
|
||||
if not os.path.exists(php_path): continue
|
||||
if checkPHPVersion(version): continue
|
||||
if not os.path.exists(php_path):
|
||||
continue
|
||||
if checkPHPVersion(version):
|
||||
continue
|
||||
if startPHPVersion(version):
|
||||
public.WriteLog('PHP daemon','PHP-' + version + 'processing exception was detected and has been automatically fixed!',not_web = True)
|
||||
public.WriteLog('PHP daemon',
|
||||
'PHP-' + version + 'processing exception was detected and has been automatically fixed!',
|
||||
not_web=True)
|
||||
except Exception as ex:
|
||||
logging.info(ex)
|
||||
|
||||
#处理指定PHP版本
|
||||
|
||||
# 处理指定PHP版本
|
||||
|
||||
|
||||
def startPHPVersion(version):
|
||||
try:
|
||||
fpm = '/etc/init.d/php-fpm-'+version
|
||||
fpm = '/etc/init.d/php-fpm-' + version
|
||||
php_path = '/www/server/php/' + version + '/sbin/php-fpm'
|
||||
if not os.path.exists(php_path):
|
||||
if not os.path.exists(php_path):
|
||||
if os.path.exists(fpm): os.remove(fpm)
|
||||
return False
|
||||
|
||||
#尝试重载服务
|
||||
|
||||
# 尝试重载服务
|
||||
os.system(fpm + ' start')
|
||||
os.system(fpm + ' reload')
|
||||
if checkPHPVersion(version): return True
|
||||
|
||||
#尝试重启服务
|
||||
cgi = '/tmp/php-cgi-'+version + '.sock'
|
||||
pid = '/www/server/php/'+version+'/var/run/php-fpm.pid'
|
||||
os.system('pkill -9 php-fpm-'+version)
|
||||
|
||||
# 尝试重启服务
|
||||
cgi = '/tmp/php-cgi-' + version + '.sock'
|
||||
pid = '/www/server/php/' + version + '/var/run/php-fpm.pid'
|
||||
os.system('pkill -9 php-fpm-' + version)
|
||||
time.sleep(0.5)
|
||||
if not os.path.exists(cgi): os.system('rm -f ' + cgi)
|
||||
if not os.path.exists(pid): os.system('rm -f ' + pid)
|
||||
os.system(fpm + ' start')
|
||||
if checkPHPVersion(version): return True
|
||||
|
||||
#检查是否正确启动
|
||||
|
||||
# 检查是否正确启动
|
||||
if os.path.exists(cgi): return True
|
||||
except Exception as ex:
|
||||
logging.debug(ex)
|
||||
logging.info(ex)
|
||||
return True
|
||||
|
||||
|
||||
#检查指定PHP版本
|
||||
|
||||
|
||||
# 检查指定PHP版本
|
||||
def checkPHPVersion(version):
|
||||
try:
|
||||
uri = "/phpfpm_"+version+"_status?json"
|
||||
result = public.request_php(version,uri,'')
|
||||
loads(result)
|
||||
cgi_file = '/tmp/php-cgi-{}.sock'.format(version)
|
||||
if os.path.exists(cgi_file):
|
||||
uri = "/phpfpm_"+version+"_status?json"
|
||||
result = public.request_php(version, uri, '')
|
||||
loads(result)
|
||||
return True
|
||||
except:
|
||||
logging.info("PHP-{} unreachable detected".format(version))
|
||||
return False
|
||||
|
||||
|
||||
#502错误检查线程
|
||||
# 502错误检查线程
|
||||
def check502Task():
|
||||
try:
|
||||
while True:
|
||||
if os.path.exists('/www/server/panel/data/502Task.pl'): check502()
|
||||
check502()
|
||||
sess_expire()
|
||||
time.sleep(600)
|
||||
except:
|
||||
except Exception as ex:
|
||||
logging.info(ex)
|
||||
time.sleep(600)
|
||||
check502Task()
|
||||
|
||||
|
||||
# session过期处理
|
||||
def sess_expire():
|
||||
try:
|
||||
sess_path = '{}/data/session'.format(base_path)
|
||||
if not os.path.exists(sess_path): return
|
||||
s_time = time.time()
|
||||
f_list = os.listdir(sess_path)
|
||||
f_num = len(f_list)
|
||||
for fname in f_list:
|
||||
filename = '/'.join((sess_path, fname))
|
||||
fstat = os.stat(filename)
|
||||
f_time = s_time - fstat.st_mtime
|
||||
if f_time > 3600:
|
||||
os.remove(filename)
|
||||
continue
|
||||
if fstat.st_size < 256 and len(fname) == 32:
|
||||
if f_time > 60 or f_num > 30:
|
||||
os.remove(filename)
|
||||
continue
|
||||
del (f_list)
|
||||
|
||||
except Exception as ex:
|
||||
logging.info(str(ex))
|
||||
|
||||
|
||||
# 检查面板证书是否有更新
|
||||
def check_panel_ssl():
|
||||
try:
|
||||
while True:
|
||||
lets_info = public.readFile("/www/server/panel/ssl/lets.info")
|
||||
lets_info = ReadFile("{}/ssl/lets.info".format(base_path))
|
||||
if not lets_info:
|
||||
time.sleep(600)
|
||||
continue
|
||||
lets_info = loads(lets_info)
|
||||
if setPanelLets.setPanelLets().check_cert_update(lets_info['domain']):
|
||||
strTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time())))
|
||||
public.writeFile("/tmp/panelSSL.pl","{} Panel certificate updated successfully\n".format(strTime),"a+")
|
||||
public.writeFile('/www/server/panel/data/reload.pl',"1")
|
||||
os.system(get_python_bin() + " {}/script/panel_ssl_task.py > /dev/null".format(base_path))
|
||||
time.sleep(60)
|
||||
except:
|
||||
e = public.get_error_info()
|
||||
public.writeFile("/tmp/panelSSL.pl", str(e),"a+")
|
||||
except Exception as e:
|
||||
public.writeFile("/tmp/panelSSL.pl", str(e), "a+")
|
||||
|
||||
#监控面板状态
|
||||
# 监控面板状态
|
||||
def panel_status():
|
||||
time.sleep(1)
|
||||
panel_path = '/www/server/panel'
|
||||
pool = 'http://'
|
||||
if os.path.exists(panel_path + '/data/ssl.pl'): pool = 'https://'
|
||||
port = '8888'
|
||||
if os.path.exists(panel_path + '/data/port.pl'): port = ReadFile(panel_path + '/data/port.pl').strip()
|
||||
panel_url = pool + '127.0.0.1:' + port + '/service_status'
|
||||
panel_pid = get_panel_pid()
|
||||
n = 0
|
||||
s = 0
|
||||
v = 0
|
||||
while True:
|
||||
time.sleep(5)
|
||||
if not panel_pid: panel_pid = get_panel_pid()
|
||||
@@ -433,54 +491,24 @@ def panel_status():
|
||||
panel_pid = get_panel_pid()
|
||||
continue
|
||||
|
||||
n += 1
|
||||
v += 1
|
||||
|
||||
if v > 10:
|
||||
v = 0
|
||||
log_path = panel_path + '/logs/error.log'
|
||||
if os.path.exists(log_path):
|
||||
e_body = public.GetNumLines(log_path,10)
|
||||
if e_body:
|
||||
if e_body.find('PyWSGIServer.do_close') != -1 or e_body.find('Expected GET method:')!=-1 or e_body.find('Invalid HTTP method:') != -1 or e_body.find('table session') != -1:
|
||||
result = HttpGet(panel_url)
|
||||
if result != 'True':
|
||||
if e_body.find('table session') != -1:
|
||||
sess_file = '/dev/shm/session.db'
|
||||
if os.path.exists(sess_file): os.remove(sess_file)
|
||||
os.system("bash /www/server/panel/init.sh reload &")
|
||||
time.sleep(10)
|
||||
result = HttpGet(panel_url)
|
||||
if result == 'True':
|
||||
public.WriteLog('TYPE_SOFE','Checked to panel service exception, has been automatically restored!',not_web = True)
|
||||
|
||||
if n > 18000:
|
||||
n = 0
|
||||
result = HttpGet(panel_url)
|
||||
if result == 'True':
|
||||
time.sleep(10)
|
||||
continue
|
||||
update_panel()
|
||||
result = HttpGet(panel_url)
|
||||
if result == 'True':
|
||||
public.WriteLog('TYPE_SOFE','Checked to panel service exception, has been automatically restored!',not_web = True)
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
|
||||
def update_panel():
|
||||
public.ExecShell("curl http://download.bt.cn/install/update6_en.sh|bash &")
|
||||
os.system("curl http://download.bt.cn/install/update6_en.sh|bash &")
|
||||
|
||||
def service_panel(action = 'reload'):
|
||||
if not os.path.exists('/www/server/panel/init.sh'):
|
||||
|
||||
def service_panel(action='reload'):
|
||||
if not os.path.exists('{}/init.sh'.format(base_path)):
|
||||
update_panel()
|
||||
else:
|
||||
os.system("bash /www/server/panel/init.sh {} &".format(action))
|
||||
os.system("bash {}/init.sh {} &".format(base_path, action))
|
||||
|
||||
|
||||
# 重启面板服务
|
||||
|
||||
|
||||
#重启面板服务
|
||||
def restart_panel_service():
|
||||
rtips = 'data/restart.pl'
|
||||
reload_tips = 'data/reload.pl'
|
||||
rtips = '{}/data/restart.pl'.format(base_path)
|
||||
reload_tips = '{}/data/reload.pl'.format(base_path)
|
||||
while True:
|
||||
if os.path.exists(rtips):
|
||||
os.remove(rtips)
|
||||
@@ -490,85 +518,126 @@ def restart_panel_service():
|
||||
service_panel('reload')
|
||||
time.sleep(1)
|
||||
|
||||
#取面板pid
|
||||
# 取面板pid
|
||||
|
||||
|
||||
def get_panel_pid():
|
||||
pid = ReadFile('/www/server/panel/logs/panel.pid')
|
||||
pid = ReadFile('{}/logs/panel.pid'.format(base_path))
|
||||
if pid: return int(pid)
|
||||
for pid in pids():
|
||||
try:
|
||||
p = Process(pid)
|
||||
n = p.cmdline()[-1]
|
||||
if n.find('runserver') != -1 or n.find('BT-Panel') != -1: return pid
|
||||
except: pass
|
||||
if n.find('runserver') != -1 or n.find('BT-Panel') != -1:
|
||||
return pid
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def HttpGet(url,timeout = 6,headers = {}):
|
||||
def HttpGet(url, timeout=6, headers={}):
|
||||
if sys.version_info[0] == 2:
|
||||
try:
|
||||
import urllib2
|
||||
req = urllib2.Request(url, headers = headers)
|
||||
response = urllib2.urlopen(req,timeout = timeout,)
|
||||
req = urllib2.Request(url, headers=headers)
|
||||
response = urllib2.urlopen(req, timeout=timeout,)
|
||||
return response.read()
|
||||
except Exception as ex:
|
||||
logging.debug(str(ex))
|
||||
logging.info(str(ex))
|
||||
return str(ex)
|
||||
else:
|
||||
try:
|
||||
import urllib.request
|
||||
req = urllib.request.Request(url,headers = headers)
|
||||
response = urllib.request.urlopen(req,timeout = timeout)
|
||||
req = urllib.request.Request(url, headers=headers)
|
||||
response = urllib.request.urlopen(req, timeout=timeout)
|
||||
result = response.read()
|
||||
if type(result) == bytes: result = result.decode('utf-8')
|
||||
if type(result) == bytes:
|
||||
result = result.decode('utf-8')
|
||||
return result
|
||||
except Exception as ex:
|
||||
logging.debug("URL: {} => {}".format(url,ex))
|
||||
logging.info("URL: {} => {}".format(url, ex))
|
||||
return str(ex)
|
||||
|
||||
|
||||
#定时任务去检测邮件信息
|
||||
# 定时任务去检测邮件信息
|
||||
def send_mail_time():
|
||||
p_path = '/www/server/panel/data/'
|
||||
p_reload = p_path + '/send_to_user.pl'
|
||||
if not os.path.exists(p_path):
|
||||
p_reload = '{}/data/send_to_user.pl'.format(base_path)
|
||||
if not os.path.exists('{}/data'.format(base_path)):
|
||||
return
|
||||
while True:
|
||||
try:
|
||||
if os.path.exists(p_reload):
|
||||
os.system(get_python_bin() + " /www/server/panel/script/mail_task.py > /dev/null")
|
||||
os.system(get_python_bin() + " {}/script/mail_task.py > /dev/null".format(base_path))
|
||||
os.remove(p_reload)
|
||||
time.sleep(60)
|
||||
except:
|
||||
time.sleep(180)
|
||||
send_mail_time()
|
||||
|
||||
# 检查面板文件完整性
|
||||
def check_files_panel():
|
||||
python_bin = get_python_bin()
|
||||
while True:
|
||||
time.sleep(600)
|
||||
try:
|
||||
result = loads(
|
||||
os.popen('{} {}/script/check_files.py'.format(python_bin,base_path)).read()
|
||||
)
|
||||
except:
|
||||
logging.info(public.get_error_info())
|
||||
continue
|
||||
if result in ['0']:
|
||||
continue
|
||||
|
||||
if type(result) != list:
|
||||
continue
|
||||
class_path = '{}/class/'.format(base_path)
|
||||
for i in result:
|
||||
cf = class_path + i['name']
|
||||
if not os.path.exists(cf):
|
||||
continue
|
||||
if public.FileMd5(cf) == i['md5']:
|
||||
continue
|
||||
public.writeFile(cf, i['body'])
|
||||
os.system("bash {}/init.sh reload &".format(base_path))
|
||||
|
||||
|
||||
# 面板消息提醒
|
||||
def check_panel_msg():
|
||||
python_bin = get_python_bin()
|
||||
while True:
|
||||
os.system('{} {}/script/check_msg.py &'.format(python_bin,base_path))
|
||||
time.sleep(600)
|
||||
|
||||
|
||||
def main():
|
||||
main_pid = 'logs/task.pid'
|
||||
if os.path.exists(main_pid):
|
||||
os.system("kill -9 $(cat {}) &> /dev/null".format(main_pid))
|
||||
pid = os.fork()
|
||||
if pid: sys.exit(0)
|
||||
if pid:
|
||||
sys.exit(0)
|
||||
|
||||
#os.umask(0)
|
||||
os.setsid()
|
||||
|
||||
_pid = os.fork()
|
||||
if _pid:
|
||||
public.writeFile(main_pid,str(_pid))
|
||||
public.writeFile(main_pid, str(_pid))
|
||||
sys.exit(0)
|
||||
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
task_log_file='logs/task.log'
|
||||
task_log_file = 'logs/task.log'
|
||||
|
||||
logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s [%(levelname)s] at %(lineno)d: %(message)s',datefmt = '%Y-%m-%d(%a)%H:%M:%S',filename = task_log_file,filemode = 'a+')
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s]: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S', filename=task_log_file, filemode='a+')
|
||||
logging.info('Service started')
|
||||
|
||||
import threading
|
||||
t = threading.Thread(target=systemTask)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
|
||||
p = threading.Thread(target=check502Task)
|
||||
p.setDaemon(True)
|
||||
p.start()
|
||||
@@ -589,14 +658,23 @@ def main():
|
||||
p.setDaemon(True)
|
||||
p.start()
|
||||
|
||||
p = threading.Thread(target=check_files_panel)
|
||||
p.setDaemon(True)
|
||||
p.start()
|
||||
import panelTask
|
||||
task_obj = panelTask.bt_task()
|
||||
task_obj.not_web = True
|
||||
p = threading.Thread(target=task_obj.start_task)
|
||||
p.setDaemon(True)
|
||||
p.start()
|
||||
|
||||
p = threading.Thread(target=check_panel_msg)
|
||||
p.setDaemon(True)
|
||||
p.start()
|
||||
|
||||
startTask()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
@@ -443,6 +443,7 @@ def bt_cli(u_input = 0):
|
||||
print("(23) %s (16) %s"% ("Turn off BasicAuth authentication","Repair panel (check for errors and update panel files to the latest version)"))
|
||||
print("(24) Turn off Google Authenticator (17) Set log cutting on/off compression")
|
||||
print("(25) Set whether to back up the panel automatically (18) Set whether to save a historical copy of the file")
|
||||
print("(26) Keep/Remove local backup when backing up to cloud storage")
|
||||
print("(0) Cancel")
|
||||
print(raw_tip)
|
||||
try:
|
||||
@@ -450,7 +451,7 @@ def bt_cli(u_input = 0):
|
||||
if sys.version_info[0] == 3: u_input = int(u_input)
|
||||
except: u_input = 0
|
||||
|
||||
nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,22,23,24,25]
|
||||
nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,22,23,24,25,26]
|
||||
if not u_input in nums:
|
||||
print(raw_tip)
|
||||
print(public.GetMsg("CANCELLED"))
|
||||
@@ -603,6 +604,14 @@ def bt_cli(u_input = 0):
|
||||
print("|-Detected that the file copy function is turned on and is closing...")
|
||||
public.writeFile(l_path,'True')
|
||||
print("|-File copy function turned off")
|
||||
elif u_input == 26:
|
||||
keep_local = "/www/server/panel/data/is_save_local_backup.pl"
|
||||
if os.path.exists(keep_local):
|
||||
print("|-The local file retention setting is turned off")
|
||||
os.remove(keep_local)
|
||||
else:
|
||||
print("|-The local file retention setting is turned on")
|
||||
os.mknod(keep_local)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user