mirror of
https://github.com/arc53/DocsGPT.git
synced 2026-03-08 06:44:04 +00:00
(feat:oneDrive) rm shared file support, as sharedWithMe is degraded
This commit is contained in:
@@ -210,8 +210,7 @@ class ConnectorFiles(Resource):
|
||||
"folder_id": fields.String(required=False),
|
||||
"limit": fields.Integer(required=False),
|
||||
"page_token": fields.String(required=False),
|
||||
"search_query": fields.String(required=False),
|
||||
"shared": fields.Boolean(required=False)
|
||||
"search_query": fields.String(required=False)
|
||||
}))
|
||||
@api.doc(description="List files from a connector provider (supports pagination and search)")
|
||||
def post(self):
|
||||
@@ -223,8 +222,7 @@ class ConnectorFiles(Resource):
|
||||
limit = data.get('limit', 10)
|
||||
page_token = data.get('page_token')
|
||||
search_query = data.get('search_query')
|
||||
shared = data.get('shared', False)
|
||||
|
||||
|
||||
if not provider or not session_token:
|
||||
return make_response(jsonify({"success": False, "error": "provider and session_token are required"}), 400)
|
||||
|
||||
@@ -243,7 +241,6 @@ class ConnectorFiles(Resource):
|
||||
'session_token': session_token,
|
||||
'folder_id': folder_id,
|
||||
'page_token': page_token,
|
||||
'shared': shared
|
||||
}
|
||||
if search_query:
|
||||
input_config['search_query'] = search_query
|
||||
|
||||
@@ -18,6 +18,7 @@ class SharePointAuth(BaseConnectorAuth):
|
||||
|
||||
SCOPES = [
|
||||
"Files.Read",
|
||||
"Sites.Read.All",
|
||||
"User.Read",
|
||||
]
|
||||
|
||||
|
||||
@@ -132,17 +132,9 @@ class SharePointLoader(BaseConnectorLoader):
|
||||
load_content = not list_only
|
||||
page_token = inputs.get('page_token')
|
||||
search_query = inputs.get('search_query')
|
||||
shared = inputs.get('shared', False)
|
||||
self.next_page_token = None
|
||||
|
||||
if shared and not file_ids and not folder_id:
|
||||
documents = self._list_shared_items(
|
||||
limit=limit,
|
||||
load_content=load_content,
|
||||
page_token=page_token,
|
||||
search_query=search_query
|
||||
)
|
||||
elif file_ids:
|
||||
if file_ids:
|
||||
for file_id in file_ids:
|
||||
try:
|
||||
doc = self._load_file_by_id(file_id, load_content=load_content)
|
||||
@@ -266,87 +258,7 @@ class SharePointLoader(BaseConnectorLoader):
|
||||
logging.error(f"Error listing items under parent {parent_id}: {e}")
|
||||
return documents
|
||||
|
||||
def _list_shared_items(self, limit: int = 100, load_content: bool = False,
|
||||
page_token: Optional[str] = None,
|
||||
search_query: Optional[str] = None) -> List[Document]:
|
||||
self._ensure_valid_token()
|
||||
documents: List[Document] = []
|
||||
|
||||
try:
|
||||
url = f"{self.GRAPH_API_BASE}/me/drive/sharedWithMe"
|
||||
params = {'$top': min(100, limit) if limit else 100}
|
||||
if page_token:
|
||||
params['$skipToken'] = page_token
|
||||
|
||||
response = requests.get(url, headers=self._get_headers(), params=params)
|
||||
response.raise_for_status()
|
||||
results = response.json()
|
||||
|
||||
for item in results.get('value', []):
|
||||
remote = item.get('remoteItem', {})
|
||||
drive_id = remote.get('parentReference', {}).get('driveId')
|
||||
item_id = remote.get('id')
|
||||
name = remote.get('name', item.get('name', 'Unknown'))
|
||||
|
||||
if not drive_id or not item_id:
|
||||
continue
|
||||
|
||||
if search_query and search_query.lower() not in name.lower():
|
||||
continue
|
||||
|
||||
composite_id = f"{drive_id}:{item_id}"
|
||||
|
||||
if 'folder' in remote:
|
||||
doc_metadata = {
|
||||
'file_name': name,
|
||||
'mime_type': 'folder',
|
||||
'size': remote.get('size'),
|
||||
'created_time': remote.get('createdDateTime'),
|
||||
'modified_time': remote.get('lastModifiedDateTime'),
|
||||
'source': 'share_point',
|
||||
'is_folder': True
|
||||
}
|
||||
documents.append(Document(text="", doc_id=composite_id, extra_info=doc_metadata))
|
||||
elif 'file' in remote:
|
||||
mime_type = remote.get('file', {}).get('mimeType', 'application/octet-stream')
|
||||
if mime_type not in self.SUPPORTED_MIME_TYPES:
|
||||
continue
|
||||
|
||||
doc_metadata = {
|
||||
'file_name': name,
|
||||
'mime_type': mime_type,
|
||||
'size': remote.get('size'),
|
||||
'created_time': remote.get('createdDateTime'),
|
||||
'modified_time': remote.get('lastModifiedDateTime'),
|
||||
'source': 'share_point'
|
||||
}
|
||||
|
||||
if load_content:
|
||||
content = self._download_file_content(composite_id)
|
||||
if content is None:
|
||||
continue
|
||||
documents.append(Document(text=content, doc_id=composite_id, extra_info=doc_metadata))
|
||||
else:
|
||||
documents.append(Document(text="", doc_id=composite_id, extra_info=doc_metadata))
|
||||
|
||||
if limit and len(documents) >= limit:
|
||||
break
|
||||
|
||||
next_link = results.get('@odata.nextLink')
|
||||
if next_link:
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
parsed = urlparse(next_link)
|
||||
query_params = parse_qs(parsed.query)
|
||||
skiptoken_list = query_params.get('$skiptoken')
|
||||
self.next_page_token = skiptoken_list[0] if skiptoken_list else None
|
||||
else:
|
||||
self.next_page_token = None
|
||||
|
||||
return documents
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error listing shared items: {e}")
|
||||
return documents
|
||||
|
||||
|
||||
def _download_file_content(self, file_id: str) -> Optional[str]:
|
||||
|
||||
@@ -92,7 +92,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
const [authError, setAuthError] = useState<string>('');
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [userEmail, setUserEmail] = useState<string>('');
|
||||
const [shared, setShared] = useState(false);
|
||||
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
@@ -112,7 +111,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
folderId: string | null,
|
||||
pageToken?: string,
|
||||
searchQuery = '',
|
||||
isShared = false,
|
||||
) => {
|
||||
// Cancel any in-flight request so stale responses never overwrite new state
|
||||
abortControllerRef.current?.abort();
|
||||
@@ -135,9 +133,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
page_token: pageToken,
|
||||
search_query: searchQuery,
|
||||
};
|
||||
if (isShared) {
|
||||
body.shared = true;
|
||||
}
|
||||
const response = await fetch(`${apiHost}/api/connectors/files`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -223,7 +218,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
name: getProviderConfig(provider).rootName,
|
||||
},
|
||||
]);
|
||||
loadCloudFiles(sessionToken, null, undefined, '', false);
|
||||
loadCloudFiles(sessionToken, null, undefined, '');
|
||||
} else {
|
||||
removeSessionToken(provider);
|
||||
setIsConnected(false);
|
||||
@@ -258,7 +253,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
currentFolderId,
|
||||
nextPageToken,
|
||||
searchQuery,
|
||||
shared,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -270,7 +264,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
searchQuery,
|
||||
provider,
|
||||
loadCloudFiles,
|
||||
shared,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -300,7 +293,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
searchTimeoutRef.current = setTimeout(() => {
|
||||
const sessionToken = getSessionToken(provider);
|
||||
if (sessionToken) {
|
||||
loadCloudFiles(sessionToken, currentFolderId, undefined, query, shared);
|
||||
loadCloudFiles(sessionToken, currentFolderId, undefined, query);
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
@@ -318,7 +311,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
|
||||
const sessionToken = getSessionToken(provider);
|
||||
if (sessionToken) {
|
||||
loadCloudFiles(sessionToken, folderId, undefined, '', shared);
|
||||
loadCloudFiles(sessionToken, folderId, undefined, '');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -334,27 +327,11 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
|
||||
const sessionToken = getSessionToken(provider);
|
||||
if (sessionToken) {
|
||||
loadCloudFiles(sessionToken, newFolderId, undefined, '', shared);
|
||||
loadCloudFiles(sessionToken, newFolderId, undefined, '');
|
||||
}
|
||||
};
|
||||
|
||||
const handleTabSwitch = (isShared: boolean) => {
|
||||
if (isShared === shared) return;
|
||||
setShared(isShared);
|
||||
setFiles([]);
|
||||
setCurrentFolderId(null);
|
||||
setSearchQuery('');
|
||||
setNextPageToken(null);
|
||||
setHasMoreFiles(false);
|
||||
const rootName = isShared
|
||||
? t('filePicker.sharedWithMe')
|
||||
: getProviderConfig(provider).rootName;
|
||||
setFolderPath([{ id: null, name: rootName }]);
|
||||
const sessionToken = getSessionToken(provider);
|
||||
if (sessionToken) {
|
||||
loadCloudFiles(sessionToken, null, undefined, '', isShared);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleFileSelect = (fileId: string, isFolder: boolean) => {
|
||||
if (isFolder) {
|
||||
@@ -387,7 +364,7 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
|
||||
if (data.session_token) {
|
||||
setSessionToken(provider, data.session_token);
|
||||
loadCloudFiles(data.session_token, null, undefined, '', shared);
|
||||
loadCloudFiles(data.session_token, null, undefined, '');
|
||||
}
|
||||
}}
|
||||
onError={(error) => {
|
||||
@@ -433,30 +410,6 @@ export const FilePicker: React.FC<CloudFilePickerProps> = ({
|
||||
{isConnected && (
|
||||
<div className="mt-3 overflow-hidden rounded-lg border border-[#D7D7D7] dark:border-[#6A6A6A]">
|
||||
<div className="rounded-t-lg border-[#EEE6FF78] dark:border-[#6A6A6A]">
|
||||
{provider === 'share_point' && (
|
||||
<div className="flex border-b border-[#D7D7D7] dark:border-[#6A6A6A]">
|
||||
<button
|
||||
onClick={() => handleTabSwitch(false)}
|
||||
className={`px-4 py-2 text-sm font-medium ${
|
||||
!shared
|
||||
? 'border-b-2 border-[#A076F6] text-[#A076F6]'
|
||||
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
>
|
||||
{t('filePicker.myFiles')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleTabSwitch(true)}
|
||||
className={`px-4 py-2 text-sm font-medium ${
|
||||
shared
|
||||
? 'border-b-2 border-[#A076F6] text-[#A076F6]'
|
||||
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300'
|
||||
}`}
|
||||
>
|
||||
{t('filePicker.sharedWithMe')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div className="rounded-t-lg bg-[#EEE6FF78] px-4 pt-4 dark:bg-[#2A262E]">
|
||||
<div className="mb-2 flex items-center gap-1">
|
||||
{folderPath.map((path, index) => (
|
||||
|
||||
Reference in New Issue
Block a user