add: OneDriveFileStorage

This commit is contained in:
Do1e
2023-08-18 20:00:48 +08:00
parent 6d2ab5c78e
commit 95ada5c62f
3 changed files with 230 additions and 1 deletions
+6
View File
@@ -17,6 +17,11 @@ default_value = {
's3_secret_access_key': '',
's3_bucket_name': '',
's3_endpoint_url': '',
'onedrive_domain': '',
'onedrive_client_id': '',
'onedrive_username': '',
'onedrive_password': '',
'onedrive_root_path': 'filebox_storage',
'admin_token': 'FileCodeBox2023',
'openUpload': 1,
'uploadSize': 1024 * 1024 * 10,
@@ -24,6 +29,7 @@ default_value = {
'uploadCount': 10,
'errorMinute': 1,
'errorCount': 1,
'port': 12345,
}
+87 -1
View File
@@ -5,6 +5,9 @@
import asyncio
import hashlib
import time
from pathlib import Path
import datetime
import re
import aioboto3
from fastapi import UploadFile
@@ -69,6 +72,88 @@ class S3FileStorage:
return result
class OneDriveFileStorage:
def __init__(self):
try:
import msal
from office365.graph_client import GraphClient
from office365.runtime.client_request_exception import ClientRequestException
except ImportError:
raise ImportError('请先安装`msal`和`Office365-REST-Python-Client`')
self.msal = msal
self.domain = settings.onedrive_domain
self.client_id = settings.onedrive_client_id
self.username = settings.onedrive_username
self.password = settings.onedrive_password
try:
client = GraphClient(self.acquire_token_pwd)
self.root_path = client.me.drive.root.get_by_path(settings.onedrive_root_path).get().execute_query()
except ClientRequestException as e:
if e.code == 'itemNotFound':
client.me.drive.root.create_folder(settings.onedrive_root_path)
self.root_path = client.me.drive.root.get_by_path(settings.onedrive_root_path).get().execute_query()
else:
raise e
except Exception as e:
raise Exception('OneDrive验证失败,请检查配置是否正确\n' + str(e))
def acquire_token_pwd(self):
authority_url = f'https://login.microsoftonline.com/{self.domain}'
app = self.msal.PublicClientApplication(
authority=authority_url,
client_id=self.client_id
)
result = app.acquire_token_by_username_password(username=self.username,
password=self.password,
scopes=['https://graph.microsoft.com/.default'])
return result
def _get_path_str(self, path):
if isinstance(path, str):
path = path.replace('\\', '/').replace('//', '/').split('/')
elif isinstance(path, Path):
path = str(path).replace('\\', '/').replace('//', '/').split('/')
else:
raise TypeError('path must be str or Path')
return '/'.join(path[:-1]), path[-1]
def _save(self, file, save_path):
content = file.read()
path, name = self._get_path_str(save_path)
self.root_path.get_by_path(path).upload(name, content).execute_query()
async def save_file(self, file: UploadFile, save_path: str):
await asyncio.to_thread(self._save, file.file, save_path)
def _delete(self, save_path):
path, name = self._get_path_str(save_path)
self.root_path.get_by_path(path + '/' + name).delete_object().execute_query()
async def delete_file(self, file_code: FileCodes):
await asyncio.to_thread(self._delete, await file_code.get_file_path())
def _convert_link_to_download_link(self, link):
p1 = re.search(r'https:\/\/(.+)\.sharepoint\.com', link).group(1)
p2 = re.search(r'personal\/(.+)\/', link).group(1)
p3 = re.search(rf'{p2}\/(.+)', link).group(1)
return f'https://{p1}.sharepoint.com/personal/{p2}/_layouts/52/download.aspx?share={p3}'
def _get_file_url(self, save_path):
path, name = self._get_path_str(save_path)
remote_file = self.root_path.get_by_path(path + '/' + name)
expiration_datetime = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(hours=1)
expiration_datetime = expiration_datetime.strftime("%Y-%m-%dT%H:%M:%SZ")
premission = remote_file.create_link("view", "anonymous", expiration_datetime=expiration_datetime).execute_query()
return self._convert_link_to_download_link(premission.link.webUrl)
async def get_file_url(self, file_code: FileCodes):
if file_code.prefix == '文本分享':
return file_code.text
result = await asyncio.to_thread(self._get_file_url, await file_code.get_file_path())
return result
class FileStorageTemplate:
def __init__(self):
...
@@ -85,6 +170,7 @@ class FileStorageTemplate:
storages = {
'local': SystemFileStorage,
's3': S3FileStorage
's3': S3FileStorage,
'onedrive': OneDriveFileStorage,
}
file_storage = storages[settings.file_storage]()