Skip to content
Browse files

Merge pull request #653 from CodeGra-de/master

## Description
Release the stable release 'HereBeMonsters' (aka the glorious and infamous version `H`). This release adds:

### Major changes
- Add Plagiarism checkers (#486) (#513) (#536) (#555) (#508) (#556) (#645) (#576)
  It is now possible to check for plagiarism in CodeGrade. This enables privacy aware plagiarism checking. It is possible to use check against old CodeGrade assignment and upload base code and old submissions that are not in CodeGrade. For more information see our documentation.

- Make it possible give grades higher than ten (#500)
  Teachers can now indicate that students can receive a grader higher than 10 for an assignment, making it possible to create assignments with bonus points in CodeGrade. When using within LTI this requires a new LTI parameter.
  You should add the following to the `<blti:custom>` section of your canvas LTI config for CodeGrade:

  <lticm:property name="custom_canvas_points_possible">

### Minor changes
- Change homepage to login screen (#480) (#496) (#501) (#557) (#616)
  The homepage has been improved to show all your courses and assignments at a glance when logged in.
- Allow .tar.xz archives to be uploaded (#492)
  This further improves the flexibility CodeGrade gives students when handing in submissions.
- Fix infinite loop overview mode (#477)
  In some combinations of permissions loading the overview mode resulted in an infinite loader.
- Add general feedback tab to overview mode (#523)
  This further decreases the chance that students will miss any of their feedback.
- Fix broken matchFiles function (#528) (#550)
  This fixes a bug that files changed inside a directory would not show up in the overview mode.
- Improve speed of diffing by using another library (#529)
  Viewer the diff between two large files is a lot faster!
- Remove the option to automatically generate keys (#554)
  It is no longer possible to generate the `secret_key` or `lti_secret_key` configuration options. Please update your config accordingly.
- Rewrite snippets manager (#551)
  This rewrite should make creating, using, deleting and updating snippets faster and more reliable.
- Drastically improve the experience of CodeGrade on mobile (#558)
  It is now way easier to use CodeGrade on mobile.
- Filter users in the user selector (#553)
  When selecting users (when uploading for others, or adding to courses) only show users will be shown that can be selected.
- Improve handling of LTI (#561) (#588)
  A complete rewrite of LTI backend handling. This should improve the stability of passbacks by a lot. This also guarantees that the submission date in Canvas and CodeGrade will match exactly.
  This also adds a new convenience route `/api/v1/lti/?lms=Canvas` to get lti config for the given LMS (Canvas only supported at the moment).
- Add items to the sidebar conditionally (#578) (#580) (#600)
  Depending on what page you are you will get extra items in the sidebar to help quick navigation. Currently plagiarism cases and submissions are added depending on the page.
- Start caching submissions (#643) (#636)
  Submissions are cached in the front-end so changing between the codeviewer and submissions list is now way quicker.
- Ensure all rubric rows have a maximum amount of >= 0 points (#579)
  It is no longer allowed to have rows in a rubric where the maximum possible score is < 0. If you needed this to create rubrics with bonus categories simply use the 'Max points' option in the rubric editor. All existing rubrics are not changed.

### Small changes and bugfixes
- Use new logos (#481) (#506)
  This updates our logo to the newest and greatest version!
- Various small bugs in the sidebar
- Add a minimum duration on the permission manager loaders (#521)
  This makes it clearer that permissions are actually updated.
- Throw an API error when a rubric row contains an empty header (#535)
  This is a backwards incompatible API change, however it doesn't change anything for the frontend.
- Fix horizontal overflow on codeviewer (#518)
  The codeviewer would sometimes overflow creating a vertical scrollbar when displaying files containing a large amount of consecutive tabs.
- Check if an assignment is loaded before getting its course (#549)
  In some rare cases LTI launches would fail be cause assignments were not loaded correctly.
- Add structured logging setup (#546)
  This makes it easier to follow requests and debug issues.
- Fix general feedback line wrapping (#570)
  Giving long lines as general feedback should be displayed correctly to the user now.
- Add manage assignment button to submission list (#574)
  It is now possible to easily navigate to the manage assignment page from the submissions list.
- Start using enum to store permissions in the backend (#571)
  Most routes will be faster by this design change.
- Improve filetree design (#599) (#611)  (#587)
  It is now easier to spot additions, changes and deletion directly in the filetree.
- Add ``<noscript>`` tag (#613)
  An error message will be displayed when javascript is disabled.
- Improve speed of filetree operations (#623)
  Loading large filetrees is now way quicker by using smarter data-structures.
- Add health route (#593)
  It is now possible to more easily monitor the health of your CodeGrade instance.
- Fix fontSize & contextAmount on submission page (#633)
  Sometimes the fields would show up empty, this shouldn't happen anymore!
- Replace submitted symlinks with actual files (#627)
  When a student uploads an archive with symlinks the student is warned and all symlinks are replaced by files explaining that the original files were symlinks but that those are not supported by CodeGrade.
- Fix grade history popover boundary (#625)
  The grade history would sometimes show up outside the screen, but no more!
- Make it impossible to submit empty archives (#622)
  A error is shown when a student tries to submit an archive without files.
- Show toast when local-storage doesn't work (#607)
  When a user has no local-storage available a warning is shown so the user knows that their experience might be sub-optimal.
- Show author of general feedback and line comments (#564) (#605)
  The author of all general feedback and line comments is displayed to the user. Only users with the `can_see_assignee` permission will see authors.
- Justify description popover text (#596)
  The text in descriptions is now justified and their popups will only show when the 'i' is clicked.
- Only submit rubric items or normal grade (#589)
  In some rare cases overriding rubrics would result in a race condition, resulting in wrong case.
- Redesign the download popover on the submission page (#595)
  This new design looks way better, but you tell us!
- Only show overview mode when you have permission to see feedback (#563)
  When you don't have permission to see feedback the overview mode will never be shown.
- Various other performance improvements (#566)
  We always strive for the best performance possible, and again in this release we increased the performance of CodeGrade! 🎉
- Make sure codeviewer is full width on medium pages (#591)
  This makes it easier to review and display code on smaller screens.
- Use custom font in toasted actions (#614)
  It is now always possible to close toasts, even when your font cannot display '✖'
  • Loading branch information...
olmokramer committed Oct 30, 2018
2 parents d706d36 + 620888a commit 8fbd918283b43238bb0ec950a057ca820cf12e25
Showing 303 changed files with 22,637 additions and 5,573 deletions.
@@ -7,8 +7,7 @@
"comments": false,
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
"presets": ["env", "stage-2"]
@@ -1,10 +1,38 @@
version: 2

enabled: true
channel: "eslint-4"
- .vue

- "**/psef_test/*.py"
- "**/test/**/*"
- "**/config/**/*.js"

enabled: false
enabled: true
enabled: true
enabled: true
enabled: false
enabled: false
enabled: false
enabled: false
threshold: 8
enabled: true
enabled: true

- "**.js"
- "**.py"
@@ -4,4 +4,6 @@ exclude_lines =
pragma: no cover

# Don't complain if tests don't hit defensive assertion code:
raise NotImplementedError
raise NotImplementedError
assert False
@@ -39,6 +39,8 @@ module.exports = {
'no-else-return': 'off',
'no-plusplus': 'off',
'function-paren-newline': ['error', 'consistent'],
'no-bitwise': 'off',
'no-mixed-operators': 'off',

// allow vuex
'no-param-reassign': ["error", { 'props': false }],
@@ -22,3 +22,4 @@
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: AGPL-3.0-only

import os
import re
import sys
import json
import secrets
import datetime
import subprocess
from collections import OrderedDict

import flask_migrate

BASE_DIR = os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(__file__), '..')))
PERMS_FILE = os.path.join(BASE_DIR, 'seed_data', 'permissions.json')


MIGRATION_TEMPLATE = """""\"\"\"Creating "{perm_name}" permission.
Revision ID: {up_revision}
Revises: {down_revision}
Create Date: {create_date}
from alembic import op
import sqlalchemy as sa
from sqlalchemy.sql import text
# revision identifiers, used by Alembic.
revision = '{up_revision}'
down_revision = '{down_revision}'
branch_labels = None
depends_on = None
def upgrade():
conn = op.get_bind()
INSERT INTO "Permission" (name, default_value, course_permission)
SELECT '{perm_name}', {default_value}, {course_permission} WHERE NOT EXISTS
(SELECT 1 FROM "Permission" WHERE name = '{perm_name}')
def downgrade():

def get_input(question: str) -> str:
print(question, end=': ')
while True:
user_input = input()
if user_input:
return user_input

def get_yes_or_no(question: str) -> bool:
while True:
res = get_input(question + ' [y/n]')
if res in ('y', 'j', 'yes'):
return True
elif res in ('n', 'no'):
return False

def main() -> None:
name = ' '
while not re.match(r'[a-z]+(_[a-z]+)+', name):
name = get_input('Name of new permission')
course_perm = get_yes_or_no('Is it a course permission')
short_desc = get_input('Short description of permission')
long_desc = get_input('Long description of permission')
default_true = get_yes_or_no('Should the default value be True')

r_f_name: str
if course_perm:
r_f_name = os.path.join(BASE_DIR, 'seed_data', 'course_roles.json')
r_f_name = os.path.join(BASE_DIR, 'seed_data', 'roles.json')

with open(r_f_name, 'r') as f:
roles = json.load(f, object_pairs_hook=OrderedDict)

for key, val in roles.items():
if get_yes_or_no(
'Should the role "{}" have this permission'.format(key)

with open(r_f_name, 'w') as f:
json.dump(roles, f, indent=2, separators=(',', ': '))

with open(PERMS_FILE, 'r') as f:
perms = json.load(f, object_pairs_hook=OrderedDict)

perms[name] = OrderedDict(
with open(PERMS_FILE, 'w') as f:
json.dump(perms, f, indent=2, separators=(',', ': '))

print('Generating migration', end=' ...')
out = subprocess.check_output(
os.path.join(BASE_DIR, ''), 'db', 'heads']
match = re.match(r'([a-z0-9]+) \(head\)', out)
assert match is not None
old_rev =
new_rev = secrets.token_hex(10)
with open(
BASE_DIR, 'migrations', 'versions', '{}'.format(new_rev)
), 'w'
) as out:
create_date=datetime.datetime.utcnow().isoformat(sep=' ')

subprocess.check_call(['python', os.path.join(BASE_DIR, '.scripts', '')])
subprocess.check_call(['make', 'db_upgrade'])

if __name__ == '__main__':
Oops, something went wrong.

0 comments on commit 8fbd918

Please sign in to comment.
You can’t perform that action at this time.