2016-12-28 5 views
1

Google 스프레드 시트에서 Google 슬라이드를 생성하려고합니다. 문제없이 Sheets 스크립트를 사용했지만 Google Slides를 인증하려고 시도하고 Oauth 사용 권한 확인 메시지를 표시 한 후에이 오류가 발생하여 참조를 찾을 수 없습니다. Developers Console에서 Google Slides API 및 Drive API를 사용하도록 설정했습니다.403 오류 메시지 "Google 슬라이드 API가 프로젝트 ... 이전에 사용되지 않았거나 사용 중지되었습니다"

"에 대한 요청이 실패했습니다. 반환 된 코드 403. 서버 응답이 잘림 : {"error ": {"code ": 403,"message ":"Google 슬라이드 API가 프로젝트 ID- ... 전 또는 그것 disab ... (줄 93, 파일 "코드")

오류 코드는 다음과 같습니다. 실패한 함수는 How to download Google Slides as images?에서 복사되었습니다. . 클라이언트 ID 및 암호는 단지 보안을 위해 ommitted, 정의

// from https://mashe.hawksey.info/2015/10/setting-up-oauth2-access-with-google-apps-script-blogger-api-example/ 

function getService() { 
    // Create a new service with the given name. The name will be used when 
    // persisting the authorized token, so ensure it is unique within the 
    // scope of the property store. 
    return OAuth2.createService('slidesOauth') 

     // Set the endpoint URLs, which are the same for all Google services. 
     .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth') 
     .setTokenUrl('https://accounts.google.com/o/oauth2/token') 


     // Set the client ID and secret, from the Google Developers Console. 
     .setClientId(CLIENT_ID) 
     .setClientSecret(CLIENT_SECRET) 

     // Set the name of the callback function in the script referenced 
     // above that should be invoked to complete the OAuth flow. 
     .setCallbackFunction('authCallback') 

     // Set the property store where authorized tokens should be persisted. 
     .setPropertyStore(PropertiesService.getUserProperties()) 

     // Set the scopes to request (space-separated for Google services). 
     // this is blogger read only scope for write access is: 
     // https://www.googleapis.com/auth/blogger 
     .setScope('https://www.googleapis.com/auth/blogger.readonly') 

     // Below are Google-specific OAuth2 parameters. 

     // Sets the login hint, which will prevent the account chooser screen 
     // from being shown to users logged in with multiple accounts. 
     .setParam('login_hint', Session.getActiveUser().getEmail()) 

     // Requests offline access. 
     .setParam('access_type', 'offline') 

     // Forces the approval prompt every time. This is useful for testing, 
     // but not desirable in a production application. 
     .setParam('approval_prompt', 'force'); 
} 

function authCallback(request) { 
    var oauthService = getService(); 
    var isAuthorized = oauthService.handleCallback(request); 
    if (isAuthorized) { 
    return HtmlService.createHtmlOutput('Success! You can close this tab.'); 
    } else { 
    return HtmlService.createHtmlOutput('Denied. You can close this tab'); 
    } 
} 

// from https://stackoverflow.com/questions/31662455/how-to-download-google-slides-as-images/40678925#40678925 

function downloadPresentation(id) { 
    var slideIds = getSlideIds(id); 

    for (var i = 0, slideId; slideId = slideIds[i]; i++) { 
    downloadSlide('Slide ' + (i + 1), id, slideId); 
    } 
} 
function downloadSlide(name, presentationId, slideId) { 
    var url = 'https://docs.google.com/presentation/d/' + presentationId + 
    '/export/png?id=' + presentationId + '&pageid=' + slideId; 
    var options = { 
    headers: { 
     Authorization: 'Bearer ' + getService().getAccessToken() 
    } 
    }; 
    var response = UrlFetchApp.fetch(url, options); // This is the failing line 93 
    var image = response.getAs(MimeType.PNG); 
    image.setName(name); 
    DriveApp.createFile(image); 
} 
+0

API가 올바른 프로젝트 ID에 사용 설정되어 있습니까? 개발자 콘솔의 프로젝트 드롭 다운에서 선택 하시겠습니까? (내가이 오류를 잘못 프로젝트에서 API를 사용하도록 설정하기 전에 언급했기 때문에이 문제를 언급합니다.) – Bardy

+0

예,이 계정의 유일한 프로젝트이며 프로젝트에 API를 사용하는 방법을 파악하는 데 시간이 다소 걸렸습니다. 그러나 제안에 감사드립니다 –

답변

1

편집 :이이 코드 snipp 작업있어 et :

var CLIENT_ID = '...'; 
var CLIENT_SECRET = '...'; 
var PRESENTATION_ID = '...'; 

// from https://mashe.hawksey.info/2015/10/setting-up-oauth2-access-with-google-apps-script-blogger-api-example/ 

function getService() { 
    // Create a new service with the given name. The name will be used when 
    // persisting the authorized token, so ensure it is unique within the 
    // scope of the property store. 
    return OAuth2.createService('slidesOauth') 

     // Set the endpoint URLs, which are the same for all Google services. 
     .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth') 
     .setTokenUrl('https://accounts.google.com/o/oauth2/token') 


     // Set the client ID and secret, from the Google Developers Console. 
     .setClientId(CLIENT_ID) 
     .setClientSecret(CLIENT_SECRET) 

     // Set the name of the callback function in the script referenced 
     // above that should be invoked to complete the OAuth flow. 
     .setCallbackFunction('authCallback') 

     // Set the property store where authorized tokens should be persisted. 
     .setPropertyStore(PropertiesService.getUserProperties()) 

     // Set the scopes to request (space-separated for Google services). 
     .setScope('https://www.googleapis.com/auth/drive') 

     // Below are Google-specific OAuth2 parameters. 

     // Sets the login hint, which will prevent the account chooser screen 
     // from being shown to users logged in with multiple accounts. 
     .setParam('login_hint', Session.getActiveUser().getEmail()) 

     // Requests offline access. 
     .setParam('access_type', 'offline') 

     // Forces the approval prompt every time. This is useful for testing, 
     // but not desirable in a production application. 
     .setParam('approval_prompt', 'force'); 
} 

function authCallback(request) { 
    var oauthService = getService(); 
    var isAuthorized = oauthService.handleCallback(request); 
    if (isAuthorized) { 
    return HtmlService.createHtmlOutput('Success! You can close this tab.'); 
    } else { 
    return HtmlService.createHtmlOutput('Denied. You can close this tab'); 
    } 
} 

function getSlideIds(presentationId) { 
    var url = 'https://slides.googleapis.com/v1/presentations/' + presentationId; 
    var options = { 
    headers: { 
     Authorization: 'Bearer ' + getService().getAccessToken() 
    } 
    }; 
    var response = UrlFetchApp.fetch(url, options); 

    var slideData = JSON.parse(response); 
    return slideData.slides.map(function(slide) { 
    return slide.objectId; 
    }); 
} 


// from http://stackoverflow.com/questions/31662455/how-to-download-google-slides-as-images/40678925#40678925 

function downloadPresentation(id) { 
    var slideIds = getSlideIds(id); 

    for (var i = 0, slideId; slideId = slideIds[i]; i++) { 
    downloadSlide('Slide ' + (i + 1), id, slideId); 
    } 
} 

function downloadSlide(name, presentationId, slideId) { 
    var url = 'https://docs.google.com/presentation/d/' + presentationId + 
    '/export/png?id=' + presentationId + '&pageid=' + slideId; 
    var options = { 
    headers: { 
     Authorization: 'Bearer ' + getService().getAccessToken() 
    } 
    }; 
    var response = UrlFetchApp.fetch(url, options); // This is the failing line 93 
    var image = response.getAs(MimeType.PNG); 
    image.setName(name); 
    DriveApp.createFile(image); 
} 

function start() { 
    var service = getService(); 
    var authorizationUrl = service.getAuthorizationUrl(); 
    Logger.log('Open the following URL and re-run the script: %s', 
     authorizationUrl); 

    if (service.hasAccess()) { 
    downloadPresentation(PRESENTATION_ID); 
    } 
} 

나는 클라이언트 ID와 비밀이 당신이 생각하는 프로젝트에서 오지 않는다고 생각합니다. your project's credentials page을 방문하여 'OAuth 2.0 클라이언트 ID'에 일치하는 클라이언트 ID가 있는지 확인할 수 있습니다. 클라이언트 ID가 포함 된 프로젝트는 슬라이드 API를 사용하도록 설정해야합니다.

참고 사항 : 사용중인/export/png 종점은 문서화 된/지원되는 Google API가 아니므로 이름이 바뀌거나 나중에 중단 될 수 있습니다. Slides API를 통해 슬라이드의 렌더링 된 PNG를 가져 오는 공식 API에 관심이 있다면 issue on the tracker을 따르십시오.


이전 내용 :

귀하의 코드는 또한에서 복사하는 코드 조각보다 약간 다릅니다. ScriptApp.getOAuthToken()을 사용하여 인증 헤더의 값을 가져 오지만 다른 getService().getAccessToken() 함수를 호출하고 있습니다. 귀하의 OAuth 토큰을 생성하기 위해 apps-script-oauth2 라이브러리를 사용하고있는 것으로 보입니다. 그렇다면 OAuth2.createService으로 전달되는 clientId 및 클라이언트 비밀번호를 생성 한 개발자 콘솔 프로젝트에서 Slides API가 사용 설정되어 있는지 확인하십시오. 반드시 스크립트에 연결된 동일한 프로젝트가 아니어야합니다. ScriptApp.getOAuthToken()으로 전환하면 옵션으로 사용할 수 있습니다.

문제가 해결되지 않으면 코드를 더 많이 제공 하시겠습니까? 붙여 넣은 스 니펫은 오류 메시지와 일치하지 않는 것 같습니다. 코드에서 오류에서 언급 한 바와 같이 slides.googleapis.com이 아닌 docs.google.com에 요청하는 것 같습니다.

+0

추가 된 코드; 당신이 말했듯이, 나는 clientId와 클라이언트 비밀을 확실히 제어 할 수 있도록 ScriptApp 호출을 함수로 대체했습니다. 스 니펫이 정확합니다. 템플릿으로 사용하려는 슬라이드가 https : //docs.google.com/presentation/d/1V7k5UTj에 있지만 docs.google.com에서 요청하고 있습니다. 리디렉션. –

+0

@ 브루노, 실제로 downloadSlide를 호출하는 부분을 추가 하시겠습니까? 나는 전체 스크립트로 재현하려고 할 수 있습니다. 나는 여전히 클라이언트 ID/비밀이 당신이 기대하지 않는 프로젝트에 속한다는 것을 의심한다. –

+0

당신은 맞습니다. downloadSlide를 호출하는 함수가 빠졌지 만 문제와 관련이 없습니다. main 함수는 유효한 ID가있는 downloadSlides를 호출합니다 (두 번 확인되었습니다. 마지막으로 ID는 https://docs.google.com/presentation/d/에 추가되었으며 제대로 작동 함). 프로젝트를 두 번 확인했는데 계정과 연결된 유일한 프로젝트이며 Google 드라이브와 Google 슬라이드 API가 모두 활성화되어 있다고보고합니다. 여전히 문제의 핵심은 "최초 사용"의 측면에서 사용 중지 된 것이 아니라고 생각합니다. –

-1

이 영업 질문에 직접적인 답변을하지 않습니다에 설치 될했지만, 직접 1 부분을 해결 않습니다의 OAuth 인증의 공인 리디렉션 URI를 설정, 함께 있었다 "Google 스프레드 시트에서 Google 프레젠테이션을 생성하려고합니다."이것은 첫 번째 문장의 video (and accompanying blog post [개]을 사용한 정확한 사용 사례입니다.참고 : 게시물의 페이로드는 JSON이지만 비디오의 전체 예제는 Python에 있으므로 비 Python 개발자는이를 단순히 의사 코드로 사용할 수 있습니다.

+0

내 코드를 구현하기 전에 ... 좋은 참고가되었지만 질문에 대한 대답은 말할 수 없다. –