e2xauthoring 0.2.0.dev0__tar.gz → 0.2.0.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/PKG-INFO +1 -1
- e2xauthoring-0.2.0.dev2/e2xauthoring/__version__.py +1 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/app/handlers/apihandlers.py +129 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/app/handlers/base.py +102 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/app/templates/authoring/asset-manifest.json +10 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/app/templates/authoring/index.html +1 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/app/templates/authoring/static/js/main.1e6f65c1.js +3 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/app/templates/authoring/static/js/main.1e6f65c1.js.LICENSE.txt +88 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/app/templates/authoring/static/js/main.1e6f65c1.js.map +1 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/managers/__init__.py +17 -0
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/assignmentmodel.py → e2xauthoring-0.2.0.dev2/e2xauthoring/managers/assignmentmanager.py +7 -7
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/managers/manager.py → e2xauthoring-0.2.0.dev2/e2xauthoring/managers/base.py +19 -1
- e2xauthoring-0.2.0.dev2/e2xauthoring/managers/dataclasses/__init__.py +49 -0
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/presetmodel.py → e2xauthoring-0.2.0.dev2/e2xauthoring/managers/presetmanager.py +11 -5
- e2xauthoring-0.2.0.dev2/e2xauthoring/managers/taskmanager.py +167 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/managers/taskpoolmanager.py +66 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/managers/templatemanager.py +69 -0
- e2xauthoring-0.2.0.dev2/e2xauthoring/managers/worksheetmanager.py +50 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/addtaskheader.py +1 -1
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/copyfiles.py +5 -4
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/copynotebooks.py +6 -5
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/filltemplate.py +2 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/makeexercise.py +9 -2
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/package-lock.json +24 -6
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/package.json +1 -1
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/pyproject.toml +2 -2
- e2xauthoring-0.2.0.dev0/e2xauthoring/__version__.py +0 -1
- e2xauthoring-0.2.0.dev0/e2xauthoring/app/handlers/apihandlers.py +0 -272
- e2xauthoring-0.2.0.dev0/e2xauthoring/app/handlers/base.py +0 -41
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/__init__.py +0 -15
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/basemodel.py +0 -20
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/dataclasses/__init__.py +0 -28
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/dataclasses/message.py +0 -13
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/dataclasses/template.py +0 -6
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/exercisemodel.py +0 -44
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/lister/lister.py +0 -27
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/lister/taskpoollister.py +0 -33
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/lister/templatelister.py +0 -17
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/managers/taskmanager.py +0 -123
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/managers/taskpoolmanager.py +0 -63
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/managers/templatemanager.py +0 -50
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/taskmodel.py +0 -186
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/taskpoolmodel.py +0 -125
- e2xauthoring-0.2.0.dev0/e2xauthoring/models/templatemodel.py +0 -67
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/.github/workflows/sonarcloud.yml +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/.gitignore +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/.pre-commit-config.yaml +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/LICENSE +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/MANIFEST.in +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/README.md +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/__init__.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/app/__init__.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/app/authoring.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/app/handlers/handlers.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/assets/.gitignore +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/converters/__init__.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/converters/converter.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/converters/generateexercise.py +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/questions/Code (Autograded).ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/questions/Code (Manual).ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/questions/Diagram.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/questions/Freetext.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/questions/Multiple Choice.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/questions/Single Choice.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/questions/Upload Files.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/template/Footer.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/template/Group Info.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/template/Header.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0/e2xauthoring/models → e2xauthoring-0.2.0.dev2/e2xauthoring/managers}/presets/template/Student Info.ipynb +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/__init__.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/generatetaskids.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/preprocessor.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/preprocessors/removeexercise.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/utils/__init__.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/utils/gitutils.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/e2xauthoring/utils/notebookvariableextractor.py +0 -0
- {e2xauthoring-0.2.0.dev0 → e2xauthoring-0.2.0.dev2}/lerna.json +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.0-dev2"
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from e2xcore.handlers import E2xApiHandler
|
|
4
|
+
from e2xcore.utils import urljoin
|
|
5
|
+
from jupyter_client.kernelspec import KernelSpecManager
|
|
6
|
+
from nbgrader.server_extensions.formgrader.base import check_xsrf
|
|
7
|
+
from tornado import web
|
|
8
|
+
|
|
9
|
+
from ...managers import (
|
|
10
|
+
AssignmentManager,
|
|
11
|
+
PresetManager,
|
|
12
|
+
TaskManager,
|
|
13
|
+
TaskPoolManager,
|
|
14
|
+
TemplateManager,
|
|
15
|
+
WorksheetManager,
|
|
16
|
+
)
|
|
17
|
+
from ...utils.gitutils import get_author, set_author
|
|
18
|
+
from .base import ApiManageHandler
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class KernelSpecHandler(E2xApiHandler):
|
|
22
|
+
@web.authenticated
|
|
23
|
+
@check_xsrf
|
|
24
|
+
def get(self):
|
|
25
|
+
self.write(json.dumps(KernelSpecManager().get_all_specs()))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class GitAuthorHandler(E2xApiHandler):
|
|
29
|
+
@web.authenticated
|
|
30
|
+
@check_xsrf
|
|
31
|
+
def get(self):
|
|
32
|
+
self.write(json.dumps(get_author()))
|
|
33
|
+
|
|
34
|
+
@web.authenticated
|
|
35
|
+
@check_xsrf
|
|
36
|
+
def post(self):
|
|
37
|
+
data = self.get_json_body()
|
|
38
|
+
name = data.get("name")
|
|
39
|
+
email = data.get("email")
|
|
40
|
+
self.write(json.dumps(set_author(name=name, email=email)))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
api_url = urljoin("e2x", "authoring", "api")
|
|
44
|
+
name_regex = r"(?P<name>[^/]+)"
|
|
45
|
+
assignment_regex = r"(?P<assignment>[^/]+)"
|
|
46
|
+
default_handlers = [
|
|
47
|
+
(
|
|
48
|
+
urljoin(api_url, "assignments", "?"),
|
|
49
|
+
ApiManageHandler,
|
|
50
|
+
dict(
|
|
51
|
+
manager_cls=AssignmentManager,
|
|
52
|
+
actions=dict(
|
|
53
|
+
get=dict(actions=["list"]),
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
(
|
|
58
|
+
urljoin(api_url, "worksheets", "?"),
|
|
59
|
+
ApiManageHandler,
|
|
60
|
+
dict(
|
|
61
|
+
manager_cls=WorksheetManager,
|
|
62
|
+
actions=dict(
|
|
63
|
+
get=dict(actions=["get", "list"]),
|
|
64
|
+
delete=dict(default="remove", actions=["remove"]),
|
|
65
|
+
post=dict(default="create", actions=["create"]),
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
),
|
|
69
|
+
(
|
|
70
|
+
urljoin(api_url, "tasks", "?"),
|
|
71
|
+
ApiManageHandler,
|
|
72
|
+
dict(
|
|
73
|
+
manager_cls=TaskManager,
|
|
74
|
+
actions=dict(
|
|
75
|
+
delete=dict(default="remove", actions=["remove"]),
|
|
76
|
+
get=dict(
|
|
77
|
+
default="get", actions=["get", "list", "list_all", "git_diff"]
|
|
78
|
+
),
|
|
79
|
+
post=dict(default="create", actions=["create"]),
|
|
80
|
+
put=dict(actions=["copy", "rename", "commit"]),
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
),
|
|
84
|
+
(
|
|
85
|
+
urljoin(api_url, "templates", "?"),
|
|
86
|
+
ApiManageHandler,
|
|
87
|
+
dict(
|
|
88
|
+
manager_cls=TemplateManager,
|
|
89
|
+
actions=dict(
|
|
90
|
+
delete=dict(default="remove", actions=["remove"]),
|
|
91
|
+
get=dict(default="get", actions=["get", "list", "list_variables"]),
|
|
92
|
+
post=dict(default="create", actions=["create"]),
|
|
93
|
+
put=dict(actions=["copy", "rename"]),
|
|
94
|
+
),
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
(
|
|
98
|
+
urljoin(api_url, "pools", "?"),
|
|
99
|
+
ApiManageHandler,
|
|
100
|
+
dict(
|
|
101
|
+
manager_cls=TaskPoolManager,
|
|
102
|
+
actions=dict(
|
|
103
|
+
delete=dict(default="remove", actions=["remove"]),
|
|
104
|
+
get=dict(default="get", actions=["get", "list"]),
|
|
105
|
+
post=dict(default="create", actions=["create"]),
|
|
106
|
+
put=dict(actions=["copy", "rename", "turn_into_repository"]),
|
|
107
|
+
),
|
|
108
|
+
),
|
|
109
|
+
),
|
|
110
|
+
(
|
|
111
|
+
urljoin(api_url, "presets", "?"),
|
|
112
|
+
ApiManageHandler,
|
|
113
|
+
dict(
|
|
114
|
+
manager_cls=PresetManager,
|
|
115
|
+
actions=dict(
|
|
116
|
+
get=dict(
|
|
117
|
+
actions=[
|
|
118
|
+
"list_question_presets",
|
|
119
|
+
"list_template_presets",
|
|
120
|
+
"get_question_preset",
|
|
121
|
+
"get_template_preset",
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
),
|
|
125
|
+
),
|
|
126
|
+
),
|
|
127
|
+
(urljoin(api_url, "kernelspec"), KernelSpecHandler),
|
|
128
|
+
(urljoin(api_url, "git", "author"), GitAuthorHandler),
|
|
129
|
+
]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from e2xcore.handlers import E2xApiHandler
|
|
5
|
+
from nbgrader.server_extensions.formgrader.base import check_xsrf
|
|
6
|
+
from tornado import web
|
|
7
|
+
|
|
8
|
+
from e2xauthoring.managers.dataclasses import ErrorMessage, SuccessMessage
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def status_msg(method):
|
|
12
|
+
"""Decorates a method of a BaseApiManager
|
|
13
|
+
Wraps the response in a status message (ErrorMessage or SuccessMessage)
|
|
14
|
+
and catches exceptions.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
method: The method to decorate
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def wrapper(*args, **kwargs):
|
|
21
|
+
try:
|
|
22
|
+
res = method(*args, **kwargs)
|
|
23
|
+
return SuccessMessage(data=res)
|
|
24
|
+
except Exception as e:
|
|
25
|
+
return ErrorMessage(error=getattr(e, "message", str(e)))
|
|
26
|
+
|
|
27
|
+
return wrapper
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ApiManageHandler(E2xApiHandler):
|
|
31
|
+
def initialize(self, manager_cls, actions) -> None:
|
|
32
|
+
self.__manager = manager_cls(self.coursedir)
|
|
33
|
+
self.__allowed_actions = {
|
|
34
|
+
request_type: dict(default=None, actions=[])
|
|
35
|
+
for request_type in ["delete", "get", "post", "put"]
|
|
36
|
+
}
|
|
37
|
+
self.set_allowed_actions(actions)
|
|
38
|
+
|
|
39
|
+
def set_allowed_actions(self, allowed_actions):
|
|
40
|
+
for request_type, action_dict in self.__allowed_actions.items():
|
|
41
|
+
if request_type in allowed_actions:
|
|
42
|
+
actions = allowed_actions[request_type].get("actions", [])
|
|
43
|
+
for action in actions:
|
|
44
|
+
assert hasattr(
|
|
45
|
+
self.__manager, action
|
|
46
|
+
), f"The manager class does not provide an action called {action}."
|
|
47
|
+
action_dict["default"] = allowed_actions[request_type].get(
|
|
48
|
+
"default", None
|
|
49
|
+
)
|
|
50
|
+
action_dict["actions"].extend(actions)
|
|
51
|
+
|
|
52
|
+
def extract_arguments(self, method: str):
|
|
53
|
+
params = dict()
|
|
54
|
+
json_body = self.get_json_body() or dict()
|
|
55
|
+
for arg in inspect.signature(method).parameters.keys():
|
|
56
|
+
argument = self.get_argument(name=arg, default=None)
|
|
57
|
+
if argument is None:
|
|
58
|
+
argument = json_body.get(arg, None)
|
|
59
|
+
params[arg] = argument
|
|
60
|
+
return params
|
|
61
|
+
|
|
62
|
+
def perform_action(self, action: str, allowed_actions: List[str]):
|
|
63
|
+
assert (
|
|
64
|
+
action is not None and action in allowed_actions
|
|
65
|
+
), f"Action {action} is not a valid action."
|
|
66
|
+
method = getattr(self.__manager, action)
|
|
67
|
+
arguments = self.extract_arguments(method)
|
|
68
|
+
return method(**arguments)
|
|
69
|
+
|
|
70
|
+
@status_msg
|
|
71
|
+
def handle_request(self, request_type: str):
|
|
72
|
+
action = self.get_argument(
|
|
73
|
+
"action", default=None # self.__allowed_actions[request_type]["default"]
|
|
74
|
+
)
|
|
75
|
+
if action is None:
|
|
76
|
+
action = (self.get_json_body() or dict()).get(
|
|
77
|
+
"action", self.__allowed_actions[request_type]["default"]
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
return self.perform_action(
|
|
81
|
+
action, self.__allowed_actions[request_type]["actions"]
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
@web.authenticated
|
|
85
|
+
@check_xsrf
|
|
86
|
+
def get(self):
|
|
87
|
+
self.finish(self.handle_request("get").json())
|
|
88
|
+
|
|
89
|
+
@web.authenticated
|
|
90
|
+
@check_xsrf
|
|
91
|
+
def delete(self):
|
|
92
|
+
self.finish(self.handle_request("delete").json())
|
|
93
|
+
|
|
94
|
+
@web.authenticated
|
|
95
|
+
@check_xsrf
|
|
96
|
+
def put(self):
|
|
97
|
+
self.finish(self.handle_request("put").json())
|
|
98
|
+
|
|
99
|
+
@web.authenticated
|
|
100
|
+
@check_xsrf
|
|
101
|
+
def post(self):
|
|
102
|
+
self.finish(self.handle_request("post").json())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>e²xgrader - Authoring</title><script type="text/javascript">window.base_url="{{ base_url }}",window.url_prefix="{{ url_prefix }}",window.webpackstuff="/e2x/authoring/static/js/main.1e6f65c1.js"</script><script defer="defer" src="{{base_url}}/e2x/authoring/static/js/main.1e6f65c1.js"></script>{%- block head -%} {%- endblock -%}</head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|