2016-10-11 2 views
6

Можно ли загрузить файл в Общие документы библиотеки из сайта Microsoft SharePoint с Python OneDrive SDK?Загрузить файл в MS SharePoint с помощью Python OneDrive SDK

This documentation говорит, что это должно быть (в первом предложении), но я не могу заставить его работать.

Я могу проверить подлинность (с Azure AD) и загрузить в папку с OneDrive, но при попытке загрузить в папкуSharePoint, я получаю эту ошибку:

"Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown."

код, я использую, который возвращает объект с ошибкой:

(...authentication...) 
client = onedrivesdk.OneDriveClient('https://{tenant}.sharepoint.com/{site}/_api/v2.0/', auth, http) 
client.item(path='/drive/special/documents').children['test.xlsx'].upload('test.xlsx') 

where I'd like to upload on the web

Я могу успешно загрузить на https://{tenant}-my.sharepoint.com/_api/v2.0/ (обратите внимание на «-Мой» после {tenant}) со следующим кодом:

client = onedrivesdk.OneDriveClient('https://{tenant}-my.sharepoint.com/_api/v2.0/', auth, http) 
returned_item = client.item(drive='me', id='root').children['test.xlsx'].upload('test.xlsx') 

Как я мог загрузить один и тот же файл на сайт SharePoint?

(Ответы на подобные вопросы (1, 2, 3, 4) на переполнение стека либо слишком расплывчатым или предлагают использовать другой API. Мой вопрос, если это возможно с помощью OneDrive Python SDK, и если да, то как чтобы сделать это)


Update:. Вот мой полный код и выход. (Чувствительные исходные данные заменяются аналогично отформатированного бредом.)

import re 
import onedrivesdk 
from onedrivesdk.helpers.resource_discovery import ResourceDiscoveryRequest 

# our domain (not the original) 
redirect_uri = 'https://example.ourdomain.net/' 
# our client id (not the original) 
client_id = "a1234567-1ab2-1234-a123-ab1234abc123" 
# our client secret (not the original) 
client_secret = 'ABCaDEFGbHcd0e1I2fghJijkL3mn4M5NO67P8Qopq+r=' 
resource = 'https://api.office.com/discovery/' 
auth_server_url = 'https://login.microsoftonline.com/common/oauth2/authorize' 
auth_token_url = 'https://login.microsoftonline.com/common/oauth2/token' 
http = onedrivesdk.HttpProvider() 
auth = onedrivesdk.AuthProvider(http_provider=http, client_id=client_id, 
           auth_server_url=auth_server_url, 
           auth_token_url=auth_token_url) 

should_authenticate_via_browser = False 
try: 
    # Look for a saved session. If not found, we'll have to 
    # authenticate by opening the browser. 
    auth.load_session() 
    auth.refresh_token() 
except FileNotFoundError as e: 
    should_authenticate_via_browser = True 
    pass 

if should_authenticate_via_browser: 
    auth_url = auth.get_auth_url(redirect_uri) 
    code = '' 
    while not re.match(r'[a-zA-Z0-9_-]+', code): 
     # Ask for the code 
     print('Paste this URL into your browser, approve the app\'s access.') 
     print('Copy the resulting URL and paste it below.') 
     print(auth_url) 
     code = input('Paste code here: ') 
     # Parse code from URL if necessary 
     if re.match(r'.*?code=([a-zA-Z0-9_-]+).*', code): 
      code = re.sub(r'.*?code=([a-zA-Z0-9_-]*).*', r'\1', code) 
    auth.authenticate(code, redirect_uri, client_secret, resource=resource) 
    # If you have access to more than one service, you'll need to decide 
    # which ServiceInfo to use instead of just using the first one, as below. 
    service_info = ResourceDiscoveryRequest().get_service_info(auth.access_token)[0] 
    auth.redeem_refresh_token(service_info.service_resource_id) 
    auth.save_session() # Save session into a local file. 

# Doesn't work 
client = onedrivesdk.OneDriveClient(
    'https://{tenant}.sharepoint.com/sites/{site}/_api/v2.0/', auth, http) 
returned_item = client.item(path='/drive/special/documents') 
         .children['test.xlsx'] 
         .upload('test.xlsx') 
print(returned_item._prop_dict['error_description']) 

# Works, uploads to OneDrive instead of SharePoint site 
client2 = onedrivesdk.OneDriveClient(
    'https://{tenant}-my.sharepoint.com/_api/v2.0/', auth, http) 
returned_item2 = client2.item(drive='me', id='root') 
         .children['test.xlsx'] 
         .upload('test.xlsx') 
print(returned_item2.web_url) 

Выход:

Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown. 
https://{tenant}-my.sharepoint.com/personal/user_domain_net/_layouts/15/WopiFrame.aspx?sourcedoc=%1ABCDE2345-67F8-9012-3G45-6H78IJKL9M01%2N&file=test.xlsx&action=default 
+0

Можете ли вы предоставить полную трассу? Или укажите, какая строка была источником ошибки, строка, начинающаяся с 'client' или' returns_item'? – sytech

+0

Также, вы [установите соответствующий AuthScope] (https://github.com/OneDrive/onedrive-api-docs/blob/master/site-images/AuthScopesForSharePoint.png?raw=true) для SharePoint Online? Это отдельно от ваших разрешений OneDrive. – sytech

+0

@Gator_Python - я добавил полный код. Ошибка не возникает, но возвращаемый объект содержит свойства загруженного файла в успешном случае и это сообщение об ошибке в неудачном случае. AuthScope установлен таким образом (на самом деле все разрешения отмечены галочкой). –

ответ

3

я, наконец, нашел решение, с помощью (SO пользователя) sytech.

Ответ на мой первоначальный вопрос в том, что с помощью оригинального Python OneDrive SDK, это не возможно, чтобы загрузить файл в Shared Documents папку с SharePoint Online сайта (на момент написания этого): когда SDK запрашивает resource discovery service, он отбрасывает все услуги, service_api_version - не v2.0. Тем не менее, я получаю службу SharePoint с v1.0, поэтому она отбрасывается, хотя к ней можно получить доступ и с помощью API v2.0.

Однако, расширяя класс ResourceDiscoveryRequest (в SDK OneDrive), мы можем создать обходной путь для этого.Мне удалось загрузить файл таким образом:

import json 
import re 
import onedrivesdk 
import requests 
from onedrivesdk.helpers.resource_discovery import ResourceDiscoveryRequest, \ 
    ServiceInfo 

# our domain (not the original) 
redirect_uri = 'https://example.ourdomain.net/' 
# our client id (not the original) 
client_id = "a1234567-1ab2-1234-a123-ab1234abc123" 
# our client secret (not the original) 
client_secret = 'ABCaDEFGbHcd0e1I2fghJijkL3mn4M5NO67P8Qopq+r=' 
resource = 'https://api.office.com/discovery/' 
auth_server_url = 'https://login.microsoftonline.com/common/oauth2/authorize' 
auth_token_url = 'https://login.microsoftonline.com/common/oauth2/token' 

# our sharepoint URL (not the original) 
sharepoint_base_url = 'https://{tenant}.sharepoint.com/' 
# our site URL (not the original) 
sharepoint_site_url = sharepoint_base_url + 'sites/{site}' 

file_to_upload = 'C:/test.xlsx' 
target_filename = 'test.xlsx' 


class AnyVersionResourceDiscoveryRequest(ResourceDiscoveryRequest): 

    def get_all_service_info(self, access_token, sharepoint_base_url): 
     headers = {'Authorization': 'Bearer ' + access_token} 
     response = json.loads(requests.get(self._discovery_service_url, 
              headers=headers).text) 
     service_info_list = [ServiceInfo(x) for x in response['value']] 
     # Get all services, not just the ones with service_api_version 'v2.0' 
     # Filter only on service_resource_id 
     sharepoint_services = \ 
      [si for si in service_info_list 
      if si.service_resource_id == sharepoint_base_url] 
     return sharepoint_services 


http = onedrivesdk.HttpProvider() 
auth = onedrivesdk.AuthProvider(http_provider=http, client_id=client_id, 
           auth_server_url=auth_server_url, 
           auth_token_url=auth_token_url) 

should_authenticate_via_browser = False 
try: 
    # Look for a saved session. If not found, we'll have to 
    # authenticate by opening the browser. 
    auth.load_session() 
    auth.refresh_token() 
except FileNotFoundError as e: 
    should_authenticate_via_browser = True 
    pass 

if should_authenticate_via_browser: 
    auth_url = auth.get_auth_url(redirect_uri) 
    code = '' 
    while not re.match(r'[a-zA-Z0-9_-]+', code): 
     # Ask for the code 
     print('Paste this URL into your browser, approve the app\'s access.') 
     print('Copy the resulting URL and paste it below.') 
     print(auth_url) 
     code = input('Paste code here: ') 
     # Parse code from URL if necessary 
     if re.match(r'.*?code=([a-zA-Z0-9_-]+).*', code): 
      code = re.sub(r'.*?code=([a-zA-Z0-9_-]*).*', r'\1', code) 

    auth.authenticate(code, redirect_uri, client_secret, resource=resource) 
    service_info = AnyVersionResourceDiscoveryRequest().\ 
     get_all_service_info(auth.access_token, sharepoint_base_url)[0] 
    auth.redeem_refresh_token(service_info.service_resource_id) 
    auth.save_session() 

client = onedrivesdk.OneDriveClient(sharepoint_site_url + '/_api/v2.0/', 
            auth, http) 
# Get the drive ID of the Documents folder. 
documents_drive_id = [x['id'] 
         for x 
         in client.drives.get()._prop_list 
         if x['name'] == 'Documents'][0] 
items = client.item(drive=documents_drive_id, id='root') 
# Upload file 
uploaded_file_info = items.children[target_filename].upload(file_to_upload) 

аутентификации для другой сервис дает вам другой маркер.

+0

Код выглядит хорошо, но код, который я пишу, должен быть автоматизирован, поэтому я не могу копировать и вставлять «код», сгенерированный браузером каждый раз, этот «код» истекает очень скоро. Итак, на основе вашего кода я изменил свой код, но независимо от того, что это v1.0 или v2.0, я все равно получаю пустой ответ ['value'] ..... Могу ли я спросить, знаете ли вы, что случилось с моим код? Вот мой код: https://github.com/hanhanwu/Basic_But_Useful/blob/master/one_drive_buz_test.py –

+0

@CherryWu - код выше _is_ автоматизирован. 'auth.save_session()' сохраняет информацию аутентификации в файл с именем 'session.pickle'. 'auth.load_session()' загружает это. Как это работает, при первом запуске этого кода он откроет окно браузера, где вам нужно будет войти в систему и скопировать и вставить URL-адрес после перенаправления обратно в консоль Python. Затем этот токен аутентификации сохраняется и следующий раз загружается без открытия браузера. Подробнее об этом можно прочитать в разделе «Сохранение и загрузка сеанса» [здесь] (https://github.com/OneDrive/onedrive-sdk-python). –

+0

Большое спасибо Attila, сегодня у меня нет времени попробовать это, но быстрый вопрос, код, который мы получили из браузера, имеет очень короткий срок службы, означает ли это, что «Сохранение и загрузка сеанса» в ваш код, что «код» больше не истекает? –

Смежные вопросы