GithubHelp home page GithubHelp logo

mitodl / sga-lti Goto Github PK

View Code? Open in Web Editor NEW
2.0 11.0 2.0 445 KB

an LTI implementation of Staff Graded Assignments, for use with edX

License: BSD 3-Clause "New" or "Revised" License

Makefile 0.15% Shell 0.46% Python 75.69% HTML 19.09% JavaScript 3.92% Dockerfile 0.58% Procfile 0.03% SCSS 0.08%

sga-lti's Introduction

sga-lti

sga-lti:LTI implementation of Staff Graded Assignments
Version:0.4.1
Author:MIT Office of Digital Learning
Homepage:http://odl.mit.edu
License:BSD

an LTI implementation of Staff Graded Assignments, for use with edX

Getting Started

You can either run this locally with a default sqlite database after installing the requirements.txt file, or if you have Docker and prefer a cleaner environment, install docker-compose with pip install docker-compose and run docker-compose up. This will set up a near production-ready containerized development environment that runs migrations, with the django development server running on port 8071.

To run one-off commands, like shell, you can run docker-compose run web python manage.py shell or to create root user, etc.

Environment/Local Variables

The following variables need to be created in environment or in local settings ("sga-lti.yml"):

# Media files (for uploaded files)
AWS_STORAGE_BUCKET_NAME  # S3 bucket name
AWS_ACCESS_KEY_ID  # S3 access key id credential
AWS_SECRET_ACCESS_KEY  # S3 secret access key credential
MEDIAFILES_LOCATION  # Optional S3 subfolder within AWS_STORAGE_BUCKET_NAME
LTI_OAUTH_CREDENTIALS  # A dictionary of lti oauth key/secret pairs

Servers additionally need the parameters:

SECRET_KEY  # The Django secret key
ALLOWED_HOSTS  # A list containing the name of the server
DATABASE_URL  # The url to connect to the database

Sample sga-lti.yml for local development:

DEBUG: True
SGA_LTI_SECURE_SSL_REDIRECT: False
SGA_LTI_DB_DISABLE_SSL: True
SGA_LTI_LOG_LEVEL: INFO
DJANGO_LOG_LEVEL: INFO
LTI_OAUTH_CREDENTIALS:
    client-key: client-secret
AWS_STORAGE_BUCKET_NAME: XXXXXXXXXX
AWS_ACCESS_KEY_ID: AKXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
MEDIAFILES_LOCATION: /testing

Sample server configuration:

ALLOWED_HOSTS             ["example.com"]
DATABASE_URL              postgres://xxx:yyy@hostname:port/zzz
LTI_OAUTH_CREDENTIALS     {"client-key": "client-secret"}
AWS_STORAGE_BUCKET_NAME   s3_bucket
AWS_ACCESS_KEY_ID         AKXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
MEDIAFILES_LOCATION       /sga_files
SECRET_KEY                super_secret_key

Installing as an LTI tool

To add this to a course, first follow the edX instructions for adding LTI passport configuration: http://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/lti_component.html.

You can add this tool to a graded unit by going to edX studio for that unit. Under "Add New Component", click "Advanced", and pick "LTI Consumer". Edit the newly created LTI consumer. Fill in the following settings:

  • Display Name: the name of the assignment that will be passed to SGA-LTI
  • LTI ID: [your LTI passport id that you configured in course settings]
  • LTI URL: [the root url of the tool] (so if the tool is deployed at example.com, the launch URL is https://example.com)
  • LTI Launch Target: Inline
  • Scored: True
  • Request user's username: True
  • Request user's email: True

NOTE: This tool is only designed to be installed in graded units of an edX course.

Adding an application

To add an application to this, add it to the requirements file, add its needed settings, include its URLs, and provide any needed template overrides.

Testing

The project is set up with `tox<https://tox.readthedocs.org/en/latest/>`_ and `py.test<http://pytest.org/latest/>`_. It will run pylint, pep8, and py.test tests with coverage. It will also generate an HTML coverage report. To run them all inside the docker image, run docker-compose run web tox, or if you are running locally, after installing the requirements file, just run tox.

Continuous Testing

If you want test to run on file changes, the test_requirements.txt adds pytest-watcher, which can be started with ptw. This unfortunately will not work well in the Docker container because the file events it uses are fired on the host OS, and not the docker OS. I have corrected it upstream with `issue<https://github.com/joeyespo/pytest-watch/issues/9>`_ to the `pytest-watch repo<https://github.com/joeyespo/pytest-watch>`_, but it has not been released to pypi as of this writing.

sga-lti's People

Contributors

alvinsiu avatar zags avatar renovate[bot] avatar kyfantaz avatar shaidar avatar pdpinch avatar blarghmatey avatar

Stargazers

 avatar Nate Aune avatar

Watchers

Ferdi Alimadhi avatar  avatar James Cloos avatar James Kachel avatar  avatar ichuang avatar  avatar jenniw avatar Collin Preston avatar  avatar  avatar

sga-lti's Issues

Migrate Travis -> Github Actions

Travis will be limited open source projects build time soon, so we need to transition to github actions.

Take a look at how we did it open discussions or bootcamps or micromasters

return a meaningful errror message when oauth_consumer_key is missing

This is an edge case, so we should discuss before implementing.

Steps to reproduce:

  1. Add lti-consumer xblock to the course via advanced settings, but leave lti passports blank
  2. Add SGA-LTI as you normally would

Expected outcome:

an error message indicating that the consumer key is bad and / or missing.

Actual outcome:

I'm redirected to the studio error message, which is particularly confusing if the user isn't actually in studio:

Error (400) bad request while connecting from OPEN EDX LMS

Hello, I've recently installed sga-lti on heroku.
Have not changed a thing in code, just changed sga-lti.yml file. I made it to look as followed
ALLOWED_HOSTS [".inrobot.ru", "inrobot-lti-sga.herokuapp.com"] DATABASE_URL postgres://bdoxlzafnqhvks:Oap19v97o-_bFfQFRBDdvk6fkq@ec2-54-243-52-211.compute-1.amazonaws.com:5432/d3vsn5f6ksv0s1 LTI_OAUTH_CREDENTIALS {bububu: dududu} AWS_STORAGE_BUCKET_NAME idiotsandtrobots AWS_ACCESS_KEY_ID HERE IS MY KEY AWS_SECRET_ACCESS_KEY HERE IS MY SECRET MEDIAFILES_LOCATION /sga_files SECRET_KEY babdadam

And when I tail heroku logs i get following errors while trying to connect to lti server from edx
ERROR 15 [django.security.DisallowedHost] base.py:216 - [8311f173-fea6-4af9-b32d-9bfa40cbe99a] - Invalid HTTP_HOST header: 'inrobot-lti-sga.herokuapp.com'. You may need to add 'inrobot-lti-sga.herokuapp.com' to ALLOWED_HOSTS.

If anyone can answer my question, it would be much appreciated. Thanks in advance.

Make S3 links private

We need to set S3 buckets to private and be able to generate valid urls with timeouts for authorized users to access these files.

Make File Description optional

Currently, in the student view, it is required to add a File Description before uploading. Is it possible to make this optional?

500 error on attempting to access grader view with a user named `pdpinch-grader`

I'm getting a 500 error in the grader view after assigning my test student to the grader, ValueError: Cannot query "pdpinch_student": Must be "User" instance.

Stack trace:

2016-07-05T22:39:13.601595+00:00 app[web.1]: Traceback (most recent call last):
2016-07-05T22:39:13.601597+00:00 app[web.1]:     response = self.process_exception_by_middleware(e, request)
2016-07-05T22:39:13.601599+00:00 app[web.1]:     return view_func(request, course_id, *args, **kwargs)
2016-07-05T22:39:13.601596+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/core/handlers/base.py", line 149, in get_response
2016-07-05T22:39:13.601599+00:00 app[web.1]:   File "./sga/backend/authentication.py", line 28, in _wrapped_view
2016-07-05T22:39:13.601600+00:00 app[web.1]:   File "./sga/views.py", line 286, in view_assignment
2016-07-05T22:39:13.601601+00:00 app[web.1]:     submission, _ = Submission.objects.get_or_create(student=student_user, assignment=assignment)
2016-07-05T22:39:13.601601+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/manager.py", line 122, in manager_method
2016-07-05T22:39:13.601602+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/query.py", line 465, in get_or_create
2016-07-05T22:39:13.601597+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/core/handlers/base.py", line 147, in get_response
2016-07-05T22:39:13.601603+00:00 app[web.1]:     return self.get(**lookup), False
2016-07-05T22:39:13.601603+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/query.py", line 378, in get
2016-07-05T22:39:13.601602+00:00 app[web.1]:     return getattr(self.get_queryset(), name)(*args, **kwargs)
2016-07-05T22:39:13.601606+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/sql/query.py", line 1243, in add_q
2016-07-05T22:39:13.601604+00:00 app[web.1]:     clone = self.filter(*args, **kwargs)
2016-07-05T22:39:13.601607+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/sql/query.py", line 1174, in build_filter
2016-07-05T22:39:13.601608+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/sql/query.py", line 1071, in check_related_objects
2016-07-05T22:39:13.601608+00:00 app[web.1]:     self.check_query_object_type(value, opts, field)
2016-07-05T22:39:13.601604+00:00 app[web.1]:     return self._filter_or_exclude(False, *args, **kwargs)
2016-07-05T22:39:13.601605+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/query.py", line 808, in _filter_or_exclude
2016-07-05T22:39:13.601607+00:00 app[web.1]:     allow_joins=allow_joins, split_subq=split_subq,
2016-07-05T22:39:13.601583+00:00 app[web.1]: [2016-07-05 22:39:13] ERROR 17 [django.request] base.py:284 - [5b6af6ad-3d46-418e-8dd6-16ee3dc137d7] - Internal Server Error: /view-assignment/2/2
2016-07-05T22:39:13.601605+00:00 app[web.1]:     clone.query.add_q(Q(*args, **kwargs))
2016-07-05T22:39:13.601606+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/sql/query.py", line 1269, in _add_q
2016-07-05T22:39:13.601606+00:00 app[web.1]:     clause, _ = self._add_q(q_object, self.used_aliases)
2016-07-05T22:39:13.601604+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/query.py", line 790, in filter
2016-07-05T22:39:13.601608+00:00 app[web.1]:     self.check_related_objects(field, value, opts)
2016-07-05T22:39:13.601609+00:00 app[web.1]:     (value, opts.object_name))
2016-07-05T22:39:13.601610+00:00 app[web.1]: ValueError: Cannot query "pdpinch_student": Must be "User" instance.
2016-07-05T22:39:13.601609+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/sql/query.py", line 1055, in check_query_object_type
2016-07-05T22:39:13.602963+00:00 app[web.1]: {address space usage: 304705536 bytes/290MB} {rss usage: 36839424 bytes/35MB} [pid: 17|app: 0|req: 10/40] 10.69.17.189 () {50 vars in 1108 bytes} [Tue Jul  5 22:39:13 2016] GET /view-assignment/2/2 => generated 27 bytes in 65 msecs (HTTP/1.1 500) 2 headers in 77 bytes (1 switches on core 0)
2016-07-05T22:39:13.417854+00:00 heroku[router]: at=info method=POST path="/" host=mitodl-sga-lti-staging.herokuapp.com request_id=19fb9253-c303-431c-bf3a-7584b89a4bca fwd="107.77.192.106" dyno=web.1 connect=0ms service=54ms status=302 bytes=361
2016-07-05T22:39:13.572415+00:00 heroku[router]: at=info method=GET path="/view-assignment/2/2" host=mitodl-sga-lti-staging.herokuapp.com request_id=bddd163d-9807-410a-9ce0-4d4cbf112660 fwd="107.77.192.106" dyno=web.1 connect=1ms service=65ms status=500 bytes=104

In case it's relevant, here's my user record in the admin view:

screen shot 2016-07-05 at 6 39 02 pm

I can view the document fine from the admin view.

I'll see if I can reproduce with a fresh student user.

Multi-course compatability

User roll needs to be stored per course in the session and the authentication decorator needs to be course aware

Progress remains even if submission is cleared

If a graded submission is removed, the grade on the progress page remains until a new submission is graded. This may confuse learners if they see the older progress. Is there a way to remove the grade completely when the submission is removed?

Accessibility issue #2 - Standard File Upload Widget

While the standard file upload widget is not inaccessible, both Firefox and Chrome do not allow screen readers to read the labels provided. This is a browser issue, but can be fixed using Javascript. Doing so will also allow you to add CSS and make it look better visually. A person helping to test accessibility created this upload sample of a selector widget that uses a label element instead of a button as a trigger. He did not add styles to make it appear as a button, but you could:
http://www.mit.edu/~rjc/aria/upload.html

Have static text page when viewing tool from studio

studio has different assignment ids, and so can be slightly confusing. We can check for user_id "cuid:student" and have special logic for that

The difference in assignment ids is between edge.edx.org-935a21c2d95a495bacae8f484b8ea8e5 when on edge.edx.org and -935a21c2d95a495bacae8f484b8ea8e5 when in studio.edge.edx.org

Student List view

In the Student List view, if students do not have a grader assigned, they should be listed in the "Has No grader" tab. Currently, no one shows up there.

Adjust urls and views for Edx integration

There needs to be a dedicated entry point that is csrf exempt and redirects users to the appropriate places. All other urls need to have the course id as part of them to support multiple courses. User roll needs to be stored per course in the session and the authentication decorator needs to be course aware

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Warning

These dependencies are deprecated:

Datasource Name Replacement PR?
npm babel Unavailable
npm babel-eslint Unavailable
npm babel-preset-es2015 Unavailable
npm node-sass Unavailable
npm redux-devtools Unavailable

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • Update dependency eslint-plugin-babel to v5
  • Update dependency eslint-plugin-react to v7
  • Update dependency factory_boy to v3
  • Update dependency fake-factory to v9999
  • Update dependency history to v5
  • Update dependency jsdom to v25
  • Update dependency jsdom-global to v3
  • Update dependency mocha to v10
  • Update dependency mock to v5
  • Update dependency newrelic to v9
  • Update dependency pylint to v3
  • Update dependency pylint-django to v2
  • Update dependency pytest to v8
  • Update dependency pytest-cov to v5
  • Update dependency pytest-django to v4
  • Update dependency react-ga to v3
  • Update dependency react-hot-loader to v4
  • Update dependency react-redux to v9
  • Update dependency react-router to v6
  • Update dependency redux-actions to v3
  • Update dependency redux-devtools to v3
  • Update dependency redux-logger to v3
  • Update dependency redux-thunk to v3
  • Update dependency sass-loader to v16
  • Update dependency style-loader to v4
  • Update dependency tox to v4
  • Update dependency webpack to v5
  • Update react monorepo (major) (react, react-addons-test-utils, react-dom)
  • Update ubuntu Docker tag to v24
  • Lock file maintenance
  • 🔐 Create all rate-limited PRs at once 🔐

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

docker-compose
docker-compose.yml
dockerfile
Dockerfile
  • ubuntu 14.04.5
npm
package.json
  • babel 6.23.0
  • babel-core 6.26.3
  • babel-loader 6.4.1
  • babel-plugin-jsx 1.2.0
  • babel-preset-es2015 6.24.1
  • babel-preset-react 6.24.1
  • bourbon-neat 1.9.1
  • css-loader 0.28.11
  • history 2.1.2
  • node-neat 1.7.2
  • node-sass 3.4.2
  • react 0.14.10
  • react-dom 0.14.10
  • react-ga 1.5.0
  • react-redux 4.4.10
  • react-router 2.8.1
  • redux-actions 0.13.0
  • redux-devtools 2.1.5
  • redux-logger 2.10.2
  • redux-thunk 2.4.2
  • sass-loader 3.2.3
  • style-loader 0.23.1
  • webpack 1.15.0
  • webpack-dev-server 1.14.1
  • babel-eslint 5.0.4
  • babel-plugin-transform-react-jsx 6.24.1
  • eslint 2.13.1
  • eslint-config-defaults 9.0.0
  • eslint-plugin-babel 3.3.0
  • eslint-plugin-react 4.3.0
  • jsdom 8.5.0
  • jsdom-global 1.7.0
  • mocha 2.5.3
  • react-addons-test-utils 0.14.8
  • react-hot-loader 1.3.1
pip_requirements
requirements.txt
  • Django ==1.9.4
  • PyYAML ==3.11
  • dj-database-url ==0.5.0
  • dj-static ==0.0.6
  • django-server-status ==0.7.3
  • factory_boy ==2.12.0
  • fake-factory ==0.7.4
  • uwsgi ==2.0.26
  • psycopg2 ==2.9.9
  • six ==1.16.0
  • tox ==2.9.1
  • static3 ==0.7.0
  • newrelic ==2.106.1.88
  • django-forms-bootstrap ==3.1.0
  • django-auth-lti v1.2.8
  • boto ==2.49.0
  • django-storages ==1.14.4
test_requirements.txt
  • pylint ==1.9.5
  • pylint-django ==0.11.1
  • pytest-cov ==2.12.1
  • pytest-django ==2.9.1
  • pytest-pep8 ==1.0.6
  • pytest-pylint ==0.21.0
  • pytest ==2.9.2
  • mock ==1.3.0
  • semantic_version ==2.10.0

  • Check this box to trigger a request for Renovate to run again on this repository

Don't show negative counts in list views

I'm not really sure how this happened, but this seems wrong:

image

I think what I did assign two students (each with one submittion) to the same graders. After the grader graded them, the admin removed the grader. This screenshot is from the grader's view.

500 error on student submitting a file

I'm getting a 500 error currently when I try to submit a file. Looking at the stack trace, it seems to be an issue with the data in one of the fields being too large:

500 error on student submission

2016-07-03T19:08:52.678505+00:00 app[web.1]: Traceback (most recent call last):
2016-07-03T19:08:52.678509+00:00 app[web.1]:     return self.cursor.execute(sql, params)
2016-07-03T19:08:52.678472+00:00 app[web.1]: [2016-07-03 19:08:52] ERROR 10 [django.request] base.py:284 - [7db1d235-39db-4469-891d-e874ad9ab7b5] - Internal Server Error: /view-submission-as-student/2/2
2016-07-03T19:08:52.678508+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
2016-07-03T19:08:52.678509+00:00 app[web.1]: psycopg2.DataError: value too long for type character varying(100)
2016-07-03T19:08:52.678511+00:00 app[web.1]: 
2016-07-03T19:08:52.678511+00:00 app[web.1]: The above exception was the direct cause of the following exception:
2016-07-03T19:08:52.678512+00:00 app[web.1]: 
2016-07-03T19:08:52.678510+00:00 app[web.1]: 
2016-07-03T19:08:52.678513+00:00 app[web.1]: Traceback (most recent call last):
2016-07-03T19:08:52.678513+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/core/handlers/base.py", line 149, in get_response
2016-07-03T19:08:52.678515+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/core/handlers/base.py", line 147, in get_response
2016-07-03T19:08:52.678516+00:00 app[web.1]:     response = wrapped_callback(request, *callback_args, **callback_kwargs)
2016-07-03T19:08:52.678517+00:00 app[web.1]:     return view_func(request, course_id, *args, **kwargs)
2016-07-03T19:08:52.678519+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/forms/models.py", line 451, in save
2016-07-03T19:08:52.678520+00:00 app[web.1]:     self.instance.save()
2016-07-03T19:08:52.678519+00:00 app[web.1]:     submission_form.save()
2016-07-03T19:08:52.678515+00:00 app[web.1]:     response = self.process_exception_by_middleware(e, request)
2016-07-03T19:08:52.678521+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/base.py", line 700, in save
2016-07-03T19:08:52.678521+00:00 app[web.1]:     force_update=force_update, update_fields=update_fields)
2016-07-03T19:08:52.678523+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/base.py", line 793, in _save_table
2016-07-03T19:08:52.678522+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/base.py", line 728, in save_base
2016-07-03T19:08:52.678525+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/base.py", line 843, in _do_update
2016-07-03T19:08:52.678517+00:00 app[web.1]:   File "./sga/backend/authentication.py", line 28, in _wrapped_view
2016-07-03T19:08:52.678518+00:00 app[web.1]:   File "./sga/views.py", line 73, in view_submission_as_student
2016-07-03T19:08:52.678525+00:00 app[web.1]:     return filtered._update(values) > 0
2016-07-03T19:08:52.678526+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/query.py", line 645, in _update
2016-07-03T19:08:52.678528+00:00 app[web.1]:     cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
2016-07-03T19:08:52.678523+00:00 app[web.1]:     updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
2016-07-03T19:08:52.678528+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/sql/compiler.py", line 848, in execute_sql
2016-07-03T19:08:52.678527+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/models/sql/compiler.py", line 1149, in execute_sql
2016-07-03T19:08:52.678529+00:00 app[web.1]:     cursor.execute(sql, params)
2016-07-03T19:08:52.678530+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
2016-07-03T19:08:52.678526+00:00 app[web.1]:     return query.get_compiler(self.db).execute_sql(CURSOR)
2016-07-03T19:08:52.678524+00:00 app[web.1]:     forced_update)
2016-07-03T19:08:52.678533+00:00 app[web.1]:     return self.cursor.execute(sql, params)
2016-07-03T19:08:52.678534+00:00 app[web.1]: django.db.utils.DataError: value too long for type character varying(100)
2016-07-03T19:08:52.678530+00:00 app[web.1]:     return self.cursor.execute(sql, params)
2016-07-03T19:08:52.678532+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/utils/six.py", line 685, in reraise
2016-07-03T19:08:52.678531+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/utils.py", line 95, in __exit__
2016-07-03T19:08:52.678533+00:00 app[web.1]:   File "/app/.heroku/python/lib/python3.4/site-packages/django/db/backends/utils.py", line 64, in execute
2016-07-03T19:08:52.698029+00:00 app[web.1]: {address space usage: 306405376 bytes/292MB} {rss usage: 38809600 bytes/37MB} [pid: 10|app: 0|req: 1/15] 10.230.212.101 () {54 vars in 1181 bytes} [Sun Jul  3 19:08:51 2016] POST /view-submission-as-student/2/2 => generated 27 bytes in 1492 msecs (HTTP/1.1 500) 2 headers in 77 bytes (36 switches on core 0)
2016-07-03T19:08:52.678539+00:00 app[web.1]: 
2016-07-03T19:08:52.678531+00:00 app[web.1]:     six.reraise(dj_exc_type, dj_exc_value, traceback)
2016-07-03T19:08:52.678532+00:00 app[web.1]:     raise value.with_traceback(tb)

500 Server Error

A user cannot be enrolled in multiple courses with the LTI. A 500 error appears.

File upload to S3

Upload file submissions to S3
Change uploaded submissions and feedback to have standard names
Change downloaded zip files to include course names

Change "Feedback" to "Extra Notes" and make optional

In Grader or Admin view, there is a place for Feedback, but they are trying to add their feedback on the annotated file. Can this be changed to “Extra Notes” and can it be optional to add something to it?

Staff view: single grader

  • Table of students assigned to grader
  • List of unassigned students (if grader is below their student limit)
  • Ability to assign new students to the grader (if grader is below their student limit)
  • Ability to view and edit grader limit
  • Demote to student

Send grades back to EdX

We need to store lis_outcome_service_url and send the grade to it when an assignment is graded.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.