I am having issues trying to create a calendar event using the Google Calendar API with an AWS Lambda function call.
The AWS CloudWatch logs are not giving me a whole lot of information to work with for debugging. I am very new to working with the Google API and can't figure out what is going wrong with my code.
The code I am using is here:
from __future__ import print_function
from oauth2client import service_account
from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
import httplib2
import boto3
import json
import logging
import requests
def lambda_handler(event, context):
logger = logging.getLogger()
logger.setLevel(logging.INFO)
ses = boto3.client('ses')
email_address = 'myemail#gmail.com' # change it to your email address
SCOPES = ['https://www.googleapis.com/auth/calendar']
SERVICE_ACCOUNT_FILE = 'aws-iot-f3edea2d0394.json'
credentials = service_account.ServiceAccountCredentials.from_json_keyfile_name(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
http = httplib2.Http()
http = credentials.authorize(http)
service = discovery.build('calendar', 'v3', http=http)
calendarId = 'myemail#gmail.com'
event = {
"summary": "aws iot test",
"location": "etc",
"description": "aws iot test - pushed from button",
"start": {
"dateTime": "2018-01-31T09:00:00-07:00",
"timeZone": "America/Los_Angeles"
},
"end": {
"dateTime": "2018-01-31T17:00:00-07:00",
"timeZone": "America/Los_Angeles"
}
}
event = service.events().insert(calendarId='primary', body=event).execute()
The calendar event is not being created, and I cannot figure out why. The only information I am getting from the AWS CloudWatch logs has the last event here:
[INFO] 2018-01-23T17:09:28.116Z 29b2e36a-0060-11e8-8c9e-1725945b009e URL being requested: POST https://www.googleapis.com/calendar/v3/calendars/primary/events?alt=json
This is not very informative. Can anyone help out with maybe getting AWS to give me more information, or perhaps point out what I am doing wrong in the Python code? Thank you!
I was able to figure out the issue. Google left out some administrative details needed for the integration to work, and I was able to track down a similar issue someone else was having at Google Calendar Api v3 asp.net Code 200, yet no event inserted.
Turns out you need to enable the Google service account to make changes to your calendar.
Related
here is the way using youtube api to upload videos to the channel.
but my question is every time i run the code, it ask me to "Please visit this URL to authorize this application"
# -*- coding: utf-8 -*-
# Sample Python code for youtube.videos.insert
# NOTES:
# 1. This sample code uploads a file and can't be executed via this interface.
# To test this code, you must run it locally using your own API credentials.
# See: https://developers.google.com/explorer-help/guides/code_samples#python
# 2. This example makes a simple upload request. We recommend that you consider
# using resumable uploads instead, particularly if you are transferring large
# files or there's a high likelihood of a network interruption or other
# transmission failure. To learn more about resumable uploads, see:
# https://developers.google.com/api-client-library/python/guide/media_upload
import os
import google_auth_oauthlib.flow
import googleapiclient.discovery
import googleapiclient.errors
from googleapiclient.http import MediaFileUpload
scopes = ["https://www.googleapis.com/auth/youtube.upload"]
def main():
# Disable OAuthlib's HTTPS verification when running locally.
# *DO NOT* leave this option enabled in production.
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
api_service_name = "youtube"
api_version = "v3"
client_secrets_file = "C:/Users/User/computer science/moviepy/client_secret_660339349555-der7rru7no2g1v4oe1o1g7qqm27ujodo.apps.googleusercontent.com.json"
# Get credentials and create an API client
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
client_secrets_file, scopes)
credentials = flow.run_console()
youtube = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials)
request = youtube.videos().insert(
part = "snippet,status",
body={
"snippet": {
"title": "test",
"description": "四次是鬼"
},
"status": {
"privacyStatus": "private"
}
},
# TODO: For this request to work, you must replace "YOUR_FILE"
# with a pointer to the actual file you are uploading.
media_body=MediaFileUpload("D:/Downloads/ytdl/wtf8.mp4")
)
response = request.execute()
#print(response)
if __name__ == "__main__":
main()
is there any way to prevent this situation?
i hope someone can solve my question, thanks.
I have prepared automation in GCP cloud, automation is prepared in Python SDK. Script is deploying VPC firewall rules (I used documentation to prepare it - GCP Python SDK firewall deployment). Automation works as expected, firewall rules are being created in the Google environment, but how can I check if the deployment completed successfully? I know that I can use list method to create list of existing firewall rules, then compere it with rules I wanted do deploy, but if there any native method to verify the deployment status?
OK, I prepared that code, and it works in my environment.
import json
import time
import googleapiclient
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
from colormodule import color
credentials = GoogleCredentials.get_application_default()
def create_vpc_firewall_rule(credentials, discovery, project, firewall_body):
service = discovery.build('compute', 'v1', credentials=credentials)
request = service.firewalls().insert(project=project, body=firewall_body)
response = request.execute()
return response
def firewall_body(traffic_direction_name, network_name, ports, json, project_name):
rule_name_input = f'firewall-rule-test-{traffic_direction_name}'
network_input = f'projects/{project_name}/global/networks/{network_name}'
json_string = {
"name": rule_name_input,
"allowed": [
{
"IPProtocol": "tcp",
"ports": ports
}
],
"network": network_input,
"direction": "EGRESS",
"destinationRanges": "192.168.0.23/32",
"priority": 1000,
"targetTags": [
"testwindows"
]
}
data = json.dumps(json_string)
return data
def wait_for_operation_fw_deployment(compute, project_id, operation, fw_rule_name, colors):
print('')
print('Waiting for operation to finish...')
print('')
while True:
result = compute.globalOperations().get(
project=project_id,
operation=operation).execute()
if result['status'] == 'DONE':
print(f'Deployment of {colors.OKCYAN}%s{colors.ENDC} Firewall rule has been completed.'
% fw_rule_name)
print('')
time.sleep(2)
if 'error' in result:
raise Exception(result['Deployment has returned an error.'])
return result
time.sleep(2)
firewall_body = eval(firewall_body(traffic_direction_name,network_name, ports, json, project_name))
operation = create_vpc_firewall_rule(credentials, discovery, project_name, firewall_body)
compute = googleapiclient.discovery.build('compute', 'v1')
wait_for_operation_fw_deployment(compute, project_id, operation['name'], fw_rule_name, colors)
I have a problem working with python-quickbooks package, I try to follow the docs: https://pypi.org/project/python-quickbooks/
Here is my code:
from django.conf import settings
from intuitlib.client import AuthClient
from quickbooks import QuickBooks
from quickbooks.objects.account import Account
auth_client = AuthClient(
client_id=settings.QUICKBOOKS_CLIENT_ID,
client_secret=settings.QUICKBOOKS_CLIENT_SECRET,
environment='sandbox',
redirect_uri=settings.QUICKBOOKS_REDIRECT_URI,
)
client = QuickBooks(
auth_client=auth_client,
refresh_token=settings.QUICKBOOKS_REFRESH_TOKEN,
company_id=settings.QUICKBOOKS_REALM_ID
)
account = Account()
account.from_json(
{
"AccountType": "Accounts Receivable",
"Name": "MyJobs"
}
)
account.save(qb=client)
However, this results in error:
What am I doing wrong here?
You have to provide ACCESS_TOKEN in AuthClient.
In order to get an access token, you have to pass authorization. You can check details about the authorization process here https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/oauth-2.0-playground
Also here is a repo with an example of how to use AuthClient: https://github.com/IntuitDeveloper/SampleOAuth2_UsingPythonClient
from intuitlib.client import AuthClient
from quickbooks.client import QuickBooks, Environments
auth_client = AuthClient(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL, Environments.SANDBOX, ACCESS_TOKEN)
qbo_client = QuickBooks(
auth_client=auth_client,
refresh_token=REFRESH_TOKEN,
company_id=REALM_ID,
)
I am running a web app on heroku, and my goal is to copy files within my own drive using Google Drive API for python by sending commands to the app.
So far I have this code:
import os
import json
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import httplib2
from apiclient import discovery
# use creds to create a client to interact with the Google Drive API
scope = ['https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_dict(json.loads(os.environ.get('CREDENTIALS')), scope)
client = gspread.authorize(creds)
http = creds.authorize(httplib2.Http())
service = discovery.build('drive', 'v3', http=http, cache_discovery=False)
folder = "12vQQwYK5bkg-6UKoNrXpsU1C1-fiYeTX" # folder ID
file = "1EA25-BYr1AAUUDcstfVowDeGoygMGuxKxGxFYEdKTX0" # file ID
title = "New_file_id"
service.files().copy(fileId=file,
body={"parents": [{"kind": "drive#fileLink",
"id": folder}], 'title': title}).execute()
But it gets stuck on executing POST request forever. What am I doing wrong?
When you use Drive API v3, please use name to give the filename instead of title. And please put kind to the outside of parents. So how about the following modification for body?
From :
{
"parents": [{"kind": "drive#fileLink", "id": folder}],
'title': title
}
To :
{
"parents": [folder],
"name": title,
"kind": "drive#fileLink"
}
Reference :
Files: copy
If this didn't lead to the solution, I'm sorry.
I'm trying to create Circles with the Google+ API, but I'm kinda stuck, this is my code, it was more or less copied from the official API documentation (yes I know it doesn't create Circle, but the issue is the same)
import httplib2
from apiclient.discovery import build
from oauth2client.client import OAuth2WebServerFlow
import json
with open('client_secrets.json', 'r') as f:
json_data = json.load(f)
data = json_data['web']
CLIENT_ID = data['client_id']
CLIENT_SECRET = data['client_secret']
# List the scopes your app requires:
SCOPES = ['https://www.googleapis.com/auth/plus.me',
'https://www.googleapis.com/auth/plus.circles.write']
# The following redirect URI causes Google to return a code to the user's
# browser that they then manually provide to your app to complete the
# OAuth flow.
REDIRECT_URI = 'http://localhost/oauth2callback'
# For a breakdown of OAuth for Python, see
# https://developers.google.com/api-client-library/python/guide/aaa_oauth
# CLIENT_ID and CLIENT_SECRET come from your APIs Console project
flow = OAuth2WebServerFlow(client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
scope=SCOPES,
redirect_uri=REDIRECT_URI)
auth_uri = flow.step1_get_authorize_url()
# This command-line server-side flow example requires the user to open the
# authentication URL in their browser to complete the process. In most
# cases, your app will use a browser-based server-side flow and your
# user will not need to copy and paste the authorization code. In this
# type of app, you would be able to skip the next 3 lines.
# You can also look at the client-side and one-time-code flows for other
# options at https://developers.google.com/+/web/signin/
print 'Please paste this URL in your browser to authenticate this program.'
print auth_uri
code = raw_input('Enter the code it gives you here: ')
# Set authorized credentials
credentials = flow.step2_exchange(code)
# Create a new authorized API client.
http = httplib2.Http()
http = credentials.authorize(http)
service = build('plusDomains', 'v1', http=http)
from apiclient import errors
try:
people_service = service.people()
people_document = people_service.get(userId='me').execute()
except errors.HttpError, e:
print e.content
My output:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Forbidden"
}
],
"code": 403,
"message": "Forbidden"
}
}
I searched for answer, but didn't really find any. On the API console I have Google+ API and
Google+ Domains API services added also my secret and client id are okay (otherwise the whole script would fail sooner). Also the auth is successful, my app's name is shown under https://accounts.google.com/IssuedAuthSubTokens. What did I miss?
The problem lies with your REDIRECT_URI variable. When you are using OAuth 2.0 in a purely server-side flow, the redirect URI MUST be 'urn:ietf:wg:oauth:2.0:oob'.
Try changing the variable like so (and be sure to update your client ID in the API Console):
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
Edit: Also, make sure that you are making your API call for a user within a domain. The Google+ Domains API only permits API calls that are restricted to users and content within that domain.