I'm trying to follow google's example of adding a event and originally it threw errors because I formatted something wrong but now it's saying the event is being made and linking me to it but it never actually makes the event. The 3rd picture I attached is the result and it has a little popup that says error adding event, the weird thing is that none of my events at all show up on the calendar even though I'm logged into the same account in both cases and only have one calendar. The event never gets added to my calendar I've tried running it multiple times even using different data in the event and same result, it says it adds it but never does. I'm lost any help is greatly appreciated please feel free to ask for more info if you need!
edit:
here's my event creation function
def createEvent(summary, start_time, end_time, *args, description='', location='', timeZone='America/New_York'):
credentials = get_credentials()
service = discovery.build('calendar', 'v3', credentials=credentials)
event = {
'summary': summary,
'location': location,
'description': description,
'start': {
'dateTime': start_time,
'timeZone': timeZone,
},
'end': {
'dateTime': end_time,
'timeZone': timeZone,
},
'reminders': {
'useDefault': False,
'overrides': [
# {'method': 'email', 'minutes': 24 * 60},
{'method': 'popup', 'minutes': 10},
],
},
}
for arg in args:
event[arg[0]] = arg[1]
event = service.events().insert(calendarId='primary', body=event).execute()
print ('Event created: %s' % (event.get('htmlLink')))
edit 2:
this is how the function is called with an example of the information passed in
googEvent = ['CSC 385 hw', '20-1-31T22:59:59', '20-1-31T23:59:59', 'EC Mylavarapu']
createEvent(googEvent[0], googEvent[1], googEvent[2], description=googEvent[3])
After studying your code I found that you are so close to fixing it. You only need to force the date format into ISO 8601. To accomplish that, I used the following Python methods:
import datetime
…
googEvent = ['CSC 385 hw', datetime.datetime.strptime("31/01/2020 22:59:59",
"%d/%m/%Y %H:%M:%S").isoformat(), datetime.datetime.strptime(
"31/01/2020 23:59:59", "%d/%m/%Y %H:%M:%S").isoformat(), 'EC Mylavarapu']
createEvent(googEvent[0], googEvent[1], googEvent[2], description = googEvent[3])
This is only one way of doing it. Each date is first created from a human readable string using strptime() and later converted into ISO 8601 with isoformat(). Please, answer me back if you need further help.
Related
I am trying to send email alerts for all new alerts that have just been created. I have tried
last_alert = Alert.objects.filter(kiosk=kiosk).last()
But that only gets the last alert and it triggers the same one all the time. It is possible to have 3 alerts be triggered at once. I am trying to implement a flag to know whether or not an alert has been sent. I'm probably using latest wrong here.
last_alert = Alert.objects.filter(kiosk=kiosk).latest('pk')
if last_alert.created_on:
alert_status = HTTP_208_ALREADY_REPORTED
send_alert_email = False
else:
alert_status = HTTP_201_CREATED
send_alert_email = True
last_alert.created_on = datetime.now(last_alert.kiosk.location.timezone)
Alert.create(kiosk=kiosk, created_on=datetime.now(last_alert.kiosk.location.timezone))
last_alert.save()
# Get Timezone aware date and time
current_dt = datetime.now().astimezone(kiosk.location.timezone)
current_time = current_dt.strftime('%I:%M %p')
current_date = current_dt.strftime('%m/%d/%Y')
email_props2 = {
'method': 'EMAIL',
'email': 'john#example.com',
'data': {
'facility': last_alert.kiosk.location.name,
'description': last_alert.description,
'pk': last_alert.pk,
'time': current_time,
'date': current_date,
'kioskName': kiosk.name,
'alert_type_display': last_alert.alert_type_display
}
}
if send_alert_email:
_send_email(
[email_props2['email']],
{'data': email_props2['data']},
ALERT_TEMPLATE_ID
)
Maybe I am approaching this problem wrong with the flag. Any help is very much appreciated.
thanks in advance
I have a solution. I added a processed field to the Alert model default it to False. Then filter all Alerts with field processed=False. Loop through all of the Alerts, if processed=False send an email, then set processed=True.
last_alert = Alert.objects.filter(kiosk=kiosk, processed=False)
# Get Timezone aware date and time
for alert in last_alert:
if alert.processed == False:
current_dt = datetime.now().astimezone(kiosk.location.timezone)
current_time = current_dt.strftime('%I:%M %p')
current_date = current_dt.strftime('%m/%d/%Y')
email_props2 = {
'method': 'EMAIL',
'email': 'john#example.com',
'data': {
'facility': alert.kiosk.location.name,
'description': alert.description,
'pk': alert.pk,
'time': current_time,
'date': current_date,
'kioskName': kiosk.name,
'alert_type_display': alert.alert_type_display
}
}
# Straight up send it, dude
_send_email(
[email_props2['email']],
{'data': email_props2['data']},
ALERT_TEMPLATE_ID
)
alert.processed = True
alert.save()
Alright, I'm stumped. I have googled everything I can think of from nested Dicts, Dicts inside Lists inside Dicts, to JSON referencing and have no idea how to get to this data.
I have this AWS Lambda handler that is reading Slack events and simply reversing someone's message and then spitting it out back to Slack. However, the bot can respond to itself (creating an infinite loop). I thought I had this solved, however, that was for the legacy stuff. I am Python stupid, so how do reference this data?
Data (slack_body_dict print from below):
{'token': 'NgapUeqidaGeTf4ONWkUQQiP', 'team_id': 'T7BD9RY57', 'api_app_id': 'A01LZHA7R9U', 'event': {'client_msg_id': '383aeac2-a436-4bad-8e19-7fa68facf916', 'type': 'message', 'text': 'rip', 'user': 'U7D1RQ9MM', 'ts': '1612727797.024200', 'team': 'T7BD9RY57', 'blocks': [{'type': 'rich_text', 'block_id': 'gA7K', 'elements': [{'type': 'rich_text_section', 'elements': [{'type': 'text', 'text': 'rip'}]}]}], 'channel': 'D01MK0JSNDP', 'event_ts': '1612727797.024200', 'channel_type': 'im'}, 'type': 'event_callback', 'event_id': 'Ev01MN8LJ117', 'event_time': 1612727797, 'authorizations': [{'enterprise_id': None, 'team_id': 'T7BD9RY57', 'user_id': 'U01MW6UK55W', 'is_bot': True, 'is_enterprise_install': False}], 'is_ext_shared_channel': False, 'event_context': '1-message-T7BD9RY57-D01MK0JSNDP'}
There is an 'is_bot' there under 'authorizations' I want to check. I assume this will let the bot stop responding to itself. However, for the life of me, I cannot reference it. It seems to be nested in there.
I have tried the following:
def lambda_handler(api_event, api_context):
print(f"Received event:\n{api_event}\nWith context:\n{api_context}")
# Grab relevant information form the api_event
slack_body_raw = api_event.get('body')
slack_body_dict = json.loads(slack_body_raw)
request_headers = api_event["headers"]
print(f"!!!!!!!!!!!!!!!!!!!!!!!body_dict:\n{slack_body_dict}")
print(f"#######################is_bot:\n{slack_body_dict('is_bot')}")
print(f"#######################is_bot:\n{slack_body_dict("is_bot")}")
print(f"#######################is_bot:\n{slack_body_dict(['is_bot']}")
print(f"#######################is_bot:\n{slack_body_dict(["is_bot"]}")
print(f"#######################is_bot:\n{slack_body_dict['authorizations']['is_bot']}")
As you can see I have absolutely no clue how to get to that variable to tell if it is true or false. Every 'is_bot' print reference results in an error. Can someone tell me how to reference that variable or give me something to google? Appreciate it. Code is below in case it is relevant.
import json
import os
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
def is_challenge(slack_event_body: dict) -> bool:
"""Is the event a challenge from slack? If yes return the correct response to slack
Args:
slack_event_body (dict): The slack event JSON
Returns:
returns True if it is a slack challenge event returns False otherwise
"""
if "challenge" in slack_event_body:
LOGGER.info(f"Challenge Data: {slack_event_body['challenge']}")
return True
return False
def lambda_handler(api_event, api_context):
# Grab relevant information form the api_event
slack_body_raw = api_event.get('body')
slack_body_dict = json.loads(slack_body_raw)
request_headers = api_event["headers"]
# This is to appease the slack challenge gods
if is_challenge(slack_body_dict):
challenge_response_body = {
"challenge": slack_body_dict["challenge"]
}
return helpers.form_response(200, challenge_response_body)
# This parses the slack body dict to get the event JSON
slack_event_dict = slack_body_dict["event"]
# Build the slack client.
slack_client = WebClient(token=os.environ['BOT_TOKEN'])
# We need to discriminate between events generated by
# the users, which we want to process and handle,
# and those generated by the bot.
if slack_body_dict['is_bot']: #THIS IS GIVING ME THE ERROR. I WANT TO CHECK IF BOT HERE.
logging.warning("Ignore bot event")
else:
# Get the text of the message the user sent to the bot,
# and reverse it.
text = slack_event_dict["text"]
reversed_text = text[::-1]
# Get the ID of the channel where the message was posted.
channel_id = slack_event_dict["channel"]
try:
response = slack_client.chat_postMessage(
channel=channel_id,
text=reversed_text
)
except SlackApiError as e:
# You will get a SlackApiError if "ok" is False
assert e.response["error"] # str like 'invalid_auth', 'channel_not_found'
The structure of the data is:
{
"authorizations": [
{
"is_bot": true
}
]
}
So you would need to first index "authorizations", then to get the first item 0, and lastly "is_bot".
data["authorizations"][0]["is_bot"]
Alternativly, you could iterate over all the authorizations and check if any (or all) of them are marked as a bot like so:
any(auth["is_bot"] for auth in slack_body_dict["authorizations"])
I want to create develop a chatbot using Lex's interface, as a first step i found a ScheduleAppointment default bot so i decided to do adjustments to it. The default prompts in this bot are date, time and appointmenttype. As a first step i went to using blueprint lex-make-appointment-python https://console.aws.amazon.com/lambda/home?region=us-east-1#/create/new?bp=lex-make-appointment-python and had to change lots of the default stuff there, for example it has an exact appointment time and days etc while the version i want to work on before developing it any further in lambda is one that would take ANY TIME and ANY DAY for example i can't get an error if i ask to schedule an appointment tomorrow but if the bot asks for date and i put something like hfujdhfu or banana i should be asked what is the date? again.
All that being said and done this is my version of that code after adjusting it :
import json
import dateutil.parser
import datetime
import time
import os
import math
import random
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
""" --- Helpers to build responses which match the structure of the necessary dialog actions --- """
def elicit_slot(session_attributes, intent_name, slots, slot_to_elicit, message, response_card):
return {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'ElicitSlot',
'intentName': intent_name,
'slots': slots,
'slotToElicit': slot_to_elicit,
'message': message,
'responseCard': response_card
}
}
def confirm_intent(session_attributes, intent_name, slots, message, response_card):
return {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'ConfirmIntent',
'intentName': intent_name,
'slots': slots,
'message': message,
'responseCard': response_card
}
}
def close(session_attributes, fulfillment_state, message):
response = {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'Close',
'fulfillmentState': fulfillment_state,
'message': message
}
}
return response
def delegate(session_attributes, slots):
return {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'Delegate',
'slots': slots
}
}
def build_response_card(title, subtitle, options):
"""
Build a responseCard with a title, subtitle, and an optional set of options which should be displayed as buttons.
"""
buttons = None
if options is not None:
buttons = []
for i in range(min(5, len(options))):
buttons.append(options[i])
return {
'contentType': 'application/vnd.amazonaws.card.generic',
'version': 1,
'genericAttachments': [{
'title': title,
'subTitle': subtitle,
'buttons': buttons
}]
}
""" --- Helper Functions --- """
def parse_int(n):
try:
return int(n)
except ValueError:
return float('nan')
def try_ex(func):
"""
Call passed in function in try block. If KeyError is encountered return None.
This function is intended to be used to safely access dictionary.
Note that this function would have negative impact on performance.
"""
try:
return func()
except KeyError:
return None
def isvalid_date(date):
try:
dateutil.parser.parse(date)
return True
except ValueError:
return False
def build_time_output_string(appointment_time):
hour, minute = appointment_time.split(':') # no conversion to int in order to have original string form. for eg) 10:00 instead of 10:0
if int(hour) > 12:
return '{}:{} p.m.'.format((int(hour) - 12), minute)
elif int(hour) == 12:
return '12:{} p.m.'.format(minute)
elif int(hour) == 0:
return '12:{} a.m.'.format(minute)
return '{}:{} a.m.'.format(hour, minute)
def make_appointment(intent_request):
"""
Performs dialog management and fulfillment for booking a dentists appointment.
Beyond fulfillment, the implementation for this intent demonstrates the following:
1) Use of elicitSlot in slot validation and re-prompting
2) Use of confirmIntent to support the confirmation of inferred slot values, when confirmation is required
on the bot model and the inferred slot values fully specify the intent.
"""
appointment_type = intent_request['currentIntent']['slots']['AppointmentType']
date = intent_request['currentIntent']['slots']['Date']
appointment_time = intent_request['currentIntent']['slots']['Time']
source = intent_request['invocationSource']
output_session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}
booking_map = json.loads(try_ex(lambda: output_session_attributes['bookingMap']) or '{}')
if source == 'DialogCodeHook':
# Perform basic validation on the supplied input slots.
slots = intent_request['currentIntent']['slots']
if not appointment_type:
return elicit_slot(
output_session_attributes,
intent_request['currentIntent']['name'],
intent_request['currentIntent']['slots'],
'AppointmentType',
{'contentType': 'PlainText', 'content': 'What type of appointment would you like to schedule?'},
build_response_card(
'Specify Appointment Type', 'What type of appointment would you like to schedule?',
build_options('AppointmentType', appointment_type, date, None)
)
)
if appointment_type and not date:
return elicit_slot(
output_session_attributes,
intent_request['currentIntent']['name'],
intent_request['currentIntent']['slots'],
'Date',
{'contentType': 'PlainText', 'content': 'When would you like to schedule your {}?'.format(appointment_type)},
build_response_card(
'Specify Date',
'When would you like to schedule your {}?'.format(appointment_type),
build_options('Date', appointment_type, date, None)
)
)
)
message_content = 'What time on {} works for you? '.format(date)
if appointment_time:
output_session_attributes['formattedTime'] = build_time_output_string(appointment_time)
)
available_time_string = build_available_time_string(appointment_type_availabilities)
return elicit_slot(
output_session_attributes,
intent_request['currentIntent']['name'],
slots,
'Time',
{'contentType': 'PlainText', 'content': '{}{}'.format(message_content, available_time_string)},
build_response_card(
'Specify Time',
'What time works best for you?',
build_options('Time', appointment_type, date, booking_map)
)
)
return delegate(output_session_attributes, slots)
duration = get_duration(appointment_type)
""" --- Intents --- """
def dispatch(intent_request):
"""
Called when the user specifies an intent for this bot.
"""
logger.debug('dispatch userId={}, intentName={}'.format(intent_request['userId'], intent_request['currentIntent']['name']))
intent_name = intent_request['currentIntent']['name']
# Dispatch to your bot's intent handlers
if intent_name == 'MakeAppointment':
return make_appointment(intent_request)
raise Exception('Intent with name ' + intent_name + ' not supported')
""" --- Main handler --- """
def lambda_handler(event, context):
"""
Route the incoming request based on intent.
The JSON body of the request is provided in the event slot.
"""
# By default, treat the user request as coming from the America/New_York time zone.
os.environ['TZ'] = 'America/New_York'
time.tzset()
logger.debug('event.bot.name={}'.format(event['bot']['name']))
return dispatch(event)
There is ) at line 171 and line 175 without any ( which must be causing syntax error. many code lines are unreachable because you are coding return before them but those won't cause syntax error.
You can watch the logs on Cloudwatch.
The blueprint which you are using is very complex and not beginner friendly. You really should be using this blueprint for starting. That is my suggestion.
Also, since you are using response_card so please be aware that the response cards won't be shown in the Lex Console window. It will work in Facebook and Slack though.
I am creating events for a not primary calendar, I want to check if the user is not busy in this calendar, not in primary one for this event.
My query:
the_datetime = tz.localize(datetime.datetime(2016, 1, 3, 0))
the_datetime2 = tz.localize(datetime.datetime(2016, 1, 4, 8))
body = {
"timeMin": the_datetime.isoformat(),
"timeMax": the_datetime2.isoformat(),
"timeZone": 'US/Central',
"items": [{"id": 'my.email#gmail.com'}]
}
eventsResult = service.freebusy().query(body=body).execute()
It returns:
{'calendars': {'my.email#gmail.com': {'busy': []}},
'kind': 'calendar#freeBusy',
'timeMax': '2016-01-04T14:00:00.000Z',
'timeMin': '2016-01-03T06:00:00.000Z'}
even if i have something created for that date in my X calendar, but when I create an event in primary calendar I have:
{'calendars': {'my.email#gmail.com': {'busy': [{'end': '2016-01-03T07:30:00-06:00',
'start': '2016-01-03T06:30:00-06:00'}]}},
'kind': 'calendar#freeBusy',
'timeMax': '2016-01-04T14:00:00.000Z',
'timeMin': '2016-01-03T06:00:00.000Z'}
Is there a way to tell the API the calendar I want to check?
i found it! :D
in items of body, put calendar id instead of mail
So I've just started using the google calendar api and I've had good results so far. I add attendees with their name and email in the events dictionary, like so
events = {
# other stuff here and then this
'items': [
# lots of stuff here, followed by
'attendees': [
{
'email': email1,
'displayName': name1
},
{
'email': email2,
'displayName': name2
},
],
###
]
}
Adding them goes fine, but when I access them, I'm never guaranteed of their order. I thought I could just access the emails like this
for event in events['items']:
print "email1 = " + str(event['attendees'][0]['email'])
print "email2 = " + str(event['attendees'][1]['email'])
and I can. And I've learned that lists in python always have their order preserved, which is convenient because I wanted to access the dictionaries inside the list with the index of the list. But what I've learned is that sometimes the 0 index refers to email1 and sometimes it refers to email2. Why the inconsistency? Is it inherent to the google calendar api or is there something about having dictionary objects within a python list that relaxes the order preservation assumption? Or is it something else I'm missing?
So, as #Colonel Thirty Two pointed out, while lists preserve order, how google return data into a list may not be in the same order as it was submitted to them. This order inconsistency with attendees is inconvenient if you are wanting to count on that order for the retrieval of attendees with something like
for event in events['items']:
print "email1 = " + str(event['attendees'][0]['email'])
print "email2 = " + str(event['attendees'][1]['email'])
What's more is that very few fields are writable with the google calendar api. What is writable, however, is comments. So, I added a value to that field to make the attendees identifiable. Like so
'attendees': [
{
'email': agent_email,
'displayName': agent_name,
'comment': 'agent'
},
{
'email': event_attendee_email,
'displayName': event_attendee_name,
'comment': 'client'
},
Using comment as an identifier helped me in retrieving the email and displayName of each attendee with a simple if-statement.
for i in range(len(event['attendees'])):
if event['attendees'][i]['comment'] == 'client':
event['attendees'][i]['displayName'] = event_attendee_name
event['attendees'][i]['email'] = event_attendee_email
Now it doesn't matter that the google calendar api submits my attendees back to me in a different order than the one in which I added them. I can now retrieve the attendees so I can change them. Problem solved.