Google cal enhancements, fix room lookup

This commit is contained in:
Ville Ranki 2019-12-10 23:43:08 +02:00
parent b8c9df8a31
commit a773efb7af
5 changed files with 27 additions and 27 deletions

View File

@ -6,6 +6,11 @@ COPY Pipfile .
RUN pipenv install --skip-lock --system RUN pipenv install --skip-lock --system
COPY bot.py . COPY bot.py .
COPY modules . COPY modules modules
# Uncomment for google calendar:
#COPY credentials.json .
#COPY token.pickle .
CMD [ "python", "-u", "./bot.py" ] CMD [ "python", "-u", "./bot.py" ]

View File

@ -31,7 +31,10 @@ Prints bot uptime.
Can access a google calendar in a room. This is a bit pain to set up, sorry. Can access a google calendar in a room. This is a bit pain to set up, sorry.
To set up, you'll need to generate credentials.json file - see https://console.developers.google.com/apis/credentials To set up, you'll need to generate oauth2 credentials.json file - see https://console.developers.google.com/apis/credentials
Run the bot on *local* machine as OAuth2 wants to open localhost url in your browser. I haven't found out an easy way to
do this on server.
When credentials.json is present, you must authenticate the bot to access calendar. There will be a link in console like this: When credentials.json is present, you must authenticate the bot to access calendar. There will be a link in console like this:
@ -40,6 +43,7 @@ Please visit this URL to authorize this application: https://accounts.google.com
``` ```
Open the link and authenticate as needed. A new file token.pickle will be created in the directory and bot will read it in future. Open the link and authenticate as needed. A new file token.pickle will be created in the directory and bot will read it in future.
Save the token.pickle and ship it with the bot to your server. Edit Dockerfile to copy it in container if needed.
Now the bot should be usable. Now the bot should be usable.
@ -52,7 +56,7 @@ Commands:
* !googlecal today - Show today's events * !googlecal today - Show today's events
* !googlecal add [calendar id] - Add new calendar to room * !googlecal add [calendar id] - Add new calendar to room
* !googlecal del [calendar id] - Delete calendar from room * !googlecal del [calendar id] - Delete calendar from room
* !googlecal calendars - List calendars in this room * !googlecal list - List calendars in this room
### Cron ### Cron

11
bot.py
View File

@ -28,7 +28,7 @@ class Bot:
"body": body, "body": body,
"msgtype": "m.text" "msgtype": "m.text"
} }
await self.client.room_send(self.get_room_id(room), 'm.room.message', msg) await self.client.room_send(room.room_id, 'm.room.message', msg)
async def send_html(self, room, html, plaintext): async def send_html(self, room, html, plaintext):
msg = { msg = {
@ -37,14 +37,7 @@ class Bot:
"formatted_body": html, "formatted_body": html,
"body": plaintext "body": plaintext
} }
await self.client.room_send(self.get_room_id(room), 'm.room.message', msg) await self.client.room_send(room.room_id, 'm.room.message', msg)
def get_room_id(self, room):
for roomid in self.client.rooms:
if self.client.rooms[roomid].named_room_name() == room.named_room_name():
return roomid
print('Cannot find id for room', room.named_room_name(), ' - is the bot on it?')
return None
def get_room_by_id(self, room_id): def get_room_by_id(self, room_id):
return self.client.rooms[room_id] return self.client.rooms[room_id]

View File

@ -1,7 +1,7 @@
version: '3' version: '3'
services: services:
malobot: hemppa:
container_name: hemppa container_name: hemppa
image: 'hemppa:latest' image: 'hemppa:latest'
build: '.' build: '.'

View File

@ -19,19 +19,12 @@ from google.auth.transport.requests import Request
# It's created on first run (run from console!) and # It's created on first run (run from console!) and
# can be copied to another computer. # can be copied to another computer.
# #
# ENV variables:
#
# Google calendar creds file: (defaults to this)
# GCAL_CREDENTIALS="credentials.json"
#
class MatrixModule: class MatrixModule:
def matrix_start(self, bot): def matrix_start(self, bot):
self.bot = bot self.bot = bot
self.SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'] self.SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
self.credentials_file = "credentials.json" self.credentials_file = "credentials.json"
if os.getenv("GCAL_CREDENTIALS"):
self.credentials_file = os.getenv("GCAL_CREDENTIALS")
self.service = None self.service = None
self.calendar_rooms = dict() # Contains room_id -> [calid, calid] .. self.calendar_rooms = dict() # Contains room_id -> [calid, calid] ..
@ -43,25 +36,30 @@ class MatrixModule:
if os.path.exists('token.pickle'): if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token: with open('token.pickle', 'rb') as token:
creds = pickle.load(token) creds = pickle.load(token)
print('Loaded existing pickle file')
# If there are no (valid) credentials available, let the user log in. # If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid: if not creds or not creds.valid:
print('No credentials or credentials not valid!')
if creds and creds.expired and creds.refresh_token: if creds and creds.expired and creds.refresh_token:
creds.refresh(Request()) creds.refresh(Request())
else: else:
flow = InstalledAppFlow.from_client_secrets_file( flow = InstalledAppFlow.from_client_secrets_file(
self.credentials_file, self.SCOPES) self.credentials_file, self.SCOPES)
creds = flow.run_local_server(port=0) creds = flow.run_local_server(port=0) # urn:ietf:wg:oauth:2.0:oob
# Save the credentials for the next run # Save the credentials for the next run
with open('token.pickle', 'wb') as token: with open('token.pickle', 'wb') as token:
pickle.dump(creds, token) pickle.dump(creds, token)
print('Pickle saved')
self.service = build('calendar', 'v3', credentials=creds) self.service = build('calendar', 'v3', credentials=creds)
calendar_list = self.service.calendarList().list().execute()['items'] try:
calendar_list = self.service.calendarList().list().execute()['items']
print(f'Google calendar set up successfully with access to {len(calendar_list)} calendars:\n') print(f'Google calendar set up successfully with access to {len(calendar_list)} calendars:\n')
for calendar in calendar_list: for calendar in calendar_list:
print(calendar['summary'] + ' - ' + calendar['id']) print(calendar['summary'] + ' - ' + calendar['id'])
except:
print('Getting calendar list failed!')
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
@ -77,7 +75,7 @@ class MatrixModule:
for calid in calendars: for calid in calendars:
print('Listing events in cal', calid) print('Listing events in cal', calid)
events = events + self.list_today(calid) events = events + self.list_today(calid)
if args[1] == 'calendars': if args[1] == 'list':
await bot.send_text(room, 'Calendars in this room: ' + str(self.calendar_rooms.get(room.room_id))) await bot.send_text(room, 'Calendars in this room: ' + str(self.calendar_rooms.get(room.room_id)))
elif len(args) == 3: elif len(args) == 3:
if args[1] == 'add': if args[1] == 'add':