{"id":16,"date":"2018-09-11T18:29:50","date_gmt":"2018-09-11T18:29:50","guid":{"rendered":"http:\/\/users.utu.fi\/ijthun\/?p=16"},"modified":"2018-09-11T18:47:45","modified_gmt":"2018-09-11T18:47:45","slug":"how-to-copy-lecture-information-from-hops-to-google-calendar","status":"publish","type":"post","link":"https:\/\/users.utu.fi\/ijthun\/2018\/09\/11\/how-to-copy-lecture-information-from-hops-to-google-calendar\/","title":{"rendered":"How to copy lecture information from opas.peppi.utu.fi to Google Calendar"},"content":{"rendered":"<p>Hello,<\/p>\n<p>If you found this page you probably have also missing feature from peppi.utu.fi i.e. way to get the lecture dates to your calendar. I wrote small program to do the job. The code is a little hack, not very nice one so I instruct you how to do your own..<\/p>\n<p>I chose Python 3 as programming language. I wrote the app in Windows environment but should work also in Linux without problem. ActivePython can be found from\u00a0<strong>https:\/\/www.activestate.com\/activepython\/downloads<\/strong>. Select the Python 3 version.<\/p>\n<p>In Python it is easy to do user interface using PyQt3. Once you have the ActivePython installed, install PyQt3 from command line:<\/p>\n<pre>pip3 install PyQt5<\/pre>\n<p>I used Google Calendar API as I am using Gmail. The API instructions for Python can be found from<\/p>\n<p><strong>https:\/\/developers.google.com\/calendar\/quickstart\/python<\/strong><\/p>\n<p>In order you to use Calendar API follow the instructions on that page.. find the <strong>ENABLE THE GOOGLE CALENDAR API<\/strong> button. You&#8217;ll figure out the details (I hope).<\/p>\n<p>Behind that button you should get <strong>Client ID<\/strong> and <strong>Client Secret<\/strong>, you need this in your Python code.<\/p>\n<hr \/>\n<p>Before going to the UI part, let&#8217;s check the lecture information here:<\/p>\n<p>https:\/\/opas.peppi.utu.fi\/en\/course\/DTEK8103\/9933<\/p>\n<p>You&#8217;ll see the header &#8220;DTEK8103 Software Design and Architecture&#8221;, that is the one you probably want to see in the calendar (atleast I did). Also I would like to see the lecture counter current\/max ..meaning this format.. first lecture out of 4.<\/p>\n<p>(1\/4) DTEK8103 Software Design and Architecture<\/p>\n<p>Then under Implementations header there is lecture times under &#8220;Teaching&#8221; header (on some other pages there can be more lecture times under some button).<\/p>\n<div>\n<div>02.10.2018 14:00-16:00 XIV, Natura luentosali XIV<\/div>\n<\/div>\n<div>\n<div>09.10.2018 14:00-16:00 XIV, Natura luentosali XIV<\/div>\n<\/div>\n<div>\n<div>16.10.2018 14:00-16:00 XIV, Natura luentosali XIV<\/div>\n<\/div>\n<div>\n<div>23.10.2018 14:00-16:00 XIV, Natura luentosali XIV<\/div>\n<\/div>\n<div><\/div>\n<div>so.. Our program should input the header of the course and the schdule. It should be able to parse those rows, to get the times out. For parsing we use regular expression. You can try regular expressions in online services like this:\u00a0https:\/\/regex101.com\/<\/div>\n<div>The format of the row is<\/div>\n<div>dd.mm.yyyy hh:mm-hh:mm text<\/div>\n<div>where dd can be between 01-31, mm between 01-12, year &gt;=2018, hh between 00-23, mm between 00-59 and text is just free text. To parse the line using regex we can use this:<\/div>\n<div><\/div>\n<pre># day month year start hh start mm end hh end mm course location\r\n# 1 2 3 4 5 6 7 8 9 \r\nlecture = re.compile('([0123][0-9])\\.([01][0-9])\\.([0-9]{4})\\s+([012][0-9]):([012][0-9])-([012][0-9]):([012][0-9])\\s+(\\S+),\\s+(.*)')\r\n\r\n<\/pre>\n<p>so.. what we have done this far..<\/p>\n<ul>\n<li>installed Python 3<\/li>\n<li>installed PyQt3<\/li>\n<li>activacted Google Calendar API<\/li>\n<li>figured how to parse the teaching schedule<\/li>\n<\/ul>\n<p>Let&#8217;s create UI. For UI we need textbox for the lecture header and multiline textbox for the teaching schedule. We take copy from the opas.peppi.utu.fi page (the header) to header field and copy teaching schedule to teaching schedule box. Also some button for sending the calendar items to Google Calendar.<\/p>\n<pre>from PyQt5.QtWidgets import *\r\nfrom PyQt5.QtGui import *\r\nfrom PyQt5.QtCore import * \r\nimport datetime\r\nimport re\r\nimport sys\r\nimport datetime\r\nfrom googleapiclient.discovery import build\r\nfrom httplib2 import Http\r\nfrom oauth2client import file, client, tools\r\n\r\n# copy your calendar id to next variable..\r\n# format is &lt;some crypting stuff&gt;@group.calendar.google.com\r\nCALENDAR_ID = '&lt;copy here your calendar id&gt;'\r\n\r\n\r\nclass Form(QDialog):\r\n    def __init__(self):\r\n        super(Form, self).__init__()\r\n        self.setWindowTitle(\"Lecture to Google Calendar\")\r\n        self.move(50,50)\r\n        self.resize(1024,500)\r\n        self.createFormGroupBox()\r\n \r\n        self.mainLayout = QVBoxLayout()\r\n        self.mainLayout.addWidget(self.formGroupBox)\r\n        self.setLayout(self.mainLayout)\r\n\r\n    def createFormGroupBox(self):\r\n        self.formGroupBox = QGroupBox(\"Lecture Information\")\r\n        layout = QFormLayout(self)\r\n        self.courseName = QLineEdit()\r\n        layout.addRow(QLabel(\"Lecture Name (Paste Here):\"), self.courseName)\r\n        self.lecturesBox = QTextEdit()\r\n        layout.addRow(QLabel(\"Lecture Schedule (Paste Here)\"), self.lecturesBox)\r\n\r\nself.parsedTimes = QTableWidget()\r\n        self.parsedTimes.setRowCount(15)\r\n        self.parsedTimes.setColumnCount(4)\r\n        header = self.parsedTimes.horizontalHeader()\r\n        header.setSectionResizeMode(0, QHeaderView.ResizeToContents)\r\n        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)\r\n        header.setSectionResizeMode(2, QHeaderView.ResizeToContents)\r\n        header.setSectionResizeMode(3, QHeaderView.ResizeToContents)\r\n        self.parsedTimes.setHorizontalHeaderLabels(\"Start;End;Course;Class room\".split(\";\"))\r\n\r\n        layout.addRow(QLabel(\"Parsed\"), self.parsedTimes)\r\n        self.parseSchedule = QPushButton('Parse')\r\n        self.parseSchedule.clicked.connect(self.onParse)\r\n        self.addToCalendar = QPushButton('Add to Google Calendar')\r\n        self.addToCalendar.clicked.connect(self.onAddCalendar)\r\n        hbox = QHBoxLayout()\r\n        hbox.addWidget(self.parseSchedule)\r\n        hbox.addWidget(self.addToCalendar)\r\n        layout.addRow(QLabel(\"\"), hbox)\r\n    def onAddCalendar(self):\r\n        self.Process(True)\r\n        \r\n    def onParse(self):\r\n        self.Process(False)\r\n\r\n    def Process(self, sendFlag):\r\n        courseName = self.courseName.text()\r\n\r\n        lecture = re.compile('([0123][0-9])\\.([01][0-9])\\.([0-9]{4})\\s+([012][0-9]):([012][0-9])-([012][0-9]):([012][0-9])\\s+(\\S+),\\s+(.*)')\r\n        rows = self.lecturesBox.toPlainText().split(\"\\n\")\r\n        lecture_counter = 0\r\n        for r in rows:\r\n            matched = lecture.match(r)\r\n            if matched:\r\n                lecture_counter = lecture_counter + 1\r\n\r\n        self.parsedTimes.setRowCount(lecture_counter)\r\n        no_lectures = lecture_counter\r\n\r\n        lecture_counter = 0\r\n        for r in rows:\r\n            matched = lecture.match(r)\r\n            if matched:\r\n                lecture_counter = lecture_counter + 1\r\n                self.parsedTimes.setItem(lecture_counter-1, 0, QTableWidgetItem(matched[1] + \".\" + matched[2] + \".\" + matched[3] + \" \" + matched[4] + \":\" + matched[5]))\r\n                self.parsedTimes.setItem(lecture_counter-1, 1, QTableWidgetItem(matched[1] + \".\" + matched[2] + \".\" + matched[3] + \" \" + matched[6] + \":\" + matched[7]))\r\n                self.parsedTimes.setItem(lecture_counter-1, 2, QTableWidgetItem(\"(\" + str(lecture_counter) + \"\/\" + str(no_lectures) + \") \" + courseName))\r\n                self.parsedTimes.setItem(lecture_counter-1, 3, QTableWidgetItem(matched[9]))\r\n                start_datetime_object = datetime.datetime(int(matched[3]), int(matched[2]), int(matched[1]), int(matched[4]), int(matched[5]))\r\n                end_datetime_object = datetime.datetime(int(matched[3]), int(matched[2]), int(matched[1]), int(matched[6]), int(matched[7]))\r\n                location = matched[8] + \" \" + matched[9]\r\n\r\n                if sendFlag:\r\n                    self.addToGoogleCalendar(courseName, start_datetime_object, end_datetime_object, lecture_counter, no_lectures, location, \"description\")\r\n\r\n    def addToGoogleCalendar(self,name,startDateTime,endDateTime,lecture_counter,no_lectures, location,description):\r\n        SCOPES = 'https:\/\/www.googleapis.com\/auth\/calendar'\r\n\r\n        date_format = '%Y-%m-%dT%H:%M:%S'\r\n        \r\n        event = {\r\n          'summary': \"(\" + str(lecture_counter) + \"\/\" + str(no_lectures) + \") \" + name,\r\n          'location': location,\r\n          'description': description,\r\n          'start': {\r\n            'dateTime': startDateTime.strftime(date_format), \r\n            'timeZone': 'EET',\r\n          },\r\n          'end': {\r\n            'dateTime': endDateTime.strftime(date_format), \r\n            'timeZone': 'EET',\r\n          },\r\n          'attendees': [\r\n            {'email': 'your.email@somewhere.com'},\r\n            {'email': 'your.otheremail@somewhere.com'},\r\n          ],\r\n          'reminders': {\r\n            'useDefault': False,\r\n            'overrides': [\r\n              {'method': 'email', 'minutes': 2 * 60},\r\n              {'method': 'popup', 'minutes': 40},\r\n            ],\r\n          }\r\n        }\r\n        event = service.events().insert(calendarId=CALENDAR_ID, body=event, sendNotifications=True).execute()\r\n\r\nif __name__ == '__main__':\r\n    app = QApplication(sys.argv)\r\n    form = Form()\r\n    sys.exit(form.exec_())\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>run from command line using python3:<\/p>\n<p>python3 lecture_to_google_calendar.py<\/p>\n<p>It should look like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-31\" src=\"https:\/\/users.utu.fi\/ijthun\/wp-content\/uploads\/sites\/640\/2018\/09\/LectureToGoogleCalendarScreenshot-1-300x158.png\" alt=\"\" width=\"609\" height=\"321\" srcset=\"https:\/\/users.utu.fi\/ijthun\/wp-content\/uploads\/sites\/640\/2018\/09\/LectureToGoogleCalendarScreenshot-1-300x158.png 300w, https:\/\/users.utu.fi\/ijthun\/wp-content\/uploads\/sites\/640\/2018\/09\/LectureToGoogleCalendarScreenshot-1-768x403.png 768w, https:\/\/users.utu.fi\/ijthun\/wp-content\/uploads\/sites\/640\/2018\/09\/LectureToGoogleCalendarScreenshot-1-1024x538.png 1024w, https:\/\/users.utu.fi\/ijthun\/wp-content\/uploads\/sites\/640\/2018\/09\/LectureToGoogleCalendarScreenshot-1.png 1026w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/p>\n<p>if it doesn&#8217;t or if there is bugs in above code, let me know ijthun@utu.fi<\/p>\n<p>How to use it?<\/p>\n<ul>\n<li>copy name of the course\/lecture to Lecture name field<\/li>\n<li>schedule to Lecture Schedule.<\/li>\n<li>Then press Parse button.. lectures should be parsed into the Parsed table.<\/li>\n<li>If it seems to be ok, press Add to Google Calendar button and there we go<\/li>\n<\/ul>\n<p>after this check your google calendar.. if something wrong, fix the bugs.<\/p>\n<p>use saved time for .. something useful&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello, If you found this page you probably have also missing feature from peppi.utu.fi i.e. way to get the lecture dates to your calendar. I wrote small program to do the job. The code is a little hack, not very nice one so I instruct you how to do your own.. I chose Python 3 &hellip; <a href=\"https:\/\/users.utu.fi\/ijthun\/2018\/09\/11\/how-to-copy-lecture-information-from-hops-to-google-calendar\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;How to copy lecture information from opas.peppi.utu.fi to Google Calendar&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2709,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"link","meta":{"wds_primary_category":0,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-16","post","type-post","status-publish","format-link","hentry","category-uncategorized","post_format-post-format-link"],"_links":{"self":[{"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/posts\/16","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/users\/2709"}],"replies":[{"embeddable":true,"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/comments?post=16"}],"version-history":[{"count":3,"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/posts\/16\/revisions"}],"predecessor-version":[{"id":37,"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/posts\/16\/revisions\/37"}],"wp:attachment":[{"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/media?parent=16"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/categories?post=16"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/users.utu.fi\/ijthun\/wp-json\/wp\/v2\/tags?post=16"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}