{"id":13557246,"url":"https://github.com/hypothesis/lms","last_synced_at":"2025-08-15T04:38:26.805Z","repository":{"id":37401868,"uuid":"108909388","full_name":"hypothesis/lms","owner":"hypothesis","description":"LTI app for integrating with learning management systems","archived":false,"fork":false,"pushed_at":"2025-08-04T08:03:53.000Z","size":25788,"stargazers_count":49,"open_issues_count":203,"forks_count":15,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-08-04T10:58:53.259Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hypothesis.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,"zenodo":null}},"created_at":"2017-10-30T21:15:37.000Z","updated_at":"2025-08-04T08:03:56.000Z","dependencies_parsed_at":"2023-10-02T08:00:03.350Z","dependency_job_id":"65ddd9f8-29fb-49f0-8e59-a59c52bd600f","html_url":"https://github.com/hypothesis/lms","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hypothesis/lms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypothesis%2Flms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypothesis%2Flms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypothesis%2Flms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypothesis%2Flms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hypothesis","download_url":"https://codeload.github.com/hypothesis/lms/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hypothesis%2Flms/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270524428,"owners_count":24600195,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-15T02:00:12.559Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-08-01T12:04:14.269Z","updated_at":"2025-08-15T04:38:26.785Z","avatar_url":"https://github.com/hypothesis.png","language":"Python","funding_links":[],"categories":["Python","others"],"sub_categories":[],"readme":"\u003ca href=\"https://github.com/hypothesis/lms/actions/workflows/ci.yml?query=branch%3Amain\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/hypothesis/lms/ci.yml?branch=main\"\u003e\u003c/a\u003e\n\u003ca\u003e\u003cimg src=\"https://img.shields.io/badge/python-3.12-success\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/hypothesis/lms/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-BSD--2--Clause-success\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/hypothesis/cookiecutters/tree/main/pyramid-app\"\u003e\u003cimg src=\"https://img.shields.io/badge/cookiecutter-pyramid--app-success\"\u003e\u003c/a\u003e\n\u003ca href=\"https://black.readthedocs.io/en/stable/\"\u003e\u003cimg src=\"https://img.shields.io/badge/code%20style-black-000000\"\u003e\u003c/a\u003e\n\n# LMS\n\nAn app for integrating Hypothesis with Learning Management Systems (LMS's).\n\nSee also:\n\n* [Configuration](docs/configuration.md) - Details of environment variables and setup\n* [Setting up a region](docs/setting-up-a-region.md) - How to setup a new geographic region\n\n## Setting up Your LMS Development Environment\n\nFirst you'll need to install:\n\n* [Git](https://git-scm.com/).\n  On Ubuntu: `sudo apt install git`, on macOS: `brew install git`.\n* [GNU Make](https://www.gnu.org/software/make/).\n  This is probably already installed, run `make --version` to check.\n* [pyenv](https://github.com/pyenv/pyenv).\n  Follow the instructions in pyenv's README to install it.\n  The **Homebrew** method works best on macOS.\n  The **Basic GitHub Checkout** method works best on Ubuntu.\n  You _don't_ need to set up pyenv's shell integration (\"shims\"), you can\n  [use pyenv without shims](https://github.com/pyenv/pyenv#using-pyenv-without-shims).\n* [Docker Desktop](https://www.docker.com/products/docker-desktop/).\n  On Ubuntu follow [Install on Ubuntu](https://docs.docker.com/desktop/install/ubuntu/).\n  On macOS follow [Install on Mac](https://docs.docker.com/desktop/install/mac-install/).\n* [Node](https://nodejs.org/) and npm.\n  On Ubuntu: `sudo snap install --classic node`.\n  On macOS: `brew install node`.\n* [Yarn](https://yarnpkg.com/): `sudo npm install -g yarn`.\n\nThen to set up your development environment:\n\n```terminal\ngit clone https://github.com/hypothesis/lms.git\ncd lms\nmake services\nmake devdata\nmake help\n```\n\nTo run LMS locally run `make dev` and visit http://localhost:8001.\n\n## Changing the Project's Python Version\n\nTo change what version of Python the project uses:\n\n1. Change the Python version in the\n   [cookiecutter.json](.cookiecutter/cookiecutter.json) file. For example:\n\n   ```json\n   \"python_version\": \"3.10.4\",\n   ```\n\n2. Re-run the cookiecutter template:\n\n   ```terminal\n   make template\n   ```\n\n3. Re-compile the `requirements/*.txt` files.\n   This is necessary because the same `requirements/*.in` file can compile to\n   different `requirements/*.txt` files in different versions of Python:\n\n   ```terminal\n   make requirements\n   ```\n\n4. Commit everything to git and send a pull request\n\n## Changing the Project's Python Dependencies\n\n### To Add a New Dependency\n\nAdd the package to the appropriate [`requirements/*.in`](requirements/)\nfile(s) and then run:\n\n```terminal\nmake requirements\n```\n\n### To Remove a Dependency\n\nRemove the package from the appropriate [`requirements/*.in`](requirements)\nfile(s) and then run:\n\n```terminal\nmake requirements\n```\n\n### To Upgrade or Downgrade a Dependency\n\nWe rely on [Dependabot](https://github.com/dependabot) to keep all our\ndependencies up to date by sending automated pull requests to all our repos.\nBut if you need to upgrade or downgrade a package manually you can do that\nlocally.\n\nTo upgrade a package to the latest version in all `requirements/*.txt` files:\n\n```terminal\nmake requirements --always-make args='--upgrade-package \u003cFOO\u003e'\n```\n\nTo upgrade or downgrade a package to a specific version:\n\n```terminal\nmake requirements --always-make args='--upgrade-package \u003cFOO\u003e==\u003cX.Y.Z\u003e'\n```\n\nTo upgrade **all** packages to their latest versions:\n\n```terminal\nmake requirements --always-make args=--upgrade\n```\n\n## HTTPS/SSL setup\n\n### Using self signed certificates with HTTPS\n\nBy default `make dev` runs the web application on two ports: 8001 for HTTP and 48001 for HTTPS with a self-signed certificate.\n\nUsing HTTPS is required in most LMS's for LTI 1.3 and for example in D2L it's required for any usage of their API in all LTI versions.\n\nTo use HTTPS you'll need to instruct your browser to trust the self-signed certificate.\n\nIn Chrome you can do do this with the following flag:\n\n\n\u003cchrome://flags/#allow-insecure-localhost\u003e\n\n\n### Bypassing the browser's \"unsafe scripts\" (mixed content) blocking\n\nIf you use our hosted Canvas instance at \u003chttps://hypothesis.instructure.com/\u003e\nto test your local dev instance of the app you'll get \"unsafe scripts\" or \"mixed content\"\nwarnings from your browser. This is because hypothesis.instructure.com uses https but your\nlocal dev app, which is running in an iframe in hypothesis.instructure.com, only uses http.\n\nYou'll see a blank iframe in Canvas where the app should be, along with a warning about\n\"trying to launch insecure content\" like this:\n\n![\"Trying to launch insecure content\" error](docs/images/trying-to-launch-insecure-content.png \"'Trying to launch insecure content' error\")\n\nIf you open the browser's developer console you should see an error message like:\n\n    Mixed Content: The page at 'https://hypothesis.instructure.com/...' was loaded over HTTPS,\n    but requested an insecure form action 'http://localhost:8001/...'. This request has been\n    blocked; the content must be served over HTTPS.\n\nFortunately you can easily bypass this mixed content blocking by your browser.\nYou should also see an \"Insecure content blocked\" icon in the top right of the location bar:\n\n![\"Insecure content blocked\" dialog](docs/images/insecure-content-blocked.png \"'Insecure content blocked' dialog\")\n\nClick on the \u003csamp\u003eLoad unsafe scripts\u003c/samp\u003e link and the app should load successfully.\n\n\n### Localhost alias\n\nSome services that the LMS app integrates with (eg. Canvas Studio) do not allow\nthe use of `localhost` in OAuth callback URLs. For this reason we use\n`https://hypothesis.local` URLs in some places. To make this work you must\ndeclare `hypothesis.local` as an alias for `127.0.0.1` in your `/etc/hosts` file.\n\n## Overview and code design\n\nThere are three presentations for developers that describe what the Hypothesis LMS app is and how it works. The **speaker notes** in these presentations also contain additional notes and links:\n\n1. [LMS App Demo \u0026 Architecture](https://docs.google.com/presentation/d/1eRMjS5B8Yja6Aupp8oKi-UztIJ9_8KRViSc6OMDLfMY/)\n2. [LMS App Code Design Patterns](https://docs.google.com/presentation/d/1AWcDoHaV9aAvInefR54SJepZiNM08Zou9jxNssccw3c/)\n3. [Speed Grader Workshop](https://docs.google.com/presentation/d/1TJF9SXRMbtHCPnkD9sy-TXe_u55--zYt6veVW0M6leA/) (about the design of the first version of our Canvas Speed Grader support)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypothesis%2Flms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhypothesis%2Flms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypothesis%2Flms/lists"}