From 6b0c733a49510e2603a7766d79f9778f3f8ff536 Mon Sep 17 00:00:00 2001 From: Mimis Chlympatsos Date: Mon, 18 Dec 2023 09:27:17 -0500 Subject: [PATCH 01/14] RESTful API documentation for api/sections_controller actions (#200) --- RESTful-API.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/RESTful-API.md b/RESTful-API.md index 3662909..06864e1 100644 --- a/RESTful-API.md +++ b/RESTful-API.md @@ -1194,3 +1194,15 @@ NOTE: the folder_path string can include a nested path if the folder to be remov ### GET /api/courses/:course_id/starter_file_groups/:id/download_entries - description: Download a zip archive containing all entries (files and folders) in this starter file group + +### POST /api/courses/:course_id/sections + +- description: Create a new section for the given course. +- required parameters: + - section + - name (string) + +### DELETE /api/courses/:course_id/sections/:id + +- description: Delete the section uniquely identified by the given course and section id's. +- NOTE: The section must be non-empty (must not have any students). From eda102c5ed266d0649caa067b956d4961a1f894d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:02:43 +0000 Subject: [PATCH 02/14] [pre-commit.ci] pre-commit autoupdate (#202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/igorshubovych/markdownlint-cli: v0.37.0 → v0.38.0](https://github.com/igorshubovych/markdownlint-cli/compare/v0.37.0...v0.38.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index db15e9a..d40b1f3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.37.0 + rev: v0.38.0 hooks: - id: markdownlint args: ["--fix"] From c50a511718a975dd6bb5ba27f50e7e0f797e01c2 Mon Sep 17 00:00:00 2001 From: Mimis Chlympatsos Date: Fri, 29 Mar 2024 16:22:39 -0400 Subject: [PATCH 03/14] Rest-API documentation for Assignment #destroy. (#201) --- RESTful-API.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/RESTful-API.md b/RESTful-API.md index 06864e1..82ae893 100644 --- a/RESTful-API.md +++ b/RESTful-API.md @@ -657,6 +657,15 @@ NOTE: the "AdminRole" type can only be used by AdminUser users - has_peer_review (boolean) - starter_file_type (one of "simple", "sections", "shuffle", "group") +### DELETE /api/courses/:course_id/assignments/:id + +- description: Delete the assignment corresponding to the given course and assignment id's, if it has no groups. +- required parameters: + - id (integer) + - course_id (integer) + +NOTE: this is only available to authorised instructors (or admins) + ### GET /api/courses/:course_id/assignments/:id/test_files - description: Download a zip file containing all autotesting test files for this assignment From 3e2f6857d31f08644e36d4747fec9d73decc22ba Mon Sep 17 00:00:00 2001 From: Mimis Chlympatsos Date: Fri, 29 Mar 2024 16:23:12 -0400 Subject: [PATCH 04/14] More Section API controller routes (#206) --- RESTful-API.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/RESTful-API.md b/RESTful-API.md index 82ae893..1319396 100644 --- a/RESTful-API.md +++ b/RESTful-API.md @@ -1215,3 +1215,17 @@ NOTE: the folder_path string can include a nested path if the folder to be remov - description: Delete the section uniquely identified by the given course and section id's. - NOTE: The section must be non-empty (must not have any students). + +### PUT /api/courses/:course_id/sections/:id + +- description: Update the section uniquely identified by the given course and section id's. +- required parameters: + - name (string) + +### GET /api/courses/:course_id/sections + +- description: Get all sections for this course + +### GET /api/courses/:course_id/sections/:id + +- description: Get the section uniquely identified by the given course and section id's. From a5d79ec9a229d5ae032dd528bbb49d2bb796382d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:23:26 -0400 Subject: [PATCH 05/14] [pre-commit.ci] pre-commit autoupdate (#205) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d40b1f3..93da26f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.38.0 + rev: v0.39.0 hooks: - id: markdownlint args: ["--fix"] From d86818cc1d850456f92ae7b7b4cb4e6b502c92c6 Mon Sep 17 00:00:00 2001 From: Pranav Rao <56097527+pranavrao145@users.noreply.github.com> Date: Sun, 31 Mar 2024 08:04:35 -0400 Subject: [PATCH 06/14] docs(tas-see-starter-files): added docs about starter file visibility for graders (#207) --- Instructor-Guide--Assignments--Starter-Files.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Instructor-Guide--Assignments--Starter-Files.md b/Instructor-Guide--Assignments--Starter-Files.md index 794545e..feab1a4 100644 --- a/Instructor-Guide--Assignments--Starter-Files.md +++ b/Instructor-Guide--Assignments--Starter-Files.md @@ -82,3 +82,7 @@ This is useful when using either of the "random" rules to see how the files were Students will be able to download the starter files according to the starter file rules you have set on this page. If you would like to download an example of these starter files, click the "Download starter files example" link (in the "Starter File Assignment Rules" section). Note that if the rules that you have chosen involve randomly assigning files, each time you click the link you may get different files. + +## Starter File Visibility for Graders + +Note that all graders of an assignment will have read-only access to the "Starter Files" tab under "Settings" on the assignment page, where they can view starter file groups and the rules the instructor sets on how to assign them. Furthermore, they will be able to download starter file mappings and example starter files. However, they cannot modify starter files or how they are assigned, unless they are authorized to do so. From 6dd31acf0cfab664fab6bf9097ad73acfa4eb838 Mon Sep 17 00:00:00 2001 From: Bruce Liu <65298191+Bruce-8@users.noreply.github.com> Date: Sun, 7 Apr 2024 09:46:36 -0400 Subject: [PATCH 07/14] Add documentation for instructor-configured end date for student automated tests (#208) --- ...tor-Guide--Assignments--Automated-Testing.md | 2 +- images/automated-testing-student-run.png | Bin 8799 -> 0 bytes images/automted-testing-student-run.png | Bin 0 -> 48343 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 images/automated-testing-student-run.png create mode 100644 images/automted-testing-student-run.png diff --git a/Instructor-Guide--Assignments--Automated-Testing.md b/Instructor-Guide--Assignments--Automated-Testing.md index f547ef4..a0e5f2c 100644 --- a/Instructor-Guide--Assignments--Automated-Testing.md +++ b/Instructor-Guide--Assignments--Automated-Testing.md @@ -250,7 +250,7 @@ You may customize this feature using the following settings: - **Tokens available on** This allows you to set the date and time of when you would like the students to begin testing. If you wish for the students to begin testing immediately simply set this field to the current date and time. - > :spiral_notepad: **NOTE:** Students will be allowed to start tests up until the assignment deadline INCLUDING all extensions. +- **Tokens available until** This allows you to set the date and time of when you would like to disable testing. If you wish for the tests to run up until the assignment due date simply leave this field blank. - **Tokens regenerate after** This allows you to set the time it takes for tokens to regenerate. Once a token has been used, it will be unavailable until X hours have passed, at which point the students may use that token to perform another test. If you wish for tokens not to regenerate, select the "Tokens do not regenerate" checkbox. diff --git a/images/automated-testing-student-run.png b/images/automated-testing-student-run.png deleted file mode 100644 index fe8e1713be4b9adbf82ab15c36ac222c2c3b3acc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8799 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�-X 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 kSlXI8yBOL!{J-0 Date: Fri, 19 Apr 2024 15:08:42 -0400 Subject: [PATCH 08/14] Update Docker setup instructions (#209) --- Developer-Guide--Set-Up-With-Docker.md | 185 ++++++++++++++----------- 1 file changed, 103 insertions(+), 82 deletions(-) diff --git a/Developer-Guide--Set-Up-With-Docker.md b/Developer-Guide--Set-Up-With-Docker.md index 9ab8498..987b3ce 100644 --- a/Developer-Guide--Set-Up-With-Docker.md +++ b/Developer-Guide--Set-Up-With-Docker.md @@ -1,93 +1,93 @@ # Developer Guide: Set Up with Docker -## Downloading and Installing - If you want to get started on working on MarkUs quickly and painlessly, this is the way to do it. +## Downloading and Installing + 1. If you are using **Windows**, you will need to install Windows Subsystem for Linux (WSL) by following the instructions on [this page](https://docs.microsoft.com/en-us/windows/wsl/install-win10). (The "Simplified Installation" section is probably easiest, but you need to join the Windows Insiders Program with a Microsoft account.) - - If you are given a choice of what operating system to use, select *Ubuntu 20.04*. + - If you are given a choice of which operating system to use, select *Ubuntu 22.04*. -2. Install [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/). +2. Install [Docker](https://docs.docker.com/get-docker/). - On Windows, make sure you've selected the "WSL 2 backend" tab under "System Requirements" and follow those instructions. - On Linux, also follow the instructions on "Manage Docker as a non-root user" [here](https://docs.docker.com/install/linux/linux-postinstall/). 3. If you are using **Windows**, you'll need to open a terminal into the WSL system you installed. *This is the terminal where you'll type in the rest of the commands in this section.* - 1. To start the WSL terminal, open the start menu and type in "ubuntu". Click on the "Ubuntu 20.04" application. (We recommend pinning this to your taskbar to make it easier to find in the future.) + 1. To start the WSL terminal, open the start menu and type in "ubuntu". Click on the "Ubuntu 22.04" application. (We recommend pinning this to your taskbar to make it easier to find in the future.) 2. Type in the command `pwd`, which shows what folder you're currently in. You should see `/home/` printed. If it isn't, switch to your home directory using the command `cd ~`. -4. Clone the Markus repository from GitHub by following the instructions in [Setting up Git and MarkUs](Developer-Guide--Setting-up-Git.md). (This is a document you will want to read very carefully and may come back to.) +4. Clone the Markus repository. 5. Change into the repository that you just cloned: `cd Markus`. -6. Run `docker compose build app`. +6. If you are on **Windows (WSL)** or **Linux**, you will need to configure Docker to make sure the application files are owned by a user with the same UID on your host machine as in the containers: - 1. On Linux running docker engine (not docker desktop): you will need to make sure that the files are owned by a user with the same UID on your host machine as in the container: - - Create a file named `docker-compose.override.yml` in the root directory of the MarkUs code (should be your current directory) - - Discover your current UID by running the `id -u` command - - Write the following to the newly created `docker-compose.override.yml` file (replace 1001 with the UID that you discovered in the previous step): + 1. Run the command `id -u`. If the output is `1001` you can skip this the rest of this step and move onto Step 7 below. Otherwise, keep going. + 2. Follow the first two steps in the [Installing and Configuring RubyMine](#installing-and-configuring-rubymine) section below to open the MarkUs repository in RubyMine. + 3. In the MarkUs repository, create a new top-level file named `compose.override.yaml`. + 4. Copy and paste the following text into the `compose.override.yaml` file, replacing `` with the number returned by `id -u` earlier. - ```yml - services: - app: + ```yml + services: + app: + build: + args: + UID: + rails: + build: + args: + UID: + ssh: + build: + args: + UID: + resque: + build: + args: + UID: + resque-scheduler: build: - args: - UID: 1001 - ``` + args: + UID: + webpack: + build: + args: + UID: + ``` - - now you can run `docker compose build app` +7. Run `docker compose build app`. -7. Run `docker compose up rails`. The first time you run this it will take a long time because it'll install all of MarkUs' dependencies, and then seed the MarkUs application with sample data before actually running the server. When the server actually starts, you'll see some terminal output that looks like: +8. Run `docker compose up rails`. The first time you run this it will take a long time because it'll install all of MarkUs' dependencies, and then seed the MarkUs application with sample data before actually running the server. When the server actually starts, you'll see some terminal output that looks like: ```text - Puma starting in cluster mode... - * Version 4.3.1 (ruby 2.5.3-p105), codename: Mysterious Traveller - * Min threads: 0, max threads: 16 - * Environment: development - * Process workers: 3 - * Preloading application - * Listening on tcp://0.0.0.0:3000 - Use Ctrl-C to stop - - Worker 0 (pid: 185) booted, phase: 0 - - Worker 1 (pid: 193) booted, phase: 0 - - Worker 2 (pid: 201) booted, phase: 0 + => Booting Puma + => Rails 7.1.3.2 application starting in development + => Run `bin/rails server --help` for more startup options + [1] Puma starting in cluster mode... + [1] * Puma version: 6.4.2 (ruby 3.0.2-p107) ("The Eagle of Durango") + [1] * Min threads: 0 + [1] * Max threads: 5 + [1] * Environment: development + [1] * Master PID: 1 + [1] * Workers: 3 + [1] * Restarts: (✔) hot (✖) phased + [1] * Preloading application + [1] * Listening on http://0.0.0.0:3000 + [1] Use Ctrl-C to stop + [1] - Worker 0 (PID: 71) booted in 0.01s, phase: 0 + [1] - Worker 1 (PID: 75) booted in 0.01s, phase: 0 + [1] - Worker 2 (PID: 77) booted in 0.01s, phase: 0 ``` - 1. On **Windows**, open a separate WSL terminal (but leave the current one running), and type in the command `docker compose run --rm rails bash`. This will take you into the Docker container; you'll see the prompt change to `app/$`. - - 2. Run the command `rails js:routes`, which will take a moment to generate a required file. - -8. Open your web browser and type in the URL `localhost:3000/csc108`. The initial page load might be slow, but eventually you should see a login page. Use the username `instructor` and any non-empty password to login. +9. Open your web browser and type in the URL `localhost:3000/csc108`. The initial page load might be slow, but eventually you should see a login page. Use the username `instructor` and any non-empty password to login. *Tip*: to terminate the Rails server, go to the terminal window where the server is running and press `Ctrl + C`/`⌘ + C`. - On Windows Home Edition, you'll need to use the Docker container's IP address instead: `192.168.99.100:3000/csc108`. -9. In a new terminal window, go into the Markus directory again and run `docker compose run rails rspec` to run the MarkUs test suite. This will take several minutes to run, but all tests should pass. - - **Troubleshooting** - - - If you see a test failing with the following message near the top: - - ```text - 1) SubmissionsController#get_file When the file is a jupyter notebook file should download the file as is - Failure/Error: _stdout, stderr, status = Open3.capture3(*args, stdin_data: file_contents) - - Errno::ENOENT: - No such file or directory - /app/nbconvertvenv/bin/jupyter-nbconvert - ``` - - Run the following commands: - - ```console - docker compose run --rm rails bash # This takes you into the Docker container - python3.8 -m venv /app/nbconvertvenv - /app/nbconvertvenv/bin/pip install wheel nbconvert - ``` - - Then try re-running the tests. You can do this from your current terminal (inside the Docker container) simply by running `rspec`. +10. In a new terminal window, go into the Markus directory again and run `docker compose run --rm rails rspec` to run the MarkUs test suite. This will take several minutes to run, but all tests should pass. Hooray! You have MarkUs up and running. Please keep reading for our recommended developer setup. @@ -99,7 +99,7 @@ We strongly recommend RubyMine (a JetBrains IDE) for all MarkUs development. 2. Open the MarkUs repository in RubyMine. - - On Windows, your repository will be located at `\\wsl$\Ubuntu-20.04\home\\Markus`. + - On Windows, your repository will be located at `\\wsl$\Ubuntu-22.04\home\\Markus`. 3. Complete the setup steps under [Docker: Enable Docker Support JetBrains guide](https://www.jetbrains.com/help/ruby/docker.html#enable_docker). @@ -117,7 +117,7 @@ We strongly recommend RubyMine (a JetBrains IDE) for all MarkUs development. ## Installing Pre-Commit Hooks -We use [pre-commit](https://pre-commit.com/) to run automated checks on code before each commit. To set this up on your local computer (not in Docker): +We use [pre-commit](https://pre-commit.com/) to run automated checks on code before each commit. To set this up on your local computer (*not* in a Docker container): 1. First, install Python 3. 2. Then, install the pre-commit library: `$ python3 -m pip install pre-commit` (or just `python` instead of `python3`, depending on your Python executable. @@ -133,11 +133,11 @@ After this, these checks will run every time you make a commit. If all checks pa Here's a summary of the few most common tasks you'll use in your development. - Start the MarkUs server: `docker compose up --no-recreate rails` -- Run the MarkUs rspec test suite: `docker compose run rails rspec` -- Run a specific rspec test file: `docker compose run rails rspec FILE` -- Run the Markus Jest test suite: `docker compose run rails npm run test` -- Run the Markus Jest test suite with the test coverage shown: `docker compose run rails npm run test-cov` -- Run a specific Jest test file: `docker compose run rails npm run test FILE` +- Run the MarkUs rspec test suite: `docker compose run --rm rails rspec` +- Run a specific rspec test file: `docker compose run --rm rails rspec FILE` +- Run the Markus Jest test suite: `docker compose run --rm rails npm run test` +- Run the Markus Jest test suite with the test coverage shown: `docker compose run --rm rails npm run test-cov` +- Run a specific Jest test file: `docker compose run --rm rails npm run test FILE` - Start a shell within the Docker Rails environment: `docker compose run --rm rails bash`. Within this shell, you can: - Install new dependencies: `bundle install`, `npm ci` @@ -197,7 +197,7 @@ If the `rails db:autotest_run` fails, you can still run the tests manually in yo ## Setting up ActionMailer -If you plan on doing work that involves sending/recieving emails from MarkUs, you will need to [configure ActionMailer](https://guides.rubyonrails.org/action_mailer_basics.html). To get you started quickly on setting up ActionMailer and understanding what it is used for in MarkUs, follow the instructions outlined in [Enabling ActionMailer In Development](Developer-Guide--Tips-And-Tricks--Enabling-ActionMailer-In-Development.md). +If you plan on doing work that involves sending/receiving emails from MarkUs, you will need to [configure ActionMailer](https://guides.rubyonrails.org/action_mailer_basics.html). To get you started quickly on setting up ActionMailer and understanding what it is used for in MarkUs, follow the instructions outlined in [Enabling ActionMailer In Development](Developer-Guide--Tips-And-Tricks--Enabling-ActionMailer-In-Development.md). ## Troubleshooting @@ -208,8 +208,8 @@ If you plan on doing work that involves sending/recieving emails from MarkUs, yo I'm writing frontend code. The files I've changed should according to the Webpack config files trigger Webpack rebuild, but that's not happening. I've verified that 1. My changes are valid and should be displayed from the URL I'm accessing. -2. There are no errors in the Webpacker container's logs. -3. If I run `npm run build-dev` in the Webpacker container's console directly, it succeeds and I'm able to see my changes afterwards. +2. There are no errors in the webpack container's logs. +3. If I run `npm run build-dev` in the webpack container's console directly, it succeeds and I'm able to see my changes afterwards. ### A1 @@ -220,11 +220,11 @@ I'm writing frontend code. The files I've changed should according to the Webpac When I run `docker compose up rails`, or when I restart my previously created `rails` container, I get a warning/error along the lines of ```MARKDOWN -markus-rails-1 | system temporary path is world-writable: /tmp -markus-rails-1 | /tmp is world-writable: /tmp -markus-rails-1 | . is not writable: /app -markus-rails-1 | Exiting -markus-rails-1 | /usr/lib/ruby/3.0.0/tmpdir.rb:39:in `tmpdir': could not find a temporary directory (ArgumentError) +system temporary path is world-writable: /tmp +/tmp is world-writable: /tmp +. is not writable: /app +Exiting +/usr/lib/ruby/3.0.0/tmpdir.rb:39:in `tmpdir': could not find a temporary directory (ArgumentError) [...stacktrace] ``` @@ -232,26 +232,24 @@ after following the setup guide step by step. I've looked into my host setup and ### A2 -It's unclear exactly why or how this occured, but one fix is as simple as using another directory for this purpose. Ruby reads a variety of environment variables (env vars) to determine the system's temporary directory that it can use, and you can customize that directory with an env var. Both warnings/errors are complaining about the same thing: no available `TMPDIR`. +It's unclear exactly why or how this occurred, but one fix is as simple as using another directory for this purpose. Ruby reads a variety of environment variables (env vars) to determine the system's temporary directory that it can use, and you can customize that directory with an env var. Both warnings/errors are complaining about the same thing: no available `TMPDIR`. Since this is not a wide-spread issue, it's more reasonable to have the setup living entirely on your local (i.e. ignored by git) than committing it to the repo. -1. Start by creating a `docker-compose.override.yml` file under Markus root. Notice that the filename is already listed in `.gitignore`. +1. Start by creating a `compose.override.yaml` file under Markus root. Notice that the filename is already listed in `.gitignore`. 2. The general idea is simple - configure `TMPDIR`, then pass this configuration in. Now we need to find a potential `TMPDIR` candidate inside the container. Reading gives us an idea of what ruby expects (at the time of writing, Markus was in ruby 3.0, but this file shouldn't expect major changes in the future versions. If it starts using other env var(s), update this documentation to reflect the new env var(s)). 3. You can find a directory in the rails container with the correct permissions (1777) & that is unused by Markus, or create your own. In my case `/var/tmp` fit the profile. 1. I found the directory by starting a shell in the `rails` container with `docker exec -it` and then running `find -type d -perm 1777` -4. Write this env var into the `docker-compose.override.yml` file you created. For example: +4. Write this env var into the `compose.override.yaml` file you created. For example: ```YAML - version: '3.7' - services: - rails: - environment: - - TMPDIR=/var/tmp + rails: + environment: + - TMPDIR=/var/tmp ``` -5. Save your changes. After `docker compose build app`, make sure you run `docker compose -f docker-compose.override.yml docker-compose.yml up rails` instead of just `docker compose up rails`. This will apply the `TMPDIR` we created, which would resolve the issue. +5. Save your changes. After `docker compose build app`, make sure you run `docker compose -f compose.override.yaml compose.yaml up rails` instead of just `docker compose up rails`. This will apply the `TMPDIR` we created, which would resolve the issue. ### Q3 @@ -291,3 +289,26 @@ Again, it's unclear exactly why this happened, but there's a fix. 4. Once `rails` container is up, start a shell inside it and run `bundle exec rails db:prepare`. Without running this, you won't be able to browse markus UI. 1. If for whatever reason this command fails, try `rails db:drop && rails db:create && rails db:migrate && rails db:seed` instead. 5. The downside is you'll have to redo this process every time the containers are recreated, but otherwise this should resolve the issue. Verify that the `schema_migrations` tables now contain the correct number of migration records. + +### Q4 + +I'm seeing a test failing with the following message near the top: + +```text +1) SubmissionsController#get_file When the file is a jupyter notebook file should download the file as is + Failure/Error: _stdout, stderr, status = Open3.capture3(*args, stdin_data: file_contents) + + Errno::ENOENT: + No such file or directory - /app/nbconvertvenv/bin/jupyter-nbconvert +``` + +### A4 + +Run the following commands: + +```console +docker compose run --rm rails bash # This takes you into the Docker container +./venv/bin/python3 -m pip install -r requirements-jupyter.txt +``` + +Then try re-running the tests. You can do this from your current terminal (inside the Docker container) simply by running `rspec`. From 61b475568e90ab62b346d1a68ba0e081cb3d94dc Mon Sep 17 00:00:00 2001 From: Samuel Maldonado Date: Sun, 21 Apr 2024 14:36:59 -0400 Subject: [PATCH 09/14] Add bulk-print info (#210) --- ...ide--Assignments--Marking--Grading-View.md | 8 ++++++-- images/bulk_print.png | Bin 0 -> 12651 bytes images/print.png | Bin 7589 -> 8262 bytes 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 images/bulk_print.png diff --git a/Instructor-Guide--Assignments--Marking--Grading-View.md b/Instructor-Guide--Assignments--Marking--Grading-View.md index fdd997b..1dcb02f 100644 --- a/Instructor-Guide--Assignments--Marking--Grading-View.md +++ b/Instructor-Guide--Assignments--Marking--Grading-View.md @@ -110,13 +110,17 @@ MarkUs also allows you to print a submission with the print button. This will print all PDF files that have been submitted as a single PDF file, along with a cover page which provides information about the students in a group, the mark received on each criterion, a list of all annotations on the submission, and any overall comment that has been left during grading. +You can also bulk print from the submissions table. + +![Bulk Print Button](images/bulk_print.png) + ![Printed Assignment Cover Page](images/printed-assignment-cover-page.png) -In the output pdf, the location of each annotation will also be marked. +For PDF files, the location of each annotation will be marked in the output. ![Printed Assignment Annotation](images/printed-assignment-annotation.png) -> :spiral_notepad: **NOTE**: Only PDF files are supported for printing. If a submission contains files of other types, they will not be printed. +> :spiral_notepad: **NOTE**: `.pdf` and `.ipynb` are the only file formats supported for printing. If a submission contains files of other types, they will not be printed. ## Annotations diff --git a/images/bulk_print.png b/images/bulk_print.png new file mode 100644 index 0000000000000000000000000000000000000000..237e79ccedade8c9542fbfacfb6845faf7c3d00d GIT binary patch literal 12651 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 RtqlMG002ovPDHLkV1gfhj>Z50 delta 6771 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 V99;%QBJKbH002ovPDHLkV1i-DOe+8Y From 86b3b177889c103cfb52531e0baa139ff867de10 Mon Sep 17 00:00:00 2001 From: David Liu Date: Sun, 21 Apr 2024 15:56:53 -0400 Subject: [PATCH 10/14] Remove old git information for developers --- Developer-Guide--Setting-up-Git.md | 237 ----------------------------- 1 file changed, 237 deletions(-) delete mode 100644 Developer-Guide--Setting-up-Git.md diff --git a/Developer-Guide--Setting-up-Git.md b/Developer-Guide--Setting-up-Git.md deleted file mode 100644 index 234289d..0000000 --- a/Developer-Guide--Setting-up-Git.md +++ /dev/null @@ -1,237 +0,0 @@ -# MarkUs, Git and GitHub: How it Works - -## Installation - -First, you'll need to [install Git](https://git-scm.com/downloads) onto your computer. -If you already have Git installed, we recommend [updating to the latest version](https://confluence.atlassian.com/bitbucketserver/installing-and-upgrading-git-776640906.html). - -**Important**: if you are developing MarkUs on Windows, you should be using WSL to manage your repository, which means you'll need to [Install Git on WSL](https://docs.microsoft.com/en-us/windows/wsl/tutorials/wsl-git) instead of on Windows directly. -All of the commands on this page should be run in the WSL 2 terminal (e.g., Ubuntu 20.04), not the regular Windows terminal (cmd.exe). - -## Overview - -![Workflow](images/markus-git-workflow.png) - -Note that the following few paragraphs might be a bit confusing. Hang in there, there are always people around you can ask. - -### Setting up MarkUs - -1. Open a GitHub account and set up an [SSH public key for Git](https://help.github.com/articles/generating-ssh-keys) -2. Set up your Git configuration settings. - - ```console - git config --global user.name "First-name Last-name" - git config --global user.email "your-email@example.com" - ``` - - You may omit the `--global` switch if you wish. Make sure to read up on the differences between global and non-global git configuration, though. Thanks. -3. Ask an Admin to add you as a MarkUs developer. - -4. Visit the [MarkUs GitHub repository](https://github.com/MarkUsProject/Markus) and press “Fork”. This will create a clone of the repository for your GitHub account. - -5. From your fork, copy the URL that allows you to access it using SSH. In the terminal, navigate to your intended local development directory, and run the following command using the URL you just copied. - - ```console - git clone git@github.com:YOUR_GIT_USERNAME/Markus.git - ``` - - This will create a new local "Markus" folder with a copy of your repository. - -6. Next, create a "remote" to the master repository of MarkUs upstream. This will be used to keep your local copy up to date. - - ```console - git remote add upstream git@github.com:MarkUsProject/Markus.git - ``` - - Note the remote origin should point to the SSH URL you cloned with. If this URL contains “https”, then you have not cloned using SSH. Run the following command to change it to the URL used when cloning. - - ```console - git remote set-url origin git@github.com:YOUR_GIT_USERNAME/Markus.git - ``` - -7. Make sure the remote was added. The following command should output "upstream" and "origin". - - ```console - git remote -v - ``` - -### MarkUs Development Workflow - -The steps involved until your code ends up in the main MarkUs repository are the following: - -1. Create and switch to a feature branch based on up to date local master branch - - ```console - git branch issue-1234 - git checkout issue-1234 - ``` - -2. Modify the files with the changes you want to implement. To check which files you've modified, as well as view your changes, use: - - ```console - git status - git diff - ``` - -3. Commit your changes (small commits are beautiful) on your feature branch - - ```console - git add path/to/file.rb - git commit -m "Fix for issue 1234: Implemented x behaviour in file.rb" - ``` - -4. Repeat Steps 2 & 3 until you are satisfied with your work and want to contribute to the main MarkUs repository. - -5. Before setting up a review request, make sure your issue and master branches are up to date (see section below), making sure the change-sets you just pulled in do not affect your code. - -6. Ready to submit? Push your branch to your personal MarkUs fork: - - ```console - git push origin issue-1234 - ``` - -7. Go to your GitHub fork and change to your issue branch. You should see the button "Pull Request". Fill in the issue number, quick summary of the issue, description of the fix, and what testing was performed. - -8. Click "Create Pull Request" and wait for feedback! - -### The Three MarkUs Git Repositories - -In the above picture you can see 3 main Git repositories you will interact with. The most important ones are your forked MarkUs repository (this is most likely the only MarkUs Git repository on GitHub you have read+write access to) and the clone of this repository on your local machine. If you do branch sharing with another team member that's a slightly different story and beyond the point of giving a brief overview. - -### Your Fork of the MarkUs Git Repository - -You, as a developer, will be mainly working on the locally cloned MarkUs Git repository (of your fork). Add to that quite frequent pushes to your fork on GitHub, so that other developers can test your code easily (due to a current review board limitation). In order to create a pull request you'd also want to push your feature branch onto GitHub. This interaction is represented in the above picture by the large green arrow. - -### Keeping Your Local Code Up-To-Date - -Also note the dashed arrow coming from the main ("upstream") MarkUs Git repository and pointing to your local clone of your personal MarkUs Github fork. This arrow represents interaction you have to do to keep up-to-date with the authoritative MarkUs repository, which is constantly being updated by other developers on the MarkUs team. (More on how you can do this later.) - -This subsection describes the steps you need to take to make sure your local repository is up-to-date. Generally, your `master` branch should mirror the contents of `upstream/master`, the master branch of the main MarkUs repository. Remember that **you should be doing all development on local feature branches, NOT your local master branch**! This makes merging as painless as possible. - -If this sounds too confusing for you, don't worry, we are here to help. - -1. Make sure you have already set up your "upstream" remote. (See Steps 5 and 6 of "Setting up MarkUs" above.) - -2. Switch to your local `master` branch. - - ```console - git checkout master - ``` - -3. Update the current local branch with the `master` branch of the `upstream` repository. - - ```console - git pull upstream master - ``` - - Note: if you've followed our advice and done your development only on feature branches, this step shouldn't produce any merge errors! - -4. If you're currently working on a feature branch, switch back to that branch and merge the new changes in. This step might require some manual merging. - - ```console - git checkout issue-1234 - git merge master - ``` - - Rather than running `git merge master`, you may want to *rebase* to HEAD of `upstream/master` instead, by running the following: - - ```console - git rebase upstream/master - ``` - -If this doesn't mean anything to you, you may want to ask for help first. Seriously, ask for help! There's always somebody around to clarify things. :) - -### Next Steps - -The next step should be to continue reading this document and post questions you may have on IRC or the markus-dev mailing list. - -## Git Tricks - -### Useful Commands - -- View what changes you have made on branch `issue-1234`. - - ```console - git diff --full-index master issue-1234 - ``` - -- Temporarily put your changes aside to have a cleanly tracked branch. - - ```console - git stash - ``` - -- Bring these changes back (even onto another branch, as long as it is within the same repository) - - ```console - git stash pop - ``` - -- Remove all changes made to a specific file. - - ```console - git checkout - ``` - -- Revert all changes made to the current branch. **WARNING: All changes will be lost.** - - ```console - git reset --hard HEAD - ``` - -- Once your branch `issue-1234` has been integrated into `master`, you might want to delete it. - - ```console - git branch -d issue-1234 - ``` - -- You might want to see who modified a line last, and what other changes they brought in with that commit. - - ```console - git blame config/routes.rb - ``` - - You can also use the GitHub interface for this by clicking "Blame" when viewing a file, which will take you to a page like [this](https://github.com/MarkUsProject/Markus/blame/master/config/routes.rb). - -### Issues & Solutions - -**I forgot to create an issue branch and instead made changes to my master branch. I have not committed anything yet.** - -- Create and move to a new issue branch and then commit. You don't lose your uncommited changes when moving to another branch. - - ```console - git branch issue-1234 - git checkout issue-1234 - ``` - -**I made x number of commits to my master branch and forgot to create an issue branch.** - -- Let's say you want `master` to go back to state C, and move D and E to the new branch. Here's what it looks like at first: - - ```text - A-B-C-D-E (HEAD) - ↑ - master - ``` - - After creating a new branch using `git branch issue-1234`: - - ```text - issue-1234 - ↓ - A-B-C-D-E (HEAD) - ↑ - master - ``` - - Note that the current branch is still `master`. We now move this branch back by 2 commits using `git reset --hard HEAD~2`. You *will* lose uncommitted work here! - - ```text - issue-1234 - ↓ - A-B-C-D-E (HEAD) - ↑ - master - ``` - - Finally, switch over to the new branch and get to work: `git checkout issue-1234`. From 2525f4ac8d20bdf318cffc5a01056cc471ccecf1 Mon Sep 17 00:00:00 2001 From: Pranav Rao <56097527+pranavrao145@users.noreply.github.com> Date: Sun, 28 Apr 2024 10:29:02 -0400 Subject: [PATCH 11/14] docs(fix-docker-build-command): build all images instead of just app (#211) --- Developer-Guide--Set-Up-With-Docker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Developer-Guide--Set-Up-With-Docker.md b/Developer-Guide--Set-Up-With-Docker.md index 987b3ce..e69f230 100644 --- a/Developer-Guide--Set-Up-With-Docker.md +++ b/Developer-Guide--Set-Up-With-Docker.md @@ -57,7 +57,7 @@ If you want to get started on working on MarkUs quickly and painlessly, this is UID: ``` -7. Run `docker compose build app`. +7. Run `docker compose build`. 8. Run `docker compose up rails`. The first time you run this it will take a long time because it'll install all of MarkUs' dependencies, and then seed the MarkUs application with sample data before actually running the server. When the server actually starts, you'll see some terminal output that looks like: From b9b3636ff95e0e14004730bb0e27f3f3e2618921 Mon Sep 17 00:00:00 2001 From: Samuel Maldonado Date: Fri, 10 May 2024 07:48:33 -0400 Subject: [PATCH 12/14] add remote validation setting (#213) --- Configuration.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Configuration.md b/Configuration.md index 4568b19..f0a4cc0 100644 --- a/Configuration.md +++ b/Configuration.md @@ -81,6 +81,7 @@ queues: redis: url: # url of a running redis database validate_file: # (See "User Authentication Options" below) +remote_validate_file: # (See "User Authentication Options" below) validate_ip: # (See "User Authentication Options" below) validate_custom_status_message: # (See "User Authentication Options" below) validate_user_not_allowed_message: # (See "User Authentication Options" below) @@ -220,6 +221,12 @@ validate_custom_status_message: local_auth_login_name: shibboleth ``` +Additionally, MarkUs can be set to restrict remote logins based on username and/or IP when using remote authentication. + +**To enable restricted remote authentication, set the following setting:** + +- `remote_validate_file:` an absolute path to a script that expects input from stdin (user name, password (blank), and IP address; separated by "\n") and returns 0 if the user is authenticated and any other positive integer otherwise. + ### Logout redirect The `logout_redirect` setting determines where the user will be redirected when they logout of MarkUs. It can be one of `DEFAULT`, `NONE`, or a URL. From 411c2bcbfaef6307088753eb0dd877579f1cf7f1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 02:23:03 +0000 Subject: [PATCH 13/14] [pre-commit.ci] pre-commit autoupdate (#212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.5.0 → v4.6.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.5.0...v4.6.0) - [github.com/igorshubovych/markdownlint-cli: v0.39.0 → v0.41.0](https://github.com/igorshubovych/markdownlint-cli/compare/v0.39.0...v0.41.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93da26f..9f25404 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.39.0 + rev: v0.41.0 hooks: - id: markdownlint args: ["--fix"] From c1da2b9020dcab22d25fff4a54b1feaaabd8b0d6 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 12 Aug 2024 18:56:37 +0000 Subject: [PATCH 14/14] Update documentation for LTI course creation filtering (#215) --- Configuration.md | 6 ++++++ Learning-Tools-Interoperability.md | 10 +++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Configuration.md b/Configuration.md index f0a4cc0..8c10210 100644 --- a/Configuration.md +++ b/Configuration.md @@ -277,3 +277,9 @@ If you wish to use Learning Tools Interoperability (LTI) with Markus, you'll nee You must also create a private key for generating Javascript Web Tokens to sign LTI requests. A private key can be automatically created with the `markus:lti_key` rake task. + +If you wish to filter course creation requests from LTI deployments, add the following keys: + +- `lti.course_filter_file` must be the absolute path to a Ruby file that defines a method `LtiConfig::allowed_to_create_course?(lti_deployment)`, which takes an `LtiDeployment` model instance and returns `true` or `false`. +- `lti.unpermitted_new_course_message` must be a message to display if an LTI deployment is rejected by the filter. The message must be a string with interpolation key `%{course_name}`, which will be bound to the `title` field in the launch claim `https://purl.imsglobal.org/spec/lti/claim/context`. + - Example: `"You are not permitted to create a new MarkUs course for %{course_name}. Please contact your system administrator."` diff --git a/Learning-Tools-Interoperability.md b/Learning-Tools-Interoperability.md index 0ae5533..70d1f0e 100644 --- a/Learning-Tools-Interoperability.md +++ b/Learning-Tools-Interoperability.md @@ -58,12 +58,16 @@ Canvas course and your MarkUs course must be made. Click 'Launch MarkUs' in your Canvas course. If you are not logged in to MarkUs, you will be prompted to do so. Once you are logged in, you will be presented with a list of MarkUs courses for which you are an instructor. Select the course that matches your Canvas -course and submit the form. If your course does not appear in the list, -you may click 'Create New Course', which will create a new -course based on the Canvas course information with you as an instructor. +course and submit the form. ![MarkUs Link Canvas Course](images/lti-link-course.png) +If your course does not appear in the list, +you may click 'Create New Course', to request a new +course based on the Canvas course information with you as an instructor. + +*Warning*: your system administrator may restrict which Canvas courses can trigger the creation of a new course on MarkUs. + #### Creating a Grade Book entry for a MarkUs Assignment Once a course association has been established, each assignment will