Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
59db27a
New workflow triggered using repository_dispatch
everthemore Sep 30, 2020
c11f047
Update schedule_zoom_talks.yml
everthemore Sep 30, 2020
d260eca
Create zoom_scheduling_bot_requirements.txt
everthemore Sep 30, 2020
22eef8a
Create schedulezoomtalks.py
everthemore Sep 30, 2020
ae82381
WIP
everthemore Sep 30, 2020
2d33d76
Merge branch 'master' into schedule-zoom-talks-bot
everthemore Oct 7, 2020
2dea154
WIP
everthemore Oct 8, 2020
22625c6
Implement round of comments; password action missing
everthemore Oct 8, 2020
b826336
Update req's, rename function for clarity, attempt to add registratio…
everthemore Oct 8, 2020
86ff429
Remove incorrect '-'
everthemore Oct 8, 2020
b5b7504
More suggestions implemented
everthemore Oct 8, 2020
cfd0443
Fix link
everthemore Oct 9, 2020
2434663
Use PATCH for questions
everthemore Oct 9, 2020
1a2683e
Update requirements.txt
everthemore Oct 9, 2020
827364a
Delete redundant requirements.txt
everthemore Oct 9, 2020
b4255a7
Switch to test branch
everthemore Oct 9, 2020
f84c120
Speaker registration
everthemore Oct 9, 2020
313dfb6
Remove live link
everthemore Oct 9, 2020
0723abd
Issue response
everthemore Oct 10, 2020
e39fc28
Tweaks
everthemore Oct 10, 2020
ee6c61d
Email WIP
everthemore Oct 10, 2020
ee9e924
Email v1
everthemore Oct 10, 2020
1ae7003
Add date and time to email
everthemore Oct 10, 2020
de39fb8
Add zoom link
everthemore Oct 11, 2020
49129d6
Add mailgun key
everthemore Oct 11, 2020
0d7ac9f
bugfixes
akhmerov Oct 11, 2020
fec3226
Turn off submission to researchseminars.org
everthemore Oct 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/schedule_zoom_talks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Schedule Zoom Talks
on:
repository_dispatch:
types: [schedule-zoom-talk]

jobs:
scheduleTalks:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Schedule talks
working-directory: ./bots
run: python3 schedulezoomtalks.py
env:
VSF_BOT_TOKEN: ${{ secrets.VSF_BOT_TOKEN }}
ZOOM_API_KEY: ${{ secrets.ZOOM_API_KEY }}
ZOOM_API_SECRET: ${{ secrets.ZOOM_API_SECRET }}
MAILGUN_API_KEY: ${{ secrets.MAILGUN_API_KEY }}
26 changes: 22 additions & 4 deletions common.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from functools import lru_cache
import os
from time import time
import json

import jwt
import requests

ZOOM_API = "https://api.zoom.us/v2/"
SPEAKERS_CORNER_USER_ID = "D0n5UNEHQiajWtgdWLlNSA"
TALKS_FILE = "speakers_corner_talks.yml"

MAILGUN_BASE_URL = "https://api.eu.mailgun.net/v3/"
MAILGUN_DOMAIN = "mail.virtualscienceforum.org/"

@lru_cache()
def zoom_headers(duration: int=100) -> dict:
Expand All @@ -31,7 +36,6 @@ def zoom_request(method: callable, *args, **kwargs):
if response.content:
return response.json()


def speakers_corner_user_id() -> str:
users = zoom_request(requests.get, ZOOM_API + "users")["users"]
sc_user_id = next(
Expand All @@ -43,7 +47,7 @@ def speakers_corner_user_id() -> str:

def all_meetings(user_id) -> list:
"""Return all meetings by a user.

Handles pagination, and adds ``live: True`` to a meeting that is running (if any).
"""
meetings = []
Expand All @@ -58,7 +62,7 @@ def all_meetings(user_id) -> list:
next_page_token = meetings_page["next_page_token"]
if not next_page_token:
break

live_meetings = zoom_request(
requests.get,
f"{ZOOM_API}users/{user_id}/meetings",
Expand All @@ -69,5 +73,19 @@ def all_meetings(user_id) -> list:
for meeting in meetings:
if meeting["id"] == live_meetings[0]["id"]:
meeting["live"] = True

return meetings


def decode(response):
if response.status_code > 299: # Not OK
raise RuntimeError(response.content.decode())
return json.loads(response.content.decode())


def api_query(method, endpoint, **params):
return decode(method(
MAILGUN_BASE_URL + endpoint,
auth=("api", os.getenv("MAILGUN_API_KEY")),
**params
))
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
requests
pytz
python-dateutil
PyJWT
PyJWT
PyGithub
PyYAML
109 changes: 109 additions & 0 deletions researchseminarsdotorg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import os
from requests import get, post

SPEAKERS_CORNER_SEMINAR_SERIES = {"series_id": "speakerscorner",
"name": "Speakers\' Corner",
"is_conference": False,
"topics": [""], # TODO: Get a list of topics
"language": "en",
"institutions": [""],
"timezone": "UTC",
"homepage": "https://virtualscienceforum.org/speakerscorner.md",
"visibility": 1, # 0=private, 1=unlisted, 2=public
"access_control": 0, # 0=open, see schema for more
"slots": [""],
"organizers": [{"name": "Virtual Science Forum",
"email": "vsf@virtualscienceforum.org",
"homepage": "https://virtualscienceforum.org",
"organizer": True,
"order": 0,
"display": True}]}


def find_seminar_series(series_id):
url = f"https://researchseminars.org/api/0/search/series?series_id={series_id}"
r = get(url)
if r.status_code == 200:
J = r.json()
results = J["properties"]["results"]
return (len(results) != 0)


def create_seminar_series(payload, authorization):
url = "https://researchseminars.org/api/0/save/series/"
r = post(url, json=payload, headers={"authorization":authorization})
J = r.json()
code = J.get("code")

if r.status_code == 200:
if code == "warning":
return True, J["warnings"]
else:
return True, ""
else:
return False, ""


def edit_seminar_series(name, payload, authorization):
url = "https://researchseminars.org/api/0/save/series/"
r = post(url, json=payload, headers={"authorization":authorization})
J = r.json()
code = J.get("code")

if r.status_code == 200:
if code == "warning":
return True, J["warnings"]
else:
return True, ""
else:
return False, ""


def add_talk_to_series(series_id, payload, authorization):
url = "https://researchseminars.org/api/0/save/talk/"
r = post(url, json=payload, headers={"authorization":authorization})
J = r.json()
code = J.get("code")
if r.status_code == 200:
if code == "warning":
return J["series_ctr"], J["warnings"]
else:
return J["series_ctr"]
else:
return "", r.status_code


def publish_to_researchseminars(talk):
# talk should be provided in yaml format
api_token = os.getenv("RESEARCHSEMINARS_API_TOKEN")
authorization = "vsf@virtualscienceforum.org %s" % api_token

# Find speakers' corner series, and create it if it doesn't exist
if not find_seminar_series("speakerscorner"):
print("[ResearchSeminars.org]: The speakerscorner seminar series "\
"does not yet exist. Creating it now")
create_seminar_series(SPEAKERS_CORNER_SEMINAR_SERIES)

# TODO: Figure out if we need to edit the series;
# Would be annoying since edits have to be approved

# Set up payload for talk creation
talk_payload = {"title":talk.get('title'),
"speaker":talk.get('author'), # TODO: will be 'speakerS'
"online": True,
"start_time":talk["time"],
"timezone":"UTC"
}

# Make request to remote API
series_ctr, warnings = add_talk_to_series("speakerscorner", talk_payload, authorization)

if series_ctr != "":
print("Talk with id {0} successfully added".format(series_ctr))
if warnings != "":
print("Warnings: {0}".format(warnings))
return True
else:
print("-- ERROR -- ")
print("Could not add talk to series, status code {0}".format(warnings))
return False
Loading