Google cal seems to work now!
This commit is contained in:
parent
5dc8c0b9c4
commit
9431d7a267
1
Pipfile
1
Pipfile
|
@ -9,6 +9,7 @@ geopy = "*"
|
|||
google-api-python-client = "*"
|
||||
google-auth-httplib2 = "*"
|
||||
google-auth-oauthlib = "*"
|
||||
requests = "*"
|
||||
|
||||
[dev-packages]
|
||||
pylint = "*"
|
||||
|
|
|
@ -27,9 +27,9 @@ Aviation weather TAF service access.
|
|||
|
||||
Prints bot uptime.
|
||||
|
||||
### Google Calendar (WIP)
|
||||
### Google Calendar
|
||||
|
||||
Displays changes and daily report of a google calendar to 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
|
||||
|
||||
|
@ -51,6 +51,7 @@ Commands:
|
|||
* !googlecal - Show next 10 events in calendar
|
||||
* !googlecal today - Show today's events
|
||||
* !googlecal add [calendar id] - Add new calendar to room
|
||||
* !googlecal del [calendar id] - Delete calendar from room
|
||||
* !googlecal calendars - List calendars in this room
|
||||
|
||||
## Bot setup
|
||||
|
|
61
bot.py
61
bot.py
|
@ -8,10 +8,15 @@ import traceback
|
|||
import importlib
|
||||
import sys
|
||||
import re
|
||||
import requests
|
||||
import json
|
||||
import urllib.parse
|
||||
from nio import (AsyncClient, RoomMessageText, RoomMessageUnknown, JoinError, InviteEvent)
|
||||
|
||||
|
||||
class Bot:
|
||||
appid = 'org.vranki.hemppa'
|
||||
version = '1.0'
|
||||
client = None
|
||||
join_on_invite = False
|
||||
modules = dict()
|
||||
|
@ -25,11 +30,12 @@ class Bot:
|
|||
}
|
||||
await self.client.room_send(self.get_room_id(room), 'm.room.message', msg)
|
||||
|
||||
async def send_html(self, room, html):
|
||||
async def send_html(self, room, html, plaintext):
|
||||
msg = {
|
||||
"msgtype": "m.text",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": html
|
||||
"formatted_body": html,
|
||||
"body": plaintext
|
||||
}
|
||||
await self.client.room_send(self.get_room_id(room), 'm.room.message', msg)
|
||||
|
||||
|
@ -40,6 +46,32 @@ class Bot:
|
|||
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):
|
||||
return self.client.rooms[room_id]
|
||||
|
||||
def save_settings(self):
|
||||
module_settings = dict()
|
||||
for modulename, moduleobject in self.modules.items():
|
||||
if "get_settings" in dir(moduleobject):
|
||||
try:
|
||||
module_settings[modulename] = moduleobject.get_settings()
|
||||
except:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print('Collected module settings:', module_settings)
|
||||
data = { self.appid: self.version, 'module_settings': module_settings}
|
||||
self.set_account_data(data)
|
||||
|
||||
def load_settings(self, data):
|
||||
if not data.get('module_settings'):
|
||||
return
|
||||
for modulename, moduleobject in self.modules.items():
|
||||
if data['module_settings'].get(modulename):
|
||||
if "set_settings" in dir(moduleobject):
|
||||
try:
|
||||
moduleobject.set_settings(data['module_settings'][modulename])
|
||||
except:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
|
||||
async def message_cb(self, room, event):
|
||||
# Figure out the command
|
||||
body = event.body
|
||||
|
@ -104,6 +136,26 @@ class Bot:
|
|||
traceback.print_exc(file=sys.stderr)
|
||||
await asyncio.sleep(10)
|
||||
|
||||
def set_account_data(self, data):
|
||||
userid = urllib.parse.quote(os.environ['MATRIX_USER'])
|
||||
|
||||
ad_url = f"{self.client.homeserver}/_matrix/client/r0/user/{userid}/account_data/{self.appid}?access_token={self.client.access_token}"
|
||||
|
||||
response = requests.put(ad_url, json.dumps(data))
|
||||
if response.status_code != 200:
|
||||
print('Setting account data failed:', response, response.json())
|
||||
|
||||
def get_account_data(self):
|
||||
userid = urllib.parse.quote(os.environ['MATRIX_USER'])
|
||||
|
||||
ad_url = f"{self.client.homeserver}/_matrix/client/r0/user/{userid}/account_data/{self.appid}?access_token={self.client.access_token}"
|
||||
|
||||
response = requests.get(ad_url)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
elif response.status_code != 200:
|
||||
print('Getting account data failed:', response, response.json())
|
||||
|
||||
def init(self):
|
||||
self.client = AsyncClient(os.environ['MATRIX_SERVER'], os.environ['MATRIX_USER'])
|
||||
self.client.access_token = os.getenv('MATRIX_ACCESS_TOKEN')
|
||||
|
@ -114,7 +166,7 @@ class Bot:
|
|||
print(f'Starting {len(self.modules)} modules..')
|
||||
|
||||
for modulename, moduleobject in self.modules.items():
|
||||
print(modulename + '..')
|
||||
print('Starting', modulename, '..')
|
||||
if "matrix_start" in dir(moduleobject):
|
||||
try:
|
||||
moduleobject.matrix_start(bot)
|
||||
|
@ -124,7 +176,7 @@ class Bot:
|
|||
def stop(self):
|
||||
print(f'Stopping {len(self.modules)} modules..')
|
||||
for modulename, moduleobject in self.modules.items():
|
||||
print(modulename + '..')
|
||||
print('Stopping', modulename, '..')
|
||||
if "matrix_stop" in dir(moduleobject):
|
||||
try:
|
||||
moduleobject.matrix_stop(bot)
|
||||
|
@ -140,6 +192,7 @@ class Bot:
|
|||
self.poll_task = asyncio.get_event_loop().create_task(self.poll_timer())
|
||||
|
||||
if self.client.logged_in:
|
||||
self.load_settings(self.get_account_data())
|
||||
self.client.add_event_callback(self.message_cb, RoomMessageText)
|
||||
self.client.add_event_callback(self.unknown_cb, RoomMessageUnknown)
|
||||
if self.join_on_invite:
|
||||
|
|
|
@ -33,9 +33,7 @@ class MatrixModule:
|
|||
if os.getenv("GCAL_CREDENTIALS"):
|
||||
self.credentials_file = os.getenv("GCAL_CREDENTIALS")
|
||||
self.service = None
|
||||
self.report_time = 8
|
||||
self.last_report_date = None
|
||||
self.calendar_rooms = dict() # Contains rooms -> [calid, calid] ..
|
||||
self.calendar_rooms = dict() # Contains room_id -> [calid, calid] ..
|
||||
|
||||
creds = None
|
||||
|
||||
|
@ -72,7 +70,7 @@ class MatrixModule:
|
|||
return
|
||||
args = event.body.split()
|
||||
events = []
|
||||
calendars = self.calendar_rooms.get(room) or []
|
||||
calendars = self.calendar_rooms.get(room.room_id) or []
|
||||
|
||||
if len(args) == 2:
|
||||
if args[1] == 'today':
|
||||
|
@ -80,20 +78,38 @@ class MatrixModule:
|
|||
print('Listing events in cal', calid)
|
||||
events = events + self.list_today(calid)
|
||||
if args[1] == 'calendars':
|
||||
await bot.send_text(room, 'Calendars in this room: ' + str(self.calendar_rooms.get(room)))
|
||||
await bot.send_text(room, 'Calendars in this room: ' + str(self.calendar_rooms.get(room.room_id)))
|
||||
elif len(args) == 3:
|
||||
if args[1] == 'add':
|
||||
calid = args[2]
|
||||
print(f'Adding calendar {calid} to room {room}')
|
||||
print(f'Adding calendar {calid} to room id {room.room_id}')
|
||||
|
||||
if self.calendar_rooms.get(room):
|
||||
self.calendar_rooms[room].append(calid)
|
||||
if self.calendar_rooms.get(room.room_id):
|
||||
if calid not in self.calendar_rooms[room.room_id]:
|
||||
self.calendar_rooms[room.room_id].append(calid)
|
||||
else:
|
||||
await bot.send_text(room, 'This google calendar already added in this room!')
|
||||
return
|
||||
else:
|
||||
self.calendar_rooms[room] = [calid]
|
||||
self.calendar_rooms[room.room_id] = [calid]
|
||||
|
||||
print(f'Calendars now for this room {self.calendar_rooms[room]}')
|
||||
print(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
|
||||
|
||||
bot.save_settings()
|
||||
|
||||
await bot.send_text(room, 'Added new google calendar to this room')
|
||||
if args[1] == 'del':
|
||||
calid = args[2]
|
||||
print(f'Removing calendar {calid} from room id {room.room_id}')
|
||||
|
||||
if self.calendar_rooms.get(room.room_id):
|
||||
self.calendar_rooms[room.room_id].remove(calid)
|
||||
|
||||
print(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
|
||||
|
||||
bot.save_settings()
|
||||
|
||||
await bot.send_text(room, 'Removed google calendar from this room')
|
||||
else:
|
||||
for calid in calendars:
|
||||
print('Listing events in cal', calid)
|
||||
|
@ -108,9 +124,9 @@ class MatrixModule:
|
|||
async def send_events(self, bot, events, room):
|
||||
for event in events:
|
||||
start = event['start'].get('dateTime', event['start'].get('date'))
|
||||
await bot.send_text(room, f"{self.parseDate(start)} {event['summary']}")
|
||||
# await bot.send_text(room, f"{self.parseDate(start)} {event['summary']} {event['htmlLink']}")
|
||||
# await bot.send_html(room, self.parseDate(start) + " <a href=\"" + event['htmlLink'] + "\">" + event['summary'] + "</a>")
|
||||
# await bot.send_text(room, f"{self.parse_date(start)} {event['summary']}")
|
||||
# await bot.send_text(room, f"{self.parse_date(start)} {event['summary']} {event['htmlLink']}")
|
||||
await bot.send_html(room, f'{self.parse_date(start)} <a href="{event["htmlLink"]}">{event["summary"]}</a>', f'{self.parse_date(start)} {event["summary"]}')
|
||||
|
||||
def list_upcoming(self, calid):
|
||||
startTime = datetime.datetime.utcnow()
|
||||
|
@ -133,38 +149,17 @@ class MatrixModule:
|
|||
events = events_result.get('items', [])
|
||||
return events
|
||||
|
||||
async def matrix_poll(self, bot, pollcount):
|
||||
if not self.service:
|
||||
return
|
||||
|
||||
if pollcount % (6 * 5) == 0: # Poll every 5 min
|
||||
pass # Not implemented yet
|
||||
|
||||
needs_send = False
|
||||
|
||||
today = datetime.datetime.now()
|
||||
since_last = 999
|
||||
|
||||
# Bot's been started
|
||||
if self.last_report_date:
|
||||
since_last = (today - self.last_report_date).total_seconds() / 60 / 60
|
||||
|
||||
if since_last > 20 and today.hour >= self.report_time:
|
||||
needs_send = True
|
||||
|
||||
if needs_send:
|
||||
self.last_report_date = today
|
||||
|
||||
for room in self.calendar_rooms:
|
||||
events = []
|
||||
for calid in self.calendar_rooms.get(room):
|
||||
events = events + self.list_today(calid)
|
||||
await self.send_events(bot, events, room)
|
||||
|
||||
def help(self):
|
||||
return('Google calendar. Lists 10 next events by default. today = list today\'s events.')
|
||||
|
||||
def parseDate(self, start):
|
||||
def get_settings(self):
|
||||
return { 'calendar_rooms': self.calendar_rooms }
|
||||
|
||||
def set_settings(self, data):
|
||||
if data.get('calendar_rooms'):
|
||||
self.calendar_rooms = data['calendar_rooms']
|
||||
|
||||
def parse_date(self, start):
|
||||
try:
|
||||
dt = datetime.datetime.strptime(start, '%Y-%m-%dT%H:%M:%S%z')
|
||||
return dt.strftime("%d.%m %H:%M")
|
||||
|
|
Loading…
Reference in New Issue