{"id":20015186,"url":"https://github.com/corytodd/rendezvous","last_synced_at":"2026-05-06T04:31:12.179Z","repository":{"id":70535950,"uuid":"114508683","full_name":"corytodd/rendezvous","owner":"corytodd","description":"Digital classroom engagement tracking","archived":false,"fork":false,"pushed_at":"2017-12-17T16:27:23.000Z","size":1681,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-25T09:24:55.068Z","etag":null,"topics":["chrome-extension","flask","gatech","online-learning"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/corytodd.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-17T04:14:29.000Z","updated_at":"2020-06-16T14:38:10.000Z","dependencies_parsed_at":"2023-03-11T08:43:12.467Z","dependency_job_id":null,"html_url":"https://github.com/corytodd/rendezvous","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/corytodd/rendezvous","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corytodd%2Frendezvous","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corytodd%2Frendezvous/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corytodd%2Frendezvous/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corytodd%2Frendezvous/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/corytodd","download_url":"https://codeload.github.com/corytodd/rendezvous/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corytodd%2Frendezvous/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32678571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T02:33:58.958Z","status":"ssl_error","status_checked_at":"2026-05-06T02:33:39.611Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chrome-extension","flask","gatech","online-learning"],"created_at":"2024-11-13T07:45:17.984Z","updated_at":"2026-05-06T04:31:12.141Z","avatar_url":"https://github.com/corytodd.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rendezvous\nA browser extension for your digital classroom\n\n## Why?\nThis was developed for my course project in CS 6460 at Georgia Tech. See the [formal report](https://github.com/corytodd/rendezvous/blob/master/ctodd_student_attrition_distance_learning.pdf) citing the \"why\" and the \"how\". In a nutshell, this tool provides a high-level analysis of your engagement on the Piazza course platform.\n\nThis is built on top of the unofficial Piazza API from [here](https://github.com/hfaran/piazza-api).\n\n## Disclaimer\n\nThis is not an official API or an official integration. I am not affiliated with Piazza Technologies Inc. in any way, and am not responsible for any damage that could be done with it. Use it at your own risk.\n\n## Chrome Extension\nDue do limitations in how data is acquired, this plugin is not immediately useful to people unless they happen to be in the same courses as myself. For this reason, the plugin is unlisted since I don't really want to get saturated with \"this doesn't work\" comments.\nThe Chrome plugin is available\n[here](https://chrome.google.com/webstore/detail/cs6460/blfopmdikjopbnkefkhmokknalhcejfk). \n\n\n\n## Project layout\nEveything following this line was required for the submission of my project. I'm leaving it intact for reference.  \n\nThe code for the project is outlined in the following  sections. Each heading corresponding to \nthe respective directory relative to the package root.\n\n## api\nThis directory contains the actual backend service. This is a Flask application\nwritten in Python 3.6. It uses PeeWee ORM for managing the database and relational models.\nTextBlob is used for NLP. Everything else is hand-rolled for speed and simplicity.\n\nThe layout is fairly straight forward. The entry point is standard for Flask apps and is \nlocation in app.py. This file sets up the database connection and defines all of our routes.\nHad this been a larger backend, the routes would have been segregated but I kept\nthe routine simple by only exposing three REST endpoints.\n\nThe resources package contains all of the data models that are managed by the ORM. \n\n- Courses: Maps course name to Piazza id. The ID is what you see in the URL, also called \nthe network id. The id for CS6460 is j6azklk4gaf4v9.\n- Stats: Holds all the statistics for a student's online engagement. As you can see,\nthere is nothing directly identifying students and most of the content is simply\ncalculated or aggregate in nature.\n- Scrape: This module performs the important task of actually scraping the data from\nPiazza and processing into into a Stats model. The PiazzaPost model is an intermediate\nform that is used for passing structure data between the parser and the NLP processor.\n- User: Maps a user to their authentication secret and the courses that they are enrolled in.\nThis too is light on identifiable data and only stores the Piazza student ID and a\nrandom secret that has no derivation from the user identity.\n\nThe common lib holds all the modules that are not specific to web requests. This\nincludes the low-level database, datetime handlers, and of course the NLP. The NLP\nmodules does most of the interesting calculations. The CSS gradient stuff is all\nhandled in the util module.\n\nThe database is interesting because this had the highest cost potential. The naive\nstorage method saw hundreds of MBs of storage without any clear purpose. The refined version\nbrought this down to a few hundred KBs with much less post-processing effort. A double-win\nis that we are no longer storing Piazza information, only composite data. With this small amount\nof data, we solve the problem of updating user data because we can simply dump everything and \nrecalculate as often as needed. We're only storing numbers that are meaningful to us so even\nif someone were to get the database, the data is worthless.\n\nOverall, I'm very proud of this module. It is well tested and well documented. There\nwill of course be things I'd like to refactor but those are more stylistic changes\nthat fundamental transgressions.\n\n## api_test\nThis is the unit test suite in which we achieved 91% code coverage. Emphasis was\nplaced on accuracy of the date methods and Piazza content extraction as these are\ncritical components. The actual Piazza scraping is not tested as that is a 3rd\nparty library. I've mocked this service out were appropriate to facilitate regression\ntesting. Also, because I'm nice person I've built in a random throttle so this service\ndoes not knock Piazza over during our scrape sessions.\n\nUnit testing uses the Python unittest package and there isn't much more to it.\n\n## chrome\nThe chrome plugin lives in this directory. As described in the manifest,\nit requires access to your tabs, cookies, and storage. I use the tabs API\nto determine the course name and ID. I use the cookies API to locate the Piazza\ncookie that contains the user id string. I then use the storage API to persist the \nuser authentication tuple. This is nice because it follows your browser without\nany extra effort. \n\nFor the UI, this is using Materialize CSS and some of my hand-rolled classes.\nFor javascript, I keep things simple and avoided the nightmare that all these\nmodern frameworks have become. I did indulge a bit with jQuery though because\nthat makes the code much more concise. One exception is my use of chart.js because\nthere is not point in making your graph library. Chart.js is simple and free\nso I use that for generating the pie charts.\n\nThe only Chrome specific code is located in popup.js and background.js. The latter\nis used as a listener to enable and disable the extension based on if the user is\non a Piazza website. Popup.js does all the authentication, ajax, and rendering.\nDue to the nature of Chrome extensions, it is infinitely easier to keep as much\nof your logic in a single file as possible. Had this been a normal project, the code\nwould certainly be more spread out.\n\nPopup.html is barebones as I generated most of the html dynamically. What is does provide\nhowever, are the base div anchors and library imports so the Chrome extension doesn't\nholler about security. This is actually why I host my own libs instead of using\nCDNs. Google is very strict about cross-site scripting and for good reason.\n\nTo load the development version of the plugin, refer to the Google developer's page:\n[https://developer.chrome.com/extensions/getstarted#unpacked](https://developer.chrome.com/extensions/getstarted#unpacked)\n\n## Private\nMove along, nothing to see here.\n\n## Tools\nThis is my hacking ground for mocking, testing, experimenting, and making things\nbend to my will. The main module provides a command line interface for a variety of\ntools that I used to explore Piazza, parsing, and the most effecient ways to store \nmy data. THe project was bootstrapped from the early work done in this module.\n\n## Ready to Rock\nSee [setup_uwsgi](setup_uwsgi.md) to get started with the server.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorytodd%2Frendezvous","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcorytodd%2Frendezvous","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorytodd%2Frendezvous/lists"}