Edmodo calendar synchronisation


Edmodo is a social learning platform for teachers, students, and parents. The Edmodo Planner displays personal, group and assignment events that can be exported to your computer. This tool adds support for subscription and starting and ending datetimes of events to the calendar.

"The users of Edmodo can post assignments, create polls for student responses, embed video clips, create learning groups, post quizzes for students to take, and creating a calendar for events and assignments. Students can also turn in assignments or upload assignments for their teachers to view and grade. Teachers can annotate the assignments directly in Edmodo to provide instant feedback." (Source)

Demo can be found here.
Full implementation can be downloaded here.

Automating the authenticating process

Edmodo Planner is a calendar service that requires a user to authenticate since it displays user related events. To make the calendar available for public subscription, or even to get access to the events, the user authentication process has to be automated for accessing Edmodo Planner’s export functionality. This export functionality returns the iCal file which is a common used file format for internet calendars. By making this iCal file publicly available (meaning no authentication is required) users can subscribe to the related URL so their calendar events are updated periodically.

Authenticating is done by sending your credentials to Edmodo via a POST request. According to whether the credentials are correct you get a related response body with HTML code returned. Besides the response body a Set-Cookie header is included, its value is saved on your computer (as a cookie) and injected in every future request to the host during its lifetime. Websites use cookies to assign a server-side file containing specific session data to visitors. After authenticating the server-side file is edited containing new data like the user’s first and last name. Because cookies are send back to the host the requests are identified as a specific user meaning personal content can be generated, like a greeting with your registered name.

Image can't be loaded

Above you see the authentication request in the network developer tool window. According to the Content-Length request headers 31 bytes are transmitted as request body. These bytes contain your credentials formed in key-value pairs. The key names are required for later purposes because these have to be included in the automated request. To find out the key names, click on the params tab or note the name attributes of the input tags.


When logging in with correct credentials the response has a 302 status code. If the credentials are incorrect a status code of 200 and a website is returned. We can use these characteristics to validate whether the authentication process succeeded.

Lets check if simply sending the form data is sufficient as authenticating process.

$ curl -v -o /dev/null -d "username=USERNAME,password=PASSWORD" https://www.edmodo.com
< HTTP/1.1 200 OK  
< Set-Cookie: edtr=***; expires=Thu, 21-Sep-2034 13:20:35 GMT; path=/; domain=edmodo.com;  
< Set-Cookie: EDMODOSESSID=***; path=/; domain=.edmodo.com; secure; HttpOnly  

For some reason we keep getting the 200 status code back meaning the authentication process failed, even when using correct credentials. When simulating the authentication request in the browser a Set-Cookie header is returned, and after clicking the "Log in" button its content is send back. Maybe this cookie is required for logging in. Lets test this by first opening the home page, reading the Set-Cookie value and writing it back with the POST request.

$ curl -s -o /dev/null -c /tmp/cookie https://www.edmodo.com

$ cat /tmp/cookie
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_.edmodo.com   TRUE    /       TRUE    0       EDMODOSESSID    ***
#HttpOnly_.edmodo.com   TRUE    /       TRUE    2042456367      edtr    ***

$ curl –c /tmp/cookie –b /tmp/cookie -v -o /dev/null -d "username=USERNAME&password=PASSWORD" https://www.edmodo.com
< HTTP/1.1 302 Found  
< Location: /home  
< Set-Cookie: edtr=***; expires=Thu, 21-Sep-2034 13:20:35 GMT; path=/; domain=edmodo.com;  
< Set-Cookie: EDMODOSESSID=***; path=/; domain=.edmodo.com; secure; HttpOnly  

The authentication process succeeded. Lets see if we can reach Edmodo Planner’s export functionality using the formed cookies.

$ curl –c /tmp/cookie –b /tmp/cookie https://www.edmodo.com/calendar/ics

Supporting starting and ending datetimes

We can use the python-icalendar module for parsing and changing the exported iCal file. For example the attributes X-WR-CALNAME and X-WR-CALDESC should be changed since Edmodo leaves these at "Sample Calendar". After setting the global calendar attributes we loop through every other component available. If the component is of the type event we call a specific method that contains the implementation for supporting event starting and ending datetimes .

There must be something to recognize the starting and ending time by. Lets assume they are always included in the title (in the SUMMARY attribute) in a standard 24 hour format. Trusting on this assumption we can build an implementation that parses these times, and converts and stores them as starting and ending datetimes.

For parsing the start and end time I created a regular expression that matches two timestamps where:

  • the first (start time) and second (end time) timestamp can be split by a "-" with optional spaces, or simply a single space;
  • the second timestamp (end time) is optional;
  • the delimiter between hour and minutes can be ":" or "-".

If the event suddenly contains starting and ending datetimes a miracle occurred meaning Edmodo finally supports it. When no starting or ending dates are attached to the event the whole process can be skipped since there is nothing the parsed times can be add up to.

If the start time is successfully parsed it can be combined with the starting date, the resulting datetime is set as event start. If the end time is successfully parsed it is combined with the ending date and set as event end. If no end time is available the event duration will be set one hour.

Edited on 2015-08-16: Instead of writing your own parser you can also - and probably should - use existing libraries like Moment.js and Knwl.js.