Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full support for extended base URLs #15

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
080c0e4
Update the renderer for the restructuring of PG.
drgrice1 Aug 4, 2022
673c76d
Merge pull request #7 from drgrice1/pg-environment-work
drdrew42 May 22, 2023
f5968be
add message listener for modifying css
drdrew42 Jan 3, 2023
a52dfdc
add class manipulation and standardize behavior
drdrew42 Jan 5, 2023
4cf54c1
adjust for restructured incoming cssUpdate object
drdrew42 Jan 6, 2023
332b554
new endpoints for copy and delete from private
drdrew42 Jan 6, 2023
c2629b0
catalogue all files, not just .pg
drdrew42 Jan 10, 2023
af26884
allow sessionJWT to restore AttemptsTable
drdrew42 Mar 9, 2023
1e954d8
improve answerURL response handling
drdrew42 Apr 8, 2023
e7bb999
support postMessage "showSolutions"
drdrew42 May 9, 2023
6358737
Static file support if baseURL is nonempty
drdrew42 May 19, 2023
accb165
Convert static URLs from relative to absolute
drdrew42 May 19, 2023
3799b11
Convert all problem requests to JWT
drdrew42 May 19, 2023
381c1ff
do not require provided sourcecode to be in base64
drdrew42 May 22, 2023
3ac56a0
refactor and cleanup
drdrew42 May 22, 2023
11ef91a
convert to WW2.18 mojo::template approach
drdrew42 Jun 6, 2023
a9f746d
reorganization and file cleanup
drdrew42 Jun 10, 2023
246eb21
fix preview logic
drdrew42 Jun 12, 2023
7165c98
remove PGaddons
drdrew42 Jun 12, 2023
4372a28
call this function!
drdrew42 Jun 12, 2023
f1ad558
Dockerfile and documentation update
drdrew42 Jun 14, 2023
acf1828
proper handling of hideButton options
drdrew42 Jun 20, 2023
77bbf19
properly serve entire app with extended base URL
drdrew42 Jun 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
lib/WeBWorK/htdocs/** linguist-vendored
public/** linguist-vendored
*.pl linguist-language=Perl
2 changes: 0 additions & 2 deletions .github/CODEOWNERS

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/createContainer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Github Packages Release
on:
push:
branches:
- master
- main
- development
tags:
- v*
Expand Down
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ lib/WeBWorK/bin/*
webwork-open-problem-library/
private/
tmp/*
!tmp/.gitkeep
logs/*.log

node_modules
node_modules/*
public/**/*.min.js
public/**/*.min.css
public/static-assets.json

*.o
*.pm.tdy
*.bs
Expand Down
16 changes: 11 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
FROM ubuntu:20.04
LABEL org.opencontainers.image.source=https://github.com/drdrew42/renderer
MAINTAINER drdrew42
LABEL org.opencontainers.image.source=https://github.com/openwebwork/renderer

WORKDIR /usr/app
ARG DEBIAN_FRONTEND=noninteractive
Expand All @@ -11,10 +10,8 @@ RUN apt-get update \
apt-utils \
git \
gcc \
npm \
make \
curl \
nodejs \
dvipng \
openssl \
libc-dev \
Expand Down Expand Up @@ -43,6 +40,9 @@ RUN apt-get update \
libmath-random-secure-perl \
libdata-structure-util-perl \
liblocale-maketext-lexicon-perl \
libyaml-libyaml-perl \
&& curl -fsSL https://deb.nodesource.com/setup_16.x | bash - \
&& apt-get install -y --no-install-recommends --no-install-suggests nodejs \
&& apt-get clean \
&& rm -fr /var/lib/apt/lists/* /tmp/*

Expand All @@ -51,7 +51,13 @@ RUN cpanm install Mojo::Base Statistics::R::IO::Rserve Date::Format Future::Asyn

COPY . .

RUN cd lib/WeBWorK/htdocs && npm install && cd ../../..
RUN cp render_app.conf.dist render_app.conf

RUN cp conf/pg_config.yml lib/PG/conf/pg_config.yml

RUN cd public/ && npm install && cd ..

RUN cd lib/PG/htdocs && npm install && cd ../../..

EXPOSE 3000

Expand Down
14 changes: 9 additions & 5 deletions Dockerfile_with_OPL
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
FROM ubuntu:20.04
LABEL org.opencontainers.image.source=https://github.com/drdrew42/renderer
MAINTAINER drdrew42
LABEL org.opencontainers.image.source=https://github.com/openwebwork/renderer

WORKDIR /usr/app
ARG DEBIAN_FRONTEND=noninteractive
Expand All @@ -11,10 +10,8 @@ RUN apt-get update \
apt-utils \
git \
gcc \
npm \
make \
curl \
nodejs \
dvipng \
openssl \
libc-dev \
Expand Down Expand Up @@ -43,6 +40,9 @@ RUN apt-get update \
libmath-random-secure-perl \
libdata-structure-util-perl \
liblocale-maketext-lexicon-perl \
libyaml-libyaml-perl \
&& curl -fsSL https://deb.nodesource.com/setup_16.x | bash - \
&& apt-get install -y --no-install-recommends --no-install-suggests nodejs \
&& apt-get clean \
&& rm -fr /var/lib/apt/lists/* /tmp/*

Expand All @@ -64,7 +64,11 @@ COPY . .

RUN cp render_app.conf.dist render_app.conf

RUN cd lib/WeBWorK/htdocs && npm install && cd ../../..
RUN cp conf/pg_config.yml lib/PG/conf/pg_config.yml

RUN npm install

RUN cd lib/PG/htdocs && npm install && cd ../../..

EXPOSE 3000

Expand Down
212 changes: 140 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# WeBWorK Standalone Problem Renderer & Editor

![Commit Activity](https://img.shields.io/github/commit-activity/m/drdrew42/renderer?style=plastic)
![License](https://img.shields.io/github/license/drdrew42/renderer?style=plastic)

![Commit Activity](https://img.shields.io/github/commit-activity/m/openwebwork/renderer?style=plastic)
![License](https://img.shields.io/github/license/openwebwork/renderer?style=plastic)

This is a PG Renderer derived from the WeBWorK2 codebase
* https://github.com/openwebwork/WeBWorK2

## DOCKER CONTAINER INSTALL ###
* [https://github.com/openwebwork/webwork2](https://github.com/openwebwork/webwork2)

```
## DOCKER CONTAINER INSTALL

```bash
mkdir volumes
mkdir container
git clone https://github.com/openwebwork/webwork-open-problem-library volumes/webwork-open-problem-library
git clone --recursive https://github.com/drdrew42/renderer container/
git clone --recursive https://github.com/openwebwork/renderer container/
docker build --tag renderer:1.0 ./container

docker run -d \
Expand All @@ -25,35 +25,43 @@ docker run -d \
renderer:1.0
```

If you have non-OPL content, it can be mounted as a volume at `/usr/app/private` by adding the following line to the `docker run` command:
If you have non-OPL content, it can be mounted as a volume at `/usr/app/private` by adding the following line to the
`docker run` command:

```
```bash
--mount type=bind,source=/pathToYourLocalContentRoot,target=/usr/app/private \
```

A default configuration file is included in the container, but it can be overridden by mounting a replacement at the application root. This is necessary if, for example, you want to run the container in `production` mode.
A default configuration file is included in the container, but it can be overridden by mounting a replacement at the
application root. This is necessary if, for example, you want to run the container in `production` mode.

```
```bash
--mount type=bind,source=/pathToYour/render_app.conf,target=/usr/app/render_app.conf \
```

## LOCAL INSTALL ###
## LOCAL INSTALL

If using a local install instead of docker:

* Clone the renderer and its submodules: `git clone --recursive https://github.com/drdrew42/renderer`
* Clone the renderer and its submodules: `git clone --recursive https://github.com/openwebwork/renderer`
* Enter the project directory: `cd renderer`
* Install perl dependencies listed in Dockerfile (CPANMinus recommended)
* Install Perl dependencies listed in Dockerfile (CPANMinus recommended)
* clone webwork-open-problem-library into the provided stub ./webwork-open-problem-library
- `git clone https://github.com/openwebwork/webwork-open-problem-library ./webwork-open-problem-library`
* `git clone https://github.com/openwebwork/webwork-open-problem-library ./webwork-open-problem-library`
* copy `render_app.conf.dist` to `render_app.conf` and make any desired modifications
* install other dependencies
- `cd lib/WeBWorK/htdocs`
- `npm install`
* start the app with `morbo ./script/render_app` or `morbo -l http://localhost:3000 ./script/render_app` if changing root url
* copy `conf/pg_config.yml` to `lib/PG/pg_config.yml` and make any desired modifications
* install third party JavaScript dependencies
* `cd private/`
* `npm install`
* `cd ..`
* install PG JavaScript dependencies
* `cd lib/PG/htdocs`
* `npm install`
* start the app with `morbo ./script/render_app` or `morbo -l http://localhost:3000 ./script/render_app` if changing
root url
* access on `localhost:3000` by default or otherwise specified root url

# Editor Interface
## Editor Interface

* point your browser at [`localhost:3000`](http://localhost:3000/)
* select an output format (see below)
Expand All @@ -64,55 +72,115 @@ If using a local install instead of docker:

![image](https://user-images.githubusercontent.com/3385756/129100124-72270558-376d-4265-afe2-73b5c9a829af.png)

# Renderer API
Can be interfaced through `/render-api`

## Parameters
| Key | Type | Default Value | Required | Description | Notes |
| --- | ---- | ------------- | -------- | ----------- | ----- |
| problemSourceURL | string | null | true if `sourceFilePath` and `problemSource` are null | The URL from which to fetch the problem source code | Takes precedence over `problemSource` and `sourceFilePath`. A request to this URL is expected to return valid pg source code in base64 encoding. |
| problemSource | string (base64 encoded) | null | true if `problemSourceURL` and `sourceFilePath` are null | The source code of a problem to be rendered | Takes precedence over `sourceFilePath`. |
| sourceFilePath | string | null | true if `problemSource` and `problemSourceURL` are null | The path to the file that contains the problem source code | Can begin with Library/ or Contrib/, in which case the renderer will automatically adjust the path relative to the webwork-open-problem-library root. Path may also begin with `private/` for local, non-OPL content. |
| problemSeed | number | NA | true | The seed to determine the randomization of a problem | |
| psvn | number | 123 | false | used for consistent randomization between problems | |
| formURL | string | /render-api | false | the URL for form submission | |
| baseURL | string | / | false | the URL for relative paths | |
| format | string | '' | false | Determine how the response is formatted ('html' or 'json') ||
| outputFormat | string (enum) | static | false | Determines how the problem should render, see below descriptions below | |
| language | string | en | false | Language to render the problem in (if supported) | |
| showHints | number (boolean) | 1 | false | Whether or not to show hints (restrictions apply) | Irrelevant if `permissionLevel >= 10`, in which case `showHints` is regarded as automatically 'true' |
| showSolutions | number (boolean) | 0 | false | Whether or not to show the solutions (restrictions apply) | Irrelevant if `permissionLevel >= 10`, in which case `showSolutions` is regarded as automatically 'true' |
| permissionLevel | number | 0 | false | Affects the rendering of hints and solutions. Also controls display of scaffold problems (possibly more) | See the levels we use below |
| problemNumber | number | 1 | false | We don't use this | |
| numCorrect | number | 0 | false | The number of correct attempts on a problem | |
| numIncorrect | number | 1000 | false | the number of incorrect attempts on this problem | Relevant for triggering hints that are not immediately available |
| processAnswers | number (boolean) | 1 | false | Determines whether or not answer json is populated, and whether or not problem_result and problem_state are non-empty | |
| answersSubmitted | number (boolean) | ? | false? | Determines whether to process form-data associated to the available input fields | |
| showSummary | number (boolean) | ? | false? | Determines whether or not to show the summary result of processing the form-data associated with `answersSubmitted` above ||
| showComments | number (boolean) | 0 | false | Renders author comment field at the end of the problem ||
| includeTags | number (boolean) | 0 | false | Includes problem tags in the returned JSON | Only relevant when requesting `format: 'json'` |

## Output Format
| Key | Description |
| ----- | ----- |
| static | zero buttons, locked form fields (read-only) |
| nosubmit | zero buttons, editable (for exams, save problem state and submit all together) |
| single | one submit button (intended for graded content) |
| classic | preview + submit buttons |
| simple | preview + submit + show answers buttons |
| practice | check answers + show answers buttons |

## Permission level
| Key | Value |
| --- | ----- |
| student | 0 |
| prof | 10 |
| admin | 20 |

## Permission logic summary for hints and solutions
* If `permissionLevel >= 10`, then hints and solutions will be rendered - no exceptions.
* If `permissionLevel < 10`, then:
- solutions (if they are provided in the pg source code) will be rendered if and only if `showSolutions` is true.
- hints (if they are provided in the pg source code) will be rendered if and only if:
+ `showHints` is true, and
+ `numCorrect + numIncorrect > n` where `n` is set by the pg sourcce code being rendered
## Server Configuration

Modification of `baseURL` may be necessary to separate multiple services running on `SITE_HOST`, and will be used to extend `SITE_HOST`. The result of this extension will serve as the root URL for accessing the renderer (and any supplementary assets it may need to provide in support of a rendered problem). If `baseURL` is an absolute URL, it will be used verbatim -- userful if the renderer is running behind a load balancer.

By default, `formURL` will further extend `baseURL`, and serve as the form-data target for user interactions with problems rendered by this service. If `formURL` is an absolute URL, it will be used verbatim -- useful if your implementation intends to sit in between the user and the renderer.

## Renderer API

Can be accessed by POST to `{SITE_HOST}{baseURL}{formURL}`.

By default, `localhost:3000/render-api`.

### **REQUIRED PARAMETERS**

The bare minimum of parameters that must be included are:
* the code for the problem, so, **ONE** of the following (in order of precedence):
* `problemSource` (raw pg source code, _can_ be base64 encoded)
* `sourceFilePath` (relative to OPL `Library/`, `Contrib/`; or in `private/`)
* `problemSourceURL` (fetch the pg source from remote server)
* a "seed" value for consistent randomization
* `problemSeed` (integer)

| Key | Type | Description | Notes |
| --- | ---- | ----------- | ----- |
| problemSource | string (possibly base64 encoded) | The source code of a problem to be rendered | Takes precedence over `sourceFilePath`. |
| sourceFilePath | string | The path to the file that contains the problem source code | Renderer will automatically adjust `Library/` and `Contrib/` relative to the webwork-open-problem-library root. Path may also begin with `private/` for local, non-OPL content. |
| problemSourceURL | string | The URL from which to fetch the problem source code | Takes precedence over `problemSource` and `sourceFilePath`. A request to this URL is expected to return valid pg source code in base64 encoding. |
| problemSeed | number | The seed that determines the randomization of a problem | |

**ALL** other request parameters are optional.

### Infrastructure Parameters

The defaults for these parameters are set in `render_app.conf`, but these can be overridden on a per-request basis.

| Key | Type | Default Value | Description | Notes |
| --- | ---- | ------------- | ----------- | ----- |
| baseURL | string | '/' (as set in `render_app.conf`) | the URL for relative paths | |
| formURL | string | '/render-api' (as set in `render_app.conf`) | the URL for form submission | |

### Display Parameters

#### Formatting

Parameters that control the structure and templating of the response.

| Key | Type | Default Value | Description | Notes |
| --- | ---- | ------------- | ----------- | ----- |
| language | string | en | Language to render the problem in (if supported) | affects the translation of template strings, _not_ actual problem content |
| _format | string | 'html' | Determine how the response is _structured_ ('html' or 'json') | usually 'html' if the user is directly interacting with the renderer, 'json' if your CMS sits between user and renderer |
| outputFormat | string | 'default' | Determines how the problem should be formatted | 'default', 'static', 'PTX', 'raw', or |
| displayMode | string | 'MathJax' | How to prepare math content for display | 'MathJax' or 'ptx' |

#### User Interactions

Control how the user is allowed to interact with the rendered problem.

Requesting `outputFormat: 'static'` will prevent any buttons from being included in the rendered output, regardless of the following options.

| Key | Type | Default Value | Description | Notes |
| --- | ---- | ------------- | ----------- | ----- |
| hidePreviewButton | number (boolean) | false | "Preview My Answers" is enabled by default | |
| hideCheckAnswersButton | number (boolean) | false | "Submit Answers" is enabled by default | |
| showCorrectAnswersButton | number (boolean) | `isInstructor` | "Show Correct Answers" is disabled by default, enabled if `isInstructor` is true (see below) | |

#### Content

Control what is shown to the user: hints, solutions, attempt results, scores, etc.

| Key | Type | Default Value | Description | Notes |
| --- | ---- | ------------- | ----------- | ----- |
| permissionLevel | number | 0 | **DEPRECATED.** Use `isInstructor` instead. |
| isInstructor | number (boolean) | 0 | Is the user viewing the problem an instructor or not. | Used by PG to determine if scaffolds can be allowed to be open among other things |
| showHints | number (boolean) | 1 | Whether or not to show hints | |
| showSolutions | number (boolean) | `isInstructor` | Whether or not to show the solutions | |
| hideAttemptsTable | number (boolean) | 0 | Hide the table of answer previews/results/messages | If you have a replacement for flagging the submitted entries as correct/incorrect |
| showSummary | number (boolean) | 1 | Determines whether or not to show a summary of the attempt underneath the table | Only relevant if the Attempts Table is shown `hideAttemptsTable: false` (default) |
| showComments | number (boolean) | 0 | Renders author comment field at the end of the problem | |
| showFooter | number (boolean) | 0 | Show version information and WeBWorK copyright footer | |
| includeTags | number (boolean) | 0 | Includes problem tags in the returned JSON | Only relevant when requesting `_format: 'json'` |

## Using JWTs

There are three JWT structures that the Renderer uses, each containing its predecessor:
* problemJWT
* sessionJWT
* answerJWT

### ProblemJWT

This JWT encapsulates the request parameters described above, under the API heading. Any value set in the JWT cannot be overridden by form-data. For example, if the problemJWT includes `isInstructor: 0`, then any subsequent interaction with the problem rendered by this JWT cannot override this setting by including `isInstructor: 1` in the form-data.

### SessionJWT

This JWT encapsulates a user's attempt on a problem, including:
* the text and LaTeX versions of each answer entry
* count of incorrect attempts (stopping after a correct attempt, or after `showCorrectAnswers` is used)
* the problemJWT

If stored (see next), this JWT can be submitted as the sole request parameter, and the response will effectively restore the users current state of interaction with the problem (as of their last submission).

### AnswerJWT

If the initial problemJWT contains a value for `JWTanswerURL`, this JWT will be generated and sent to the specified URL. The answerJWT is the only content provided to the URL. The renderer is intended to to be user-agnostic. It is recommended that the JWTanswerURL specify the unique identifier for the user/problem combination. (e.g. `JWTanswerURL: 'https://db.yoursite.org/grades-api/:user_problem_id'`)

For security purposes, this parameter is only accepted when included as part of a JWT.

This JWT encapsulates the status of the user's interaction with the problem.
* score
* sessionJWT

The goal here is to update the `JWTanswerURL` with the score and "state" for the user. If you have uses for additional information, please feel free to suggest as a GitHub Issue.
Loading