2016-10-11 18 views
6

Czy to możliwe, aby przesłać plik do biblioteki Dokumenty udostępnione z Microsoft SharePoint miejscu z Python OneDrive SDK?Prześlij plik do MS SharePoint przy użyciu Pythona onedrive SDK

This documentation mówi, że powinno być (w pierwszym zdaniu), ale nie mogę sprawić, żeby działało.

Jestem w stanie uwierzytelnić (z Azure AD) i przesłać do folderu onedrive, ale gdy próbuje przesłać do folderu SharePoint, wciąż otrzymuję ten błąd:

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

Kod używam, która zwraca obiekt z błędem:

(...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

mogę skutecznie przesyłać do https://{tenant}-my.sharepoint.com/_api/v2.0/ (zawiadomienie „-my” Po {tenant}) za pomocą następującego kodu:

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') 

Jak mogę przesłać ten sam plik do SharePoint miejscu?

(Odpowiedzi na podobne pytania (1, 2, 3, 4) na przepełnienie stosu są albo zbyt ogólnikowe lub sugerują, używając innego API. Moje pytanie brzmi, czy jest to możliwe przy użyciu onedrive Pythona SDK, a jeśli tak, to w jaki sposób aby to zrobić)


Aktualizacja. Oto mój pełny kod i wyjście. (wrażliwe oryginalne dane zastąpiony podobnie sformatowane bezsensownego.)

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) 

wyjściowa:

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

Czy możesz podać pełne informacje zwrotne? Lub określić, która linia była źródłem błędu linii zaczynającej się od 'client' lub' return_item'? – sytech

+0

Masz również [ustaw odpowiedni AuthScope] (https://github.com/OneDrive/onedrive-api-docs/blob/master/site-images/AuthScopesForSharePoint.png?raw=true) na SharePoint Online? Jest to oddzielne od uprawnień do usługi OneDrive. – sytech

+0

@Gator_Python - dodałem pełny kod. Nie zgłoszono żadnego błędu, ale zwracany obiekt zawiera właściwości przesłanego pliku w przypadku zakończonym sukcesem, a ten komunikat o błędzie w przypadku nieudanym. AuthScope jest ustawiony w ten sposób (w rzeczywistości wszystkie prawa są zaznaczone). –

Odpowiedz

3

końcu znaleźć rozwiązanie, za pomocą (SO użytkownika) sytech.

Odpowiedź do mojego pierwotnego pytania jest to, że przy użyciu oryginalnego Python OneDrive SDK, to niemożliwe załadować plik do folderu Shared Documents z SharePoint Online miejscu (w momencie pisania tego): gdy SDK odpytuje resource discovery service, zrzuca wszystkie usługi, których service_api_version nie jest v2.0. Dostaję jednak usługę SharePoint pod numerem v1.0, więc jest ona pomijana, chociaż można uzyskać do niej dostęp za pomocą interfejsu API v2.0.

Jednak, rozszerzając klasę ResourceDiscoveryRequest (w pakiecie OneDrive SDK), możemy utworzyć obejście tego problemu.Udało mi się przesłać plik w ten sposób:

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) 

Uwierzytelnianie inna usługa daje inny znak.

+0

Kod wygląda dobrze, ale kod, który piszę, musi być zautomatyzowany, więc nie mogę skopiować i wkleić "kodu" wygenerowanego przez przeglądarkę za każdym razem, ten "kod" również wkrótce wygaśnie. Tak więc, na podstawie Twojego kodu, zmodyfikowałem swój kod, ale bez względu na to, czy jest to v1.0, czy v2.0, nadal otrzymuję pustą odpowiedź ["wartość"] ..... Czy mogę zapytać, czy wiesz, co jest nie tak z moim kod? Oto mój kod: https://github.com/hanhanwu/Basic_But_Useful/blob/master/one_drive_buz_test.py –

+0

@CherryWu - Powyższy kod jest zautomatyzowany. 'auth.save_session()' zapisuje informacje uwierzytelniające do pliku o nazwie 'session.pickle'. 'auth.load_session()' ładuje to. Sposób jego działania polega na tym, że przy pierwszym uruchomieniu tego kodu otworzy się okno przeglądarki, w którym należy się zalogować, a następnie skopiować i wkleić adres URL po przekierowaniu z powrotem do konsoli Python. Ten token uwierzytelniania jest następnie zapisywany, a następnie ładowany bez otwierania przeglądarki. Możesz przeczytać więcej na ten temat w sekcji "Zapisywanie i ładowanie sesji" [tutaj] (https://github.com/OneDrive/onedrive-sdk-python). –

+0

Dziękuję bardzo Attila, dziś nie mam czasu na wypróbowanie tego, ale szybkie pytanie, kod który dostaliśmy z przeglądarki ma bardzo krótki czas życia, to znaczy, z "Zapisywanie i ładowanie sesji" w Twój kod, ten "kod" przestanie już obowiązywać? –

Powiązane problemy