mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-10 06:39:25 +08:00
gdrive云备份开始测试
This commit is contained in:
@@ -163,7 +163,6 @@ plugins/l2tp
|
||||
plugins/openlitespeed
|
||||
plugins/tamper_proof
|
||||
plugins/cryptocurrency_trade
|
||||
plugins/gdrive
|
||||
plugins/mtproxy
|
||||
plugins/zimg
|
||||
plugins/bk_demo
|
||||
|
||||
@@ -0,0 +1,413 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
import io
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
# -----------------------------
|
||||
import google.oauth2.credentials
|
||||
import google_auth_oauthlib.flow
|
||||
from googleapiclient.discovery import build
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request
|
||||
from googleapiclient.http import MediaFileUpload
|
||||
from googleapiclient.http import MediaIoBaseDownload
|
||||
|
||||
|
||||
class gdriveclient():
|
||||
__plugin_dir = ''
|
||||
__server_dir = ''
|
||||
|
||||
__credentials = "/root/credentials.json"
|
||||
__backup_dir_name = "backup"
|
||||
__creds = None
|
||||
__exclude = ""
|
||||
__scpos = ['https://www.googleapis.com/auth/drive.file']
|
||||
_title = 'Google Drive'
|
||||
_name = 'Google Drive'
|
||||
__debug = False
|
||||
|
||||
_DEFAULT_AUTH_PROMPT_MESSAGE = (
|
||||
'Please visit this URL to authorize this application: {url}')
|
||||
"""str: The message to display when prompting the user for
|
||||
authorization."""
|
||||
_DEFAULT_AUTH_CODE_MESSAGE = (
|
||||
'Enter the authorization code: ')
|
||||
"""str: The message to display when prompting the user for the
|
||||
authorization code. Used only by the console strategy."""
|
||||
|
||||
_DEFAULT_WEB_SUCCESS_MESSAGE = (
|
||||
'The authentication flow has completed, you may close this window.')
|
||||
|
||||
def __init__(self, plugin_dir, server_dir):
|
||||
self.__plugin_dir = plugin_dir
|
||||
self.__server_dir = server_dir
|
||||
self.set_creds()
|
||||
# self.set_libList()
|
||||
|
||||
# self.get_exclode()
|
||||
|
||||
def setDebug(self, d=False):
|
||||
self.__debug = d
|
||||
|
||||
def D(self, msg=''):
|
||||
if self.__debug:
|
||||
print(msg)
|
||||
|
||||
# 检查gdrive连接
|
||||
def _check_connect(self):
|
||||
try:
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(
|
||||
pageSize=10, fields="nextPageToken, files(id, name)").execute()
|
||||
results.get('files', [])
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 设置creds
|
||||
def set_creds(self):
|
||||
token_file = self.__server_dir + '/token.json'
|
||||
if os.path.exists(token_file):
|
||||
with open(token_file, 'rb') as token:
|
||||
tmp_data = json.load(token)['credentials']
|
||||
self.__creds = google.oauth2.credentials.Credentials(
|
||||
tmp_data['token'],
|
||||
tmp_data['refresh_token'],
|
||||
tmp_data['id_token'],
|
||||
tmp_data['token_uri'],
|
||||
tmp_data['client_id'],
|
||||
tmp_data['client_secret'],
|
||||
tmp_data['scopes'])
|
||||
# if not self._check_connect():
|
||||
# return False
|
||||
# else:
|
||||
# return True
|
||||
|
||||
def get_sign_in_url(self):
|
||||
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
|
||||
self.__plugin_dir + '/credentials.json',
|
||||
scopes=self.__scpos)
|
||||
flow.redirect_uri = 'https://localhost'
|
||||
auth_url, state = flow.authorization_url(
|
||||
access_type='offline',
|
||||
prompt='consent',
|
||||
include_granted_scopes='false')
|
||||
return auth_url, state
|
||||
|
||||
def set_auth_url(self, url):
|
||||
token_file = self.__server_dir + '/token.json'
|
||||
if os.path.exists(token_file):
|
||||
return mw.returnJson(True, "验证成功")
|
||||
|
||||
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
|
||||
self.__plugin_dir + '/credentials.json',
|
||||
scopes=self.__scpos,
|
||||
state=url.split('state=')[1].split('&code=')[0])
|
||||
flow.redirect_uri = 'https://localhost'
|
||||
flow.fetch_token(authorization_response=url)
|
||||
credentials = flow.credentials
|
||||
|
||||
credentials_data = {}
|
||||
credentials_data['credentials'] = {
|
||||
'token': credentials.token,
|
||||
'id_token': credentials.id_token,
|
||||
'refresh_token': credentials.refresh_token,
|
||||
'token_uri': credentials.token_uri,
|
||||
'client_id': credentials.client_id,
|
||||
'client_secret': credentials.client_secret,
|
||||
'scopes': credentials.scopes}
|
||||
with open(token_file, 'w') as token:
|
||||
json.dump(credentials_data, token)
|
||||
if not self.set_creds():
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
return mw.returnJson(True, "验证成功")
|
||||
|
||||
def set_libList(self):
|
||||
libList = public.readFile("/www/server/panel/data/libList.conf")
|
||||
if libList:
|
||||
libList = json.loads(libList)
|
||||
for i in libList:
|
||||
if "gdrive" in i.values():
|
||||
return
|
||||
d = {
|
||||
"name": "Google Drive",
|
||||
"type": "Cron job",
|
||||
"ps": "Back up your website or database to Google Cloud Storage.",
|
||||
"status": False,
|
||||
"opt": "gdrive",
|
||||
"module": "os",
|
||||
"script": "gdrive",
|
||||
"help": "http://forum.aapanel.com",
|
||||
"key": "",
|
||||
"secret": "",
|
||||
"bucket": "",
|
||||
"domain": "",
|
||||
"check": ["/www/server/panel/plugin/gdrive/gdrive_main.py",
|
||||
"/www/server/panel/script/backup_gdrive.py"]
|
||||
}
|
||||
d1 = {
|
||||
"name": "谷歌硬盘",
|
||||
"type": "计划任务",
|
||||
"ps": "将网站或数据库打包备份到谷歌硬盘.",
|
||||
"status": False,
|
||||
"opt": "gdrive",
|
||||
"module": "os",
|
||||
"script": "gdrive",
|
||||
"help": "http://www.bt.cn/bbs",
|
||||
"key": "",
|
||||
"secret": "",
|
||||
"bucket": "",
|
||||
"domain": "",
|
||||
"check": ["/www/server/panel/plugin/gdrive/gdrive_main.py",
|
||||
"/www/server/panel/script/backup_gdrive.py"]
|
||||
}
|
||||
language = public.readFile("/www/server/panel/config/config.json")
|
||||
if "English" in language:
|
||||
data = d
|
||||
else:
|
||||
data = d1
|
||||
libList.append(data)
|
||||
public.writeFile("/www/server/panel/data/libList.conf",
|
||||
json.dumps(libList))
|
||||
return libList
|
||||
|
||||
# 获取token
|
||||
def get_token(self, get):
|
||||
token_file = self.__server_dir + '/token.json'
|
||||
import requests
|
||||
try:
|
||||
respone = requests.get("https://www.google.com", timeout=2)
|
||||
except:
|
||||
return mw.returnJson(False, "连接谷歌失败")
|
||||
if respone.status_code != 200:
|
||||
return mw.returnJson(False, "连接谷歌失败")
|
||||
if not self.set_creds():
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
if not os.path.exists(token_file):
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
return mw.returnJson(True, "验证成功")
|
||||
|
||||
# 获取auth_url
|
||||
def get_auth_url(self, get):
|
||||
self.get_sign_in_url()
|
||||
if os.path.exists("/tmp/auth_url"):
|
||||
return mw.readFile("/tmp/auth_url")
|
||||
|
||||
# 检查连接
|
||||
def check_connect(self, get):
|
||||
token_file = self.__server_dir + '/token.json'
|
||||
if os.path.exists(token_file):
|
||||
with open(token_file, 'rb') as token:
|
||||
self.set_creds()
|
||||
else:
|
||||
self.D("Failed to get Google token, please verify before use")
|
||||
return mw.returnJson(True, "Failed to get Google token, please verify before use")
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(
|
||||
pageSize=10, fields="nextPageToken, files(id, name)").execute()
|
||||
try:
|
||||
results.get('files', [])
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
return mw.returnJson(True, "验证成功")
|
||||
except:
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
|
||||
def _get_filename(self, filename):
|
||||
l = filename.split("/")
|
||||
return l[-1]
|
||||
|
||||
def _create_folder_cycle(self, filepath):
|
||||
l = filepath.split("/")
|
||||
fid_list = []
|
||||
for i in l:
|
||||
if not i:
|
||||
continue
|
||||
fid = self.__get_folder_id(i)
|
||||
if fid:
|
||||
fid_list.append(fid)
|
||||
continue
|
||||
if not fid_list:
|
||||
fid_list.append("")
|
||||
fid_list.append(self.create_folder(i, fid_list[-1]))
|
||||
return fid_list[-1]
|
||||
|
||||
def build_object_name(self, data_type, file_name):
|
||||
"""根据数据类型构建对象存储名称
|
||||
|
||||
:param data_type:
|
||||
:param file_name:
|
||||
:return:
|
||||
"""
|
||||
|
||||
import re
|
||||
prefix_dict = {
|
||||
"site": "web",
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
|
||||
if not prefix_dict.get(data_type):
|
||||
print("data_type 类型错误!!!")
|
||||
exit(1)
|
||||
|
||||
file_regx = prefix_dict.get(data_type) + "_(.+)_20\d+_\d+\."
|
||||
sub_search = re.search(file_regx.lower(), file_name)
|
||||
sub_path_name = ""
|
||||
if sub_search:
|
||||
sub_path_name = sub_search.groups()[0]
|
||||
sub_path_name += '/'
|
||||
# 构建OS存储路径
|
||||
object_name = self.__backup_dir_name + \
|
||||
'/{}/{}'.format(data_type, sub_path_name)
|
||||
|
||||
if object_name[:1] == "/":
|
||||
object_name = object_name[1:]
|
||||
return object_name
|
||||
|
||||
# 上传文件
|
||||
def upload_file(self, filename, data_type=None):
|
||||
"""
|
||||
get.filename 上传后的文件名
|
||||
get.filepath 上传文件路径
|
||||
被面板新版计划任务调用时
|
||||
get表示file_name
|
||||
:param get:
|
||||
:return:
|
||||
"""
|
||||
# filename = filename
|
||||
filepath = self.build_object_name(data_type, filename)
|
||||
_filename = self._get_filename(filename)
|
||||
self.D(filepath)
|
||||
self.D(filename)
|
||||
|
||||
parents = self._create_folder_cycle(filepath)
|
||||
self.D(parents)
|
||||
drive_service = build('drive', 'v3', credentials=self.__creds)
|
||||
file_metadata = {'name': _filename, 'parents': [parents]}
|
||||
media = MediaFileUpload(filename, resumable=True)
|
||||
file = drive_service.files().create(
|
||||
body=file_metadata, media_body=media, fields='id').execute()
|
||||
self.D('Upload Success ,File ID: %s' % file.get('id'))
|
||||
return True
|
||||
|
||||
def _get_file_id(self, filename):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(pageSize=10, q="name='{}'".format(
|
||||
filename), fields="nextPageToken, files(id, name)").execute()
|
||||
items = results.get('files', [])
|
||||
if not items:
|
||||
return []
|
||||
else:
|
||||
for item in items:
|
||||
return item["id"]
|
||||
|
||||
def delete_file(self, filename=None, data_type=None):
|
||||
file_id = self._get_file_id(filename)
|
||||
self.delete_file_by_id(file_id)
|
||||
return True
|
||||
|
||||
def delete_file_by_id(self, file_id):
|
||||
self.D("delete id:{}".format(file_id))
|
||||
try:
|
||||
drive_service = build('drive', 'v3', credentials=self.__creds)
|
||||
drive_service.files().delete(fileId=file_id).execute()
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
# 创建目录
|
||||
def create_folder(self, folder_name, parents=""):
|
||||
self.D(self.__creds)
|
||||
self.D("folder_name: {}".format(folder_name))
|
||||
self.D("parents: {}".format(parents))
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
file_metadata = {
|
||||
'name': folder_name,
|
||||
'mimeType': 'application/vnd.google-apps.folder'
|
||||
}
|
||||
if parents:
|
||||
file_metadata['parents'] = [parents]
|
||||
folder = service.files().create(body=file_metadata, fields='id').execute()
|
||||
self.D('Create Folder ID: %s' % folder.get('id'))
|
||||
return folder.get('id')
|
||||
|
||||
def get_rootdir_id(self, folder_name='backup'):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(pageSize=10, q="name='{}' and mimeType='application/vnd.google-apps.folder'".format(folder_name),
|
||||
fields="nextPageToken, files(id, name,size,parents,webViewLink)").execute()
|
||||
items = results.get('files', [])
|
||||
if len(items) == 0:
|
||||
self.create_folder(folder_name)
|
||||
return self.get_rootdir_id(folder_name)
|
||||
|
||||
return items[0]['parents'][0]
|
||||
|
||||
# 获取目录id
|
||||
def __get_folder_id(self, floder_name):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(pageSize=10, q="name='{}' and mimeType='application/vnd.google-apps.folder'".format(floder_name),
|
||||
fields="nextPageToken, files(id, name)").execute()
|
||||
items = results.get('files', [])
|
||||
if not items:
|
||||
return []
|
||||
else:
|
||||
for item in items:
|
||||
return item["id"]
|
||||
|
||||
def get_res_info(self, rid):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().get(fileId='{}'.format(rid)).execute()
|
||||
return results
|
||||
|
||||
def get_id_list(self, driveId=''):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(pageSize=10, driveId="{}".format(driveId),
|
||||
fields="nextPageToken, files(id, name,size,parents)").execute()
|
||||
items = results.get('files', [])
|
||||
return items
|
||||
|
||||
def get_list(self, dir_id='', next_page_token=''):
|
||||
if dir_id == '':
|
||||
dir_id = self.get_rootdir_id(self.__backup_dir_name)
|
||||
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
cmd_query = "trashed=false and '{}' in parents".format(dir_id)
|
||||
results = service.files().list(pageSize=10, q=cmd_query, orderBy='folder asc',
|
||||
fields="nextPageToken, files(id, name,size,createdTime,parents,webViewLink)").execute()
|
||||
items = results.get('files', [])
|
||||
nextPageToken = results.get('nextPageToken', [])
|
||||
# print(items)
|
||||
# print(nextPageToken)
|
||||
return items
|
||||
|
||||
def get_exclode(self, exclude=[]):
|
||||
if not exclude:
|
||||
tmp_exclude = os.getenv('BT_EXCLUDE')
|
||||
if tmp_exclude:
|
||||
exclude = tmp_exclude.split(',')
|
||||
if not exclude:
|
||||
return ""
|
||||
for ex in exclude:
|
||||
self.__exclude += " --exclude=\"" + ex + "\""
|
||||
self.__exclude += " "
|
||||
return self.__exclude
|
||||
|
||||
def download_file(self, filename):
|
||||
file_id = self._get_file_id(filename)
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
request = service.files().get_media(fileId=file_id)
|
||||
with open('/tmp/{}'.format(filename), 'wb') as fh:
|
||||
downloader = MediaIoBaseDownload(fh, request)
|
||||
done = False
|
||||
while done is False:
|
||||
status, done = downloader.next_chunk()
|
||||
print("Download %d%%." % int(status.progress() * 100))
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"web": {
|
||||
"client_id": "540181629246-1horo9i4htamdbhiqar9rcbq33bqe2ob.apps.googleusercontent.com",
|
||||
"project_id": "plated-inn-369901",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_secret": "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",
|
||||
"redirect_uris": ["https://drive.aapanel.com"]
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,310 @@
|
||||
<style>
|
||||
.upyunCon {
|
||||
height: 428px;
|
||||
}
|
||||
|
||||
.up-place {
|
||||
height: 62px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.up-place .btn {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.up-place .place-input {
|
||||
background-color: #f3f3f3;
|
||||
border: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 28px;
|
||||
overflow: hidden;
|
||||
margin: 1px 0 0 -1px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
.place-input ul {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.place-input ul li {
|
||||
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.place-input ul li a {
|
||||
height: 28px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.upyunlist {
|
||||
height: 516px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.up-bottom {
|
||||
background-color: #fafafa;
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.up-use {
|
||||
line-height: 50px
|
||||
}
|
||||
|
||||
.list-list .cursor span {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.btn-title {
|
||||
margin-top: 1px
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 10px;
|
||||
font-style: oblique;
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
<div class="upyunCon">
|
||||
<div class="up-place pd15">
|
||||
<button id="backBtn" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="后退"></button>
|
||||
<input id="myPath" type="hidden" value="">
|
||||
<input id="curPath" type="hidden" value="">
|
||||
<div class="place-input pull-left">
|
||||
<div style="width:1400px;height:28px"><ul></ul></div>
|
||||
</div>
|
||||
<button class="refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-left mr20" title="刷新" style="margin-left:-1px;"></button>
|
||||
<button class="btn btn-default btn-sm pull-right btn-title" onclick="authApi()">授权</button>
|
||||
<button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="createDir()">新建文件夹</button>
|
||||
</div>
|
||||
|
||||
<div class="upyunlist pd15">
|
||||
<div class="divtable" style="margin-bottom:15px">
|
||||
<table class="table table-hover">
|
||||
<thead><tr><th>名称</th><th>大小</th><th>更新时间</th><th class="text-right">操作</th></tr></thead>
|
||||
<tbody class="list-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
.check_api {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.up-place {
|
||||
height: 62px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.up-place .btn {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.up-place .place-input {
|
||||
background-color: #f3f3f3;
|
||||
border: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 28px;
|
||||
overflow: hidden;
|
||||
margin: 1px 0 0 -1px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
.place-input ul {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.place-input ul li {
|
||||
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.place-input ul li a {
|
||||
height: 28px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.upyunlist {
|
||||
height: 546px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.up-bottom {
|
||||
background-color: #fafafa;
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.up-use {
|
||||
line-height: 50px
|
||||
}
|
||||
|
||||
.list-list .cursor span {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.btn-title {
|
||||
margin-top: 1px
|
||||
}
|
||||
|
||||
.step_item{
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.step_item .serial_box{
|
||||
display: inline-block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.step_item .serial{
|
||||
width: 70px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
.step_item .serial span{
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
line-height: 28px;
|
||||
font-size: 11px;
|
||||
border-radius: 50%;
|
||||
color: #20a53a;
|
||||
border: 2px solid #20a53a;
|
||||
}
|
||||
.step_item .serial_title{
|
||||
margin-bottom: 10px;
|
||||
font-size: 15px;
|
||||
line-height: 30px;
|
||||
color: #666;
|
||||
}
|
||||
.step_two_url{
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
width: 380px;
|
||||
/*text-overflow: ellipsis;*/
|
||||
white-space: nowrap;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
margin-right: 15px;
|
||||
border-radius: 2px;
|
||||
padding: 0 10px;
|
||||
float: left;
|
||||
width:360px;
|
||||
padding-right: 35px;
|
||||
}
|
||||
.btn_btlink{
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border: 1px solid #20a53a;
|
||||
color: #fff;
|
||||
background-color: #20a53a;
|
||||
margin-right:10px;
|
||||
}
|
||||
.btn_btlink:hover{
|
||||
color: #fff;
|
||||
background-color: #10952a;
|
||||
border-color: #398439;
|
||||
}
|
||||
.btn_btlink a:visited{
|
||||
color: #fff;
|
||||
background-color: #10952a;
|
||||
border-color: #398439;
|
||||
}
|
||||
.view_video{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.view_video ul li{
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.setp_one i{
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 25px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
.google_drive{
|
||||
width:465px;
|
||||
height:100px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/html" id="check_api">
|
||||
<div class="check_api">
|
||||
<div class="step_two">
|
||||
<div class="step_item">
|
||||
<div class="serial"><span>1</span></div>
|
||||
<div class="serial_box">
|
||||
<div class="serial_title">阅读简易操作教程:如何获取Google Drive授权?</div>
|
||||
<div class="serial_conter">
|
||||
<div class="view_video">
|
||||
<ul>
|
||||
<li>1. 点击下面第<div class="serial" style="float: none;width: 45px;"><span>2</span></div>步中的 打开授权链接。<li>
|
||||
<li>2. 在新窗口页面上登录Google Drive账号。阅读授权权限,并同意。<li>
|
||||
<li>3. 页面跳转后,将浏览器的地址栏地址复制到第<div class="serial" style="float: none;width: 45px;"><span>3</span></div>步的文本框中。<li>
|
||||
<li>4. 点击 获取授权,随即完成授权。<li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step_item pb15">
|
||||
<div class="serial"><span>2</span></div>
|
||||
<div class="serial_box">
|
||||
<div class="serial_title">操作1:👇打开授权链接,根据网页提示对插件进行授权。</div>
|
||||
<div class="serial_conter step_two" style="width: 500px;">
|
||||
<input class="bt-input-text mr5 step_two_url" type="text" disabled>
|
||||
<span class="ico-copy mr10" data-copy="" style="vertical-align: middle;cursor: pointer;margin-left: -37px;margin-right: 20px;"></span>
|
||||
<a href="" class="btn_btlink open_btlink" target="_blank" style="padding: 7px 10px;">打开授权链接</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="step_item">
|
||||
<div class="serial"><span>3</span></div>
|
||||
<div class="serial_box">
|
||||
<div class="serial_title">操作2:复制回浏览器跳转后的地址:</div>
|
||||
<div class="serial_conter">
|
||||
<textarea row="3" placeholder="验证URL地址" class="bt-input-text google_drive" style="resize: none;"/></br>
|
||||
<button type="button" class="btn btn-success btn-sm set_auth_btn">获取授权</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/javascript" src="/plugins/file?name=gdrive&f=js/gdrive.js"></script>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=gdrive&f=js/gdrive.js", function(){
|
||||
gdList('');
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,342 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
|
||||
# print(sys.platform)
|
||||
if sys.platform != "darwin":
|
||||
os.chdir("/www/server/mdserver-web")
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
import db
|
||||
|
||||
_ver = sys.version_info
|
||||
is_py2 = (_ver[0] == 2)
|
||||
is_py3 = (_ver[0] == 3)
|
||||
|
||||
DEBUG = False
|
||||
|
||||
if is_py2:
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'gdrive'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def in_array(name, arr=[]):
|
||||
for x in arr:
|
||||
if name == x:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
sys.path.append(getPluginDir() + "/class")
|
||||
from gdriveclient import gdriveclient
|
||||
|
||||
|
||||
gd = gdriveclient(getPluginDir(), getServerDir())
|
||||
gd.setDebug(False)
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':', 1)
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':', 1)
|
||||
tmp[t[0]] = t[1]
|
||||
return tmp
|
||||
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def status():
|
||||
return 'start'
|
||||
|
||||
|
||||
def isAuthApi():
|
||||
cfg = getServerDir() + "/token.json"
|
||||
if os.path.exists(cfg):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def getConf():
|
||||
if not isAuthApi():
|
||||
sign_in_url, state = gd.get_sign_in_url()
|
||||
return mw.returnJson(False, "未授权!", {'auth_url': sign_in_url})
|
||||
return mw.returnJson(True, "OK")
|
||||
|
||||
|
||||
def setAuthUrl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['url'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
url = args['url']
|
||||
|
||||
try:
|
||||
if url.startswith("http://"):
|
||||
url = url.replace("http://", "https://")
|
||||
token = gd.set_auth_url(url)
|
||||
# gd.store_token(token)
|
||||
# gd.store_user()
|
||||
return mw.returnJson(True, "授权成功!")
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, "授权失败2!:" + str(e))
|
||||
return mw.returnJson(False, "授权失败!:" + str(e))
|
||||
|
||||
|
||||
def clearAuth():
|
||||
cfg = getServerDir() + "/user.conf"
|
||||
if os.path.exists(cfg):
|
||||
os.remove(cfg)
|
||||
|
||||
token = getServerDir() + "/token.pickle"
|
||||
if os.path.exists(token):
|
||||
os.remove(token)
|
||||
|
||||
return mw.returnJson(True, "清空授权成功!")
|
||||
|
||||
|
||||
def getList():
|
||||
if not isAuthApi():
|
||||
return mw.returnJson(False, "未配置,请点击`授权`", [])
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file_id'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
try:
|
||||
flist = gd.get_list(args['file_id'])
|
||||
return mw.returnJson(True, "ok", flist)
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, str(e), [])
|
||||
|
||||
|
||||
def createDir():
|
||||
if not isAuthApi():
|
||||
return mw.returnJson(False, "未配置,请点击`授权`", [])
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['parents', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
isok = gd.create_folder(args['name'], args['parents'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "创建成功")
|
||||
return mw.returnJson(False, "创建失败")
|
||||
|
||||
|
||||
def deleteDir():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['dir_name', 'path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
isok = gd.delete_file_by_id(args['dir_name'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "删除成功")
|
||||
return mw.returnJson(False, "文件不为空,删除失败!")
|
||||
|
||||
|
||||
def deleteFile():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path', 'filename'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
isok = gd.delete_file(args['filename'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "删除成功")
|
||||
return mw.returnJson(False, "删除失败")
|
||||
|
||||
|
||||
def findPathName(path, filename):
|
||||
f = os.scandir(path)
|
||||
l = []
|
||||
for ff in f:
|
||||
t = {}
|
||||
if ff.name.find(filename) > -1:
|
||||
t['filename'] = path + '/' + ff.name
|
||||
l.append(t)
|
||||
return l
|
||||
|
||||
|
||||
def backupAllFunc(stype):
|
||||
if not isAuthApi():
|
||||
mw.echoInfo("未授权API,无法使用!!!")
|
||||
return ''
|
||||
|
||||
os.chdir(mw.getRunDir())
|
||||
backup_dir = mw.getBackupDir()
|
||||
run_dir = mw.getRunDir()
|
||||
|
||||
stype = sys.argv[1]
|
||||
name = sys.argv[2]
|
||||
num = sys.argv[3]
|
||||
|
||||
prefix_dict = {
|
||||
"site": "web",
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
|
||||
backups = []
|
||||
sql = db.Sql()
|
||||
|
||||
# print("stype:", stype)
|
||||
# 提前获取-清理多余备份
|
||||
if stype == 'site':
|
||||
pid = sql.table('sites').where('name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('0', pid)).field('id,filename').select()
|
||||
if stype == 'database':
|
||||
db_path = mw.getServerDir() + '/mysql'
|
||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
|
||||
'name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
if stype == 'path':
|
||||
backup_path = backup_dir + '/path'
|
||||
_name = 'path_{}'.format(os.path.basename(name))
|
||||
backups = findPathName(backup_path, _name)
|
||||
|
||||
# 其他类型关系性数据库(mysql类的)
|
||||
if stype.find('database_') > -1:
|
||||
plugin_name = stype.replace('database_', '')
|
||||
db_path = mw.getServerDir() + '/' + plugin_name
|
||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
|
||||
'name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
|
||||
args = stype + " " + name + " " + num
|
||||
cmd = 'python3 ' + run_dir + '/scripts/backup.py ' + args
|
||||
if stype.find('database_') > -1:
|
||||
plugin_name = stype.replace('database_', '')
|
||||
args = "database " + name + " " + num
|
||||
cmd = 'python3 ' + run_dir + '/plugins/' + \
|
||||
plugin_name + '/scripts/backup.py ' + args
|
||||
|
||||
if stype == 'path':
|
||||
name = os.path.basename(name)
|
||||
|
||||
# print("cmd:", cmd)
|
||||
os.system(cmd)
|
||||
|
||||
# 开始执行上传信息.
|
||||
if stype.find('database_') > -1:
|
||||
bk_name = 'database'
|
||||
plugin_name = stype.replace('database_', '')
|
||||
bk_prefix = plugin_name + '/db'
|
||||
stype = 'database'
|
||||
else:
|
||||
bk_prefix = prefix_dict[stype]
|
||||
bk_name = stype
|
||||
|
||||
find_path = backup_dir + '/' + bk_name + '/' + bk_prefix + '_' + name
|
||||
find_new_file = "ls " + find_path + \
|
||||
"_* | grep '.gz' | cut -d \ -f 1 | awk 'END {print}'"
|
||||
|
||||
# print(find_new_file)
|
||||
|
||||
filename = mw.execShell(find_new_file)[0].strip()
|
||||
if filename == "":
|
||||
mw.echoInfo("not find upload file!")
|
||||
return False
|
||||
|
||||
mw.echoInfo("准备上传文件 {}".format(filename))
|
||||
mw.echoStart('开始上传')
|
||||
gd.upload_file(filename, stype)
|
||||
mw.echoEnd('上传成功')
|
||||
|
||||
# print(backups)
|
||||
backups = sorted(backups, key=lambda x: x['filename'], reverse=False)
|
||||
mw.echoStart('开始删除远程备份')
|
||||
num = int(num)
|
||||
sep = len(backups) - num
|
||||
if sep > -1:
|
||||
for backup in backups:
|
||||
fn = os.path.basename(backup['filename'])
|
||||
gd.delete_file(fn, stype)
|
||||
mw.echoInfo("---已清理远程过期备份文件:" + fn)
|
||||
sep -= 1
|
||||
if sep < 0:
|
||||
break
|
||||
mw.echoEnd('结束删除远程备份')
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
def installPreInspection():
|
||||
return 'ok'
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print(status())
|
||||
elif func == 'start':
|
||||
print(start())
|
||||
elif func == 'stop':
|
||||
print(stop())
|
||||
elif func == 'restart':
|
||||
print(restart())
|
||||
elif func == 'reload':
|
||||
print(reload())
|
||||
elif func == 'install_pre_inspection':
|
||||
print(installPreInspection())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'set_auth_url':
|
||||
print(setAuthUrl())
|
||||
elif func == 'clear_auth':
|
||||
print(clearAuth())
|
||||
elif func == "get_list":
|
||||
print(getList())
|
||||
elif func == "create_dir":
|
||||
print(createDir())
|
||||
elif func == "delete_dir":
|
||||
print(deleteDir())
|
||||
elif func == 'delete_file':
|
||||
print(deleteFile())
|
||||
elif in_array(func, ['site', 'database', 'path']) or func.find('database_') > -1:
|
||||
print(backupAllFunc(func))
|
||||
else:
|
||||
print('error')
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"hook":["backup"],
|
||||
"id":998,
|
||||
"title":"谷歌云网盘",
|
||||
"tip":"lib",
|
||||
"name":"gdrive",
|
||||
"type":"扩展",
|
||||
"ps":"备份你的数据到谷歌云网盘",
|
||||
"versions":"2.0",
|
||||
"shell":"install.sh",
|
||||
"checks": "server/gdrive",
|
||||
"path":"server/gdrive",
|
||||
"author":"google",
|
||||
"home":"https://drive.google.com/",
|
||||
"api_doc":"https://developers.google.com/drive/api/guides/about-sdk?hl=zh_CN",
|
||||
"api_doc2":"https://developers.google.cn/drive/api/reference/rest/v3/comments/list?hl=zh-cn",
|
||||
"date":"2022-06-26",
|
||||
"pid":"4"
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
|
||||
PATH=$PATH:${rootPath}/bin
|
||||
export PATH
|
||||
|
||||
VERSION=$2
|
||||
|
||||
Install_App()
|
||||
{
|
||||
tmp_ping=`ping -c 1 google.com 2>&1`
|
||||
echo $tmp_ping
|
||||
if [ $? -eq 0 ];then
|
||||
tmp=`python -V 2>&1|awk '{print $2}'`
|
||||
pVersion=${tmp:0:3}
|
||||
|
||||
which pip
|
||||
if [ $? -eq 0 ];then
|
||||
tmp=$(pip list|grep google-api-python-client|awk '{print $2}')
|
||||
if [ "$tmp" != '2.39.0' ];then
|
||||
pip install --upgrade google-api-python-client
|
||||
# pip uninstall google-api-python-client -y
|
||||
pip install -I google-api-python-client==2.39.0 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
tmp=$(pip list|grep google-auth-httplib2|awk '{print $2}')
|
||||
if [ "$tmp" != '0.1.0' ];then
|
||||
pip uninstall google-auth-httplib2 -y
|
||||
pip install -I google-auth-httplib2==0.1.0 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
tmp=$(pip list|grep google-auth-oauthlib|awk '{print $2}')
|
||||
if [ "$tmp" != '0.5.0' ];then
|
||||
# pip uninstall google-auth-oauthlib -y
|
||||
pip install -I google-auth-oauthlib==0.5.0 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
tmp=$(pip list|grep -E '^httplib2'|awk '{print $2}')
|
||||
if [ "$tmp" != '0.18.1' ];then
|
||||
# pip uninstall httplib2 -y
|
||||
pip install -I httplib2==0.18.1 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
else
|
||||
pip install -I pyOpenSSL
|
||||
pip install -I google-api-python-client==2.39.0 google-auth-httplib2==0.1.0 google-auth-oauthlib==0.5.0 -i https://pypi.Python.org/simple
|
||||
pip install -I httplib2==0.18.1 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
|
||||
mkdir -p $serverPath/gdrive
|
||||
echo "${VERSION}" > $serverPath/gdrive/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
else
|
||||
echo '服务器连接不上谷歌云!安装失败!' > $install_tmp
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
rm -rf $serverPath/gdrive
|
||||
echo '卸载完成' > $install_tmp
|
||||
}
|
||||
|
||||
|
||||
action=$1
|
||||
type=$2
|
||||
|
||||
echo $action $type
|
||||
if [ "${action}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
@@ -0,0 +1,260 @@
|
||||
|
||||
function gdPost(method,args,callback){
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
$.post('/plugins/run', {name:'gdrive', func:method, args:_args}, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
|
||||
function createDir(){
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "400px",
|
||||
title: "创建目录",
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
btn: ['确定','取消'],
|
||||
content:'<div class="bingfa bt-form c6" style="padding-bottom: 10px;">\
|
||||
<p>\
|
||||
<span class="span_tit">目录名称:</span>\
|
||||
<input style="width: 200px;" type="text" name="newPath" value="">\
|
||||
</p>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$("input[name='newPath']").focus().keyup(function(e){
|
||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
||||
});
|
||||
},
|
||||
yes:function(index,layero){
|
||||
var name = $("input[name='newPath']").val();
|
||||
if(name == ''){
|
||||
layer.msg('目录名称不能为空!',{icon:2});
|
||||
return;
|
||||
}
|
||||
var parents = $("#myPath").val();
|
||||
var cur_file_id = $('#curPath').val();
|
||||
if (cur_file_id!=''){
|
||||
parents = cur_file_id;
|
||||
}
|
||||
|
||||
var dirname = name;
|
||||
var loadT = layer.msg('正在创建目录['+dirname+']...',{icon:16,time:0,shade: [0.3, '#000']});
|
||||
gdPost('create_dir', {parents:parents,name:dirname}, function(data){
|
||||
layer.close(loadT);
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if(rdata.status) {
|
||||
showMsg(rdata.msg, function(){
|
||||
layer.close(index);
|
||||
var file_id = $('#myPath').val();
|
||||
if (cur_file_id!=''){
|
||||
file_id = cur_file_id;
|
||||
}
|
||||
gdList(file_id);
|
||||
} ,{icon:1}, 2000);
|
||||
} else{
|
||||
layer.msg(rdata.msg,{icon:2});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//设置API
|
||||
function authApi(){
|
||||
|
||||
gdPost('conf', {}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
|
||||
// console.log(rdata);
|
||||
// console.log(rdata.data.auth_url);
|
||||
var apicon = '';
|
||||
if (rdata.status){
|
||||
|
||||
var html = '';
|
||||
html += '<button id="clear_auth" onclick="clearAuth();" class="btn btn-default btn-sm">清空配置</button>';
|
||||
|
||||
var loadOpen = layer.open({
|
||||
type: 1,
|
||||
title: '已授权',
|
||||
area: '240px',
|
||||
content:'<div class="change-default pd20">'+html+'</div>',
|
||||
success: function(){
|
||||
$('#clear_auth').click(function(){
|
||||
gdPost('clear_auth', {}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
layer.close(loadOpen);
|
||||
gdList('');
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
|
||||
} else{
|
||||
apicon = '<div class="new_form">'+$("#check_api").html()+'</div>';
|
||||
}
|
||||
|
||||
var layer_auth = layer.open({
|
||||
type: 1,
|
||||
area: "620px",
|
||||
title: "Google Drive 授权",
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
content:apicon,
|
||||
success:function(layero,index){
|
||||
// console.log(layero,index);
|
||||
if (!rdata.status){
|
||||
$('.check_api .step_two_url').val(rdata.data['auth_url']);
|
||||
$('.check_api .open_btlink').attr('href',rdata.data['auth_url']);
|
||||
|
||||
$('.check_api .ico-copy').click(function(){
|
||||
copyPass(rdata.data['auth_url']);
|
||||
});
|
||||
|
||||
$('.check_api .set_auth_btn').click(function(){
|
||||
|
||||
var url = $('.check_api .google_drive').val();
|
||||
if ( url == ''){
|
||||
layer.msg("验证URL不能为空",{icon:2});
|
||||
return;
|
||||
}
|
||||
// console.log(url);
|
||||
gdPost('set_auth_url', {url:url}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
var show_time = 2000;
|
||||
if (!rdata.status){
|
||||
show_time = 10000;
|
||||
}
|
||||
|
||||
showMsg(rdata.msg,function(){
|
||||
if (rdata.status){
|
||||
layer.close(layer_auth);
|
||||
gdList('');
|
||||
}
|
||||
},{icon:rdata.status?1:2},show_time);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//计算当前目录偏移
|
||||
function upPathLeft(){
|
||||
var UlWidth = $(".place-input ul").width();
|
||||
var SpanPathWidth = $(".place-input").width() - 20;
|
||||
var Ml = UlWidth - SpanPathWidth;
|
||||
if(UlWidth > SpanPathWidth ){
|
||||
$(".place-input ul").css("left",-Ml)
|
||||
}
|
||||
else{
|
||||
$(".place-input ul").css("left",0)
|
||||
}
|
||||
}
|
||||
|
||||
function getGDTime(a) {
|
||||
return new Date(a).format("yyyy/MM/dd hh:mm:ss")
|
||||
}
|
||||
|
||||
function gdList(file_id){
|
||||
$('#curPath').val(file_id);
|
||||
gdPost('get_list', {file_id:file_id}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
console.log(rdata);
|
||||
if(rdata.status === false){
|
||||
showMsg(rdata.msg,function(){
|
||||
authApi();
|
||||
},{icon:2},2000);
|
||||
return;
|
||||
}
|
||||
|
||||
var mlist = rdata.data;
|
||||
var listBody = '';
|
||||
var listFiles = '';
|
||||
for(var i=0;i<mlist.length;i++){
|
||||
if(mlist[i].size == null){
|
||||
listFiles += '<tr><td class="cursor" onclick="gdList(\''+(mlist[i].id).replace('//','/')+'\')"><span class="ico ico-folder"></span>\<span>'+mlist[i].name+'</span></td>\
|
||||
<td>-</td>\
|
||||
<td>-</td>\
|
||||
<td class="text-right"><a class="btlink" onclick="deleteFile(\''+mlist[i].id+'\', true)">删除</a></td></tr>'
|
||||
}else{
|
||||
listFiles += '<tr><td class="cursor"><span class="ico ico-file"></span><span>'+mlist[i].name+'</span></td>\
|
||||
<td>'+toSize(mlist[i].size)+'</td>\
|
||||
<td>'+getGDTime(mlist[i].createdTime)+'</td>\
|
||||
<td class="text-right"><a target="_blank" href="'+mlist[i].webViewLink+'" class="btlink">下载</a> | <a class="btlink" onclick="deleteFile(\''+mlist[i].name+'\', false)">删除</a></td></tr>'
|
||||
}
|
||||
}
|
||||
listBody += listFiles;
|
||||
var pathLi = '<li><a title="根目录" onclick="gdList(\'\')">根目录</a></li>';
|
||||
|
||||
if (mlist.length>0){
|
||||
$('#myPath').val(mlist[0]['parents'][0]);
|
||||
}
|
||||
|
||||
$(".upyunCon .place-input ul").html(pathLi);
|
||||
$(".upyunlist .list-list").html(listBody);
|
||||
|
||||
$('#backBtn').unbind().click(function() {
|
||||
gdList('');
|
||||
});
|
||||
|
||||
$('.upyunCon .refreshBtn').unbind().click(function(){
|
||||
var file_id = $('#myPath').val();
|
||||
gdList(file_id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//删除文件
|
||||
function deleteFile(name, is_dir){
|
||||
if (is_dir === false){
|
||||
safeMessage('删除文件','删除后将无法恢复,真的要删除['+name+']吗?',function(){
|
||||
var path = $("#myPath").val();
|
||||
var filename = name;
|
||||
gdPost('delete_file', {filename:filename,path:path}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
var file_id = $('#myPath').val();
|
||||
gdList(file_id);
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
safeMessage('删除文件夹','删除后将无法恢复,真的要删除文件资源['+name+']吗?',function(){
|
||||
var path = $("#myPath").val();
|
||||
gdPost('delete_dir', {dir_name:name,path:path}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
var file_id = $('#myPath').val();
|
||||
gdList(file_id);
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
# python3 plugins/gdrive/t/test.py
|
||||
# https://console.cloud.google.com/apis/credentials/consent?project=plated-inn-369901
|
||||
|
||||
# https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=226011946234-d3e1vashgag64utjedu1ljt9u39ncrpq.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fdrive.aapanel.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&state=I2da4aZUwqgmikrgrqAwwSjyoEHVs1&access_type=offline&prompt=consent&include_granted_scopes=false
|
||||
|
||||
|
||||
# https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/08125e6b-6502-4ac9-9548-ad682f00848d/objectId/62b1d655-9828-47ed-be99-65eb18c3a929/isMSAApp~/false/defaultBlade/Overview/appSignInAudience/AzureADandPersonalMicrosoftAccount/servicePrincipalCreated~/true
|
||||
|
||||
# 0WA8Q~sZkZFZKv50ryP4ux~.fpVtbHw7BuTZmbQB
|
||||
# client_id:d9878fac-8526-4ff6-8036-e1c92dd9dd80
|
||||
|
||||
# 08125e6b-6502-4ac9-9548-ad682f00848d
|
||||
|
||||
|
||||
# /drive/v2internal/files?openDrive=false&reason=102&syncType=0&errorRecovery=false&q=trashed = false and '1-z6gUXseXmlxmntvkLzOe_tYFT5tdhM9' in parents&fields=kind,nextPageToken,items(kind,modifiedDate,hasVisitorPermissions,containsUnsubscribedChildren,modifiedByMeDate,lastViewedByMeDate,alternateLink,fileSize,owners(kind,permissionId,emailAddressFromAccount,id),lastModifyingUser(kind,permissionId,emailAddressFromAccount,id),customerId,ancestorHasAugmentedPermissions,hasThumbnail,thumbnailVersion,title,id,resourceKey,abuseIsAppealable,abuseNoticeReason,shared,accessRequestsCount,sharedWithMeDate,userPermission(role),explicitlyTrashed,mimeType,quotaBytesUsed,copyable,subscribed,folderColor,hasChildFolders,fileExtension,primarySyncParentId,sharingUser(kind,permissionId,emailAddressFromAccount,id),flaggedForAbuse,folderFeatures,spaces,sourceAppId,recency,recencyReason,version,actionItems,teamDriveId,hasAugmentedPermissions,createdDate,primaryDomainName,organizationDisplayName,passivelySubscribed,trashingUser(kind,permissionId,emailAddressFromAccount,id),trashedDate,parents(id),capabilities(canMoveItemIntoTeamDrive,canUntrash,canModifyContentRestriction,canMoveItemWithinTeamDrive,canMoveItemOutOfTeamDrive,canDeleteChildren,canTrashChildren,canRequestApproval,canReadCategoryMetadata,canEditCategoryMetadata,canAddMyDriveParent,canRemoveMyDriveParent,canShareChildFiles,canShareChildFolders,canRead,canMoveItemWithinDrive,canMoveChildrenWithinDrive,canAddFolderFromAnotherDrive,canChangeSecurityUpdateEnabled,canBlockOwner,canReportSpamOrAbuse,canCopy,canDownload,canEdit,canAddChildren,canDelete,canRemoveChildren,canShare,canTrash,canRename,canReadTeamDrive,canMoveTeamDriveItem),contentRestrictions(readOnly),approvalMetadata(approvalVersion,approvalSummaries,hasIncomingApproval),shortcutDetails(targetId,targetMimeType,targetLookupStatus,targetFile,canRequestAccessToTarget),spamMetadata(markedAsSpamDate,inSpamView),labels(starred,trashed,restricted,viewed)),incompleteSearch&appDataFilter=NO_APP_DATA&spaces=drive&maxResults=200&supportsTeamDrives=true&includeItemsFromAllDrives=true&corpora=default&orderBy=folder,title_natural asc&retryCount=0&key=AIzaSyD_InbmSFufIEps5UAt2NmB_3LvBH3Sz_8 HTTP/1.1
|
||||
|
||||
# http://localhost/?code=M.C106_BAY.2.3e12c859-6107-0c5b-9ef4-14b3fb8269ba&state=JzHdzHXmA7x6zl7Be6cJ6uOlf9Bg69
|
||||
|
||||
|
||||
# python3 /www/mdserver-web/plugins/gdrive/index.py site zzzvps.com 3
|
||||
# python3 /www/mdserver-web/plugins/gdrive/index.py database t1 3
|
||||
# python3 /www/server/mdserver-web/plugins/msonedrive/index.py path
|
||||
# /Users/midoks/Desktop/dev/python 3
|
||||
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'gdrive'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
# print(getPluginDir())
|
||||
sys.path.append(getPluginDir() + "/class")
|
||||
from gdriveclient import gdriveclient
|
||||
|
||||
|
||||
gd = gdriveclient(getPluginDir(), getServerDir())
|
||||
gd.setDebug(True)
|
||||
# sign_in_url, state = gd.get_sign_in_url()
|
||||
# print(sign_in_url)
|
||||
|
||||
# url = 'https://localhost/?state=GH2YZ1VeytzVB1BqJJpQZIBk2GGAub&code=4/0Adeu5BXnD2dQvXx8Sg0WPn1XiMpihcRBNaG1yaFKIo86gUiG7q65KU1MaNCxrj_f2bjkwQ&scope=https://www.googleapis.com/auth/drive.file'
|
||||
# t = gd.set_auth_url(url)
|
||||
# print(t)
|
||||
|
||||
# def set_auth_url(url):
|
||||
# try:
|
||||
# if url.startswith("http://"):
|
||||
# url = url.replace("http://", "https://")
|
||||
# token = msodc.get_token_from_authorized_url(
|
||||
# authorized_url=url)
|
||||
# msodc.store_token(token)
|
||||
# msodc.store_user()
|
||||
# return mw.returnJson(True, "授权成功!")
|
||||
# except Exception as e:
|
||||
# print(e)
|
||||
# return mw.returnJson(False, "授权失败2!:" + str(e))
|
||||
# return mw.returnJson(False, "授权失败!:" + str(e))
|
||||
|
||||
# url = 'http://localhost/?code=M.C106_BAY.2.310112f3-a158-c400-9667-d158cbd1de6c&state=jEJz0ucR9bpZYD9PGxp2GgRDotrzO6'
|
||||
# token = set_auth_url(url)
|
||||
# print(token)
|
||||
|
||||
# token = msodc.get_token()
|
||||
# print("token:", token)
|
||||
|
||||
# t = gd.get_list('')
|
||||
# print(t)
|
||||
|
||||
# t = gd.get_id_list('1u7LjXGj1KoN-ltAdTRaib7IZJpsEnPdz')
|
||||
# print(t)
|
||||
|
||||
# t = gd.create_folder('backup_demo')
|
||||
# print(t)
|
||||
|
||||
# t = msodc.delete_object('backup')
|
||||
# print(t)
|
||||
|
||||
|
||||
# t = gd.upload_file('web_t1.cn_20230830_134549.tar.gz', 'site')
|
||||
# print(t)
|
||||
# print(gd.error_msg)
|
||||
|
||||
# /Users/midoks/Desktop/mwdev/server/mdserver-web/paramiko.log
|
||||
# backup/site/paramiko.log
|
||||
# |-正在上传到 backup/site/paramiko.log...
|
||||
# True
|
||||
|
||||
|
||||
t = gd.upload_file(
|
||||
'db_zzzvps_20230830_210727.sql.gz', 'datebase')
|
||||
print(t)
|
||||
@@ -406,6 +406,11 @@ class msodclient:
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
|
||||
if not prefix_dict.get(data_type):
|
||||
print("data_type 类型错误!!!")
|
||||
exit(1)
|
||||
|
||||
file_regx = prefix_dict.get(data_type) + "_(.+)_20\d+_\d+(?:\.|_)"
|
||||
sub_search = re.search(file_regx, file_name)
|
||||
sub_path_name = ""
|
||||
|
||||
Reference in New Issue
Block a user