add: OneDriveFileStorage
This commit is contained in:
@@ -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
@@ -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]()
|
||||
|
||||
Reference in New Issue
Block a user