Skip to content
Snippets Groups Projects
Commit 898dbba4 authored by Jan Maximilian Michal's avatar Jan Maximilian Michal
Browse files

Moved some static data into a config file. Added documentation.

parent 682d8385
No related branches found
No related tags found
No related merge requests found
[META]
author = Jan Maximilian Michal
[UPLAODER]
user = root
pass = homer
host = http://localhost:8000/
rtoken = c13456ec3d71dc657e19fb826750f676
#!/usr/local/bin/python3
################################################################################
##########################################################################
#
# This script contains the main part of hallgrim and is the only script that
# needs to be invoked. The steps it takes to generate a task are as follows:
......@@ -15,12 +15,13 @@
# * a finisher compresses data if needed (needs to be implemented, maybe as
# separate subparser).
#
################################################################################
##########################################################################
import importlib
import argparse
import os
import sys
import configparser
# local import
from hallgrim.IliasXMLCreator import packer
......@@ -29,18 +30,11 @@ from hallgrim.messages import *
from hallgrim.parser import *
from hallgrim.uploader import send_script
scaffolding = r'''
meta = {{
'author': '{}',
'title': '{}',
'type': '{}',
'points': {},
}}
task = """ decription """
{}
feedback = """ decription """
'''
def get_config():
config = configparser.ConfigParser()
config.read('config.ini')
return config
def file_to_module(name):
......@@ -93,7 +87,6 @@ def parseme():
"-a",
"--author",
help="Name of the scripts author",
default='ILIAS Author',
metavar='AUTHOR'
)
parser_new.add_argument(
......@@ -129,10 +122,6 @@ def parseme():
parser_gen = subparsers.add_parser(
"upload", help="Subcommand to upload created xml instances.")
parser_gen.add_argument(
'--host',
help='The hostname of the ilias test implementation',
metavar='HOST')
parser_gen.add_argument(
'script',
help='The script that should be uploaded',
......@@ -152,6 +141,16 @@ def parseme():
def delegator(output, script_list, instances):
"""
It gets a list of filenames and delegates them to the correct handler.
Every file that does not end with .py will be ignored. Each script
is imported and then passed as module to the handler.
Arguments:
output {filename} -- where to write the finished XML document
script_list {list} -- a list of filenames that contain scripts
instances {int} -- number of instances that should be generated
"""
for script_name in filter(lambda a: a.endswith('.py'), script_list):
script = importlib.import_module(file_to_module(script_name))
handler = {
......@@ -166,6 +165,18 @@ def delegator(output, script_list, instances):
def handle_gap_questions(output, script, instances):
""" Handles gap questions of all kinds
A script can contain any mixture of gap, numeric gap and choice gap
questions. The data object that is needed by the XML creating scripts
is generated and the task itself is handled by the parser. The parser
returns the intermediate representation of the task.
Arguments:
output {str} -- where to write the final file
script {module} -- the loaded module that describes the task
instances {int} -- number of instances that should be generated
"""
script_is_valid(script, required=['meta', 'task', 'feedback'])
data = {
'type': type_selector(script.meta['type']),
......@@ -186,6 +197,16 @@ def handle_gap_questions(output, script, instances):
def handle_choice_questions(output, script, instances):
"""
Handles multiple and single choice questions. The relevant parts of the
script are fed into a parser that return the correct intermediate
representation for the task. In this case a list of answers.
Arguments:
output {str} -- where to write the finished XML document
script {module} -- the loaded module that describes the task
instances {int} -- number of instances that should be generated
"""
script_is_valid(script, required=['meta', 'task', 'choices', 'feedback'])
data = {
'type': type_selector(script.meta['type']),
......@@ -207,6 +228,25 @@ def handle_choice_questions(output, script, instances):
def handle_new_script(name, qtype, author, points):
""" Creates a new script file.
Takes in some meta information from the command line of if not present takes
it from the config.ini or uses default values.
TODO: put the configuration before the parser and use as default values
Arguments:
name {str} -- name of the script, will also become filename
qtype {str} -- question type (choice, gap, alignment)
author {str} -- the author of the script
points {float} -- number of points for the task
"""
from hallgrim.templates import scaffolding
config = get_config()
if not author:
author = config['META']['author']
with open('scripts/' + name + '.py', 'w') as new_script:
choice = ''
if qtype in ['multiple choice', 'single choice']:
......@@ -216,9 +256,27 @@ def handle_new_script(name, qtype, author, points):
author, name, qtype, points, choice).strip(), file=new_script)
info('Generated new script "{}."'.format(new_script.name))
def handle_upload(script_path, hostname):
r = send_script(script_path)
info("Uploaded %s. Status code looks %s." % (script_path, "good" if r else "bad"))
def handle_upload(script_path):
""" Passes data to the upload script.
The status code should be 500, since ILIAS always replies with that error
code after an upload is confirmed. If anything else the script will say
the status code was bad.
Arguments:
script_path {str} -- path to the file that should be uploaded
"""
config = get_config()
r = send_script(
script_path,
config['UPLAODER']['host'],
config['UPLAODER']['user'],
config['UPLAODER']['pass'],
config['UPLAODER']['rtoken'],
)
info("Uploaded %s. Status code looks %s." %
(script_path, "good" if r else "bad"))
if __name__ == '__main__':
markdown = get_markdown()
......
......@@ -10,15 +10,14 @@ def xml_print(element, **kwargs):
###
# Solution 1
# ['text', 'text', 'text']
# [('gap_solution', points), ..., (['one', 'two', 'three'], points)]
#
# Type of first item in gap tuple determines the gap type. gap might be changed
# to set
# str : str_gap
# list : choice_gap
# tuple : num_gap (x, min, max)
#
# Solution 2
# Format of gap_list
# ['text', ('gap_solution', points), ('gap_solution', points), 'text', ...]
#
###
......
scaffolding = r'''
meta = {{
'author': '{}',
'title': '{}',
'type': '{}',
'points': {},
}}
task = """ decription """
{}
feedback = """ decription """
'''
\ No newline at end of file
################################################################################
##########################################################################
#
# This is the uploader. It simplifies the testing process immensely and makes
# autoILIAS finally obsolete, since this system uses a proper Ilias
......@@ -13,34 +13,34 @@
#
# Sadly this script adds some ugly dependencies like requests_toolbelt.
#
################################################################################
##########################################################################
import os
import requests
from requests_toolbelt import MultipartEncoder
from lxml import html
__all__ = ['send_script']
# static data
host = "http://localhost:8000/"
login = {"username" : "root", "password" : "homer", "cmd[showLogin]" : "Login"}
upload_url = host + "ilias/ilias.php?ref_id=65&cmd=post&cmdClass=ilobjquestionpoolgui&cmdNode=26:gb&baseClass=ilRepositoryGUI&fallbackCmd=upload&rtoken=c13456ec3d71dc657e19fb826750f676"
import_url = host + "ilias/ilias.php?ref_id=65&cmd=post&cmdClass=ilobjquestionpoolgui&cmdNode=26:gb&baseClass=ilRepositoryGUI&fallbackCmd=questions&rtoken=c13456ec3d71dc657e19fb826750f676"
confirm_url = host + "ilias/ilias.php?ref_id=65&cmd=post&cmdClass=ilobjquestionpoolgui&cmdNode=26:gb&baseClass=ilRepositoryGUI&rtoken=c13456ec3d71dc657e19fb826750f676"
login_url = "ilias/login.php"
upload_url = "ilias/ilias.php?ref_id=67&cmd=post&cmdClass=ilobjquestionpoolgui&cmdNode=26:gb&baseClass=ilRepositoryGUI&fallbackCmd=upload&rtoken=%s"
import_url = "ilias/ilias.php?ref_id=67&cmd=post&cmdClass=ilobjquestionpoolgui&cmdNode=26:gb&baseClass=ilRepositoryGUI&fallbackCmd=questions&rtoken=%s"
confirm_url = "ilias/ilias.php?ref_id=67&cmd=post&cmdClass=ilobjquestionpoolgui&cmdNode=26:gb&baseClass=ilRepositoryGUI&rtoken=%s"
import_data = {
"cmd[importQuestions]" : "Import",
"cmd[importQuestions]": "Import",
}
confirm_data = {
"cmd[importVerifiedFile]" : "Import",
"questions_only" : "1",
"cmd[importVerifiedFile]": "Import",
"questions_only": "1",
}
def send_script(filepath):
def send_script(filepath, host, user, password, rtoken):
login = {"username": user, "password": password, "cmd[showLogin]": "Login"}
file = MultipartEncoder(fields={
'xmldoc': (
os.path.basename(filepath),
......@@ -48,13 +48,13 @@ def send_script(filepath):
'text/xml'
)
})
header = {'Content-Type': file.content_type}
# session create and login
session = requests.Session()
r = session.post(host + "ilias/login.php", data=login)
r = session.post(import_url, data=import_data)
r = session.post(upload_url, data=file, headers={'Content-Type': file.content_type})
r = session.post(confirm_url, data=confirm_data)
r = session.post(host + login_url, data=login)
r = session.post(host + (import_url % rtoken), data=import_data)
r = session.post(host + (upload_url % rtoken), data=file, headers=header)
r = session.post(host + (confirm_url % rtoken), data=confirm_data)
return r.status_code == 500
......@@ -21,12 +21,12 @@ choices = """
feedback = """
| Aussage | Wert | Begründung |
|---------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Formalparameter sind lokale Variablen. | TRUE | Die im Methodenkopf definierten Parameter heißen auch Formalparameter und werden innerhalb der Methode als Variable gebraucht. Tatsächliche Parameter sind die im Programmablauf übergebenen Werte oder Referenzen. |
| Formalparameter sind lokale Variablen. | TRUE | Die im Methodenkopf definierten Parameter heißen auch Formalparameter und werden innerhalb der Methode als Variable gebraucht. Tatsächliche Parameter sind die im Programmablauf übergebenen Werte oder Referenzen. |
| Die JVM interpretiert Java-Bytecode. | TRUE | Java-Bytecode ist das Instruction-Set der Java-Virtual-Machine |
| (false ? true : false) == (true ? false : true) | TRUE | (false ? true : false) == (true ? false : true) -> false == false -> true |
| Das rekursive Grundschema lautet: Rekurriere - Finalisiere (falls trivial) | FALSE | Das rekursive Grundschema lautet: Finalisiere (falls trivial) - Rekurriere |
| Die Java-Laufzeitumgebung beinhaltet Compiler, Klassenbibliotheken und die (JVM) Java Virtual Machine. | FALSE | Wikipedia: "Allgemein besteht die Laufzeitumgebung aus der Java Virtual Machine (Java VM), die für die Ausführung der Java-Anwendungen verantwortlich ist, einer Programmierschnittstelle (API, für Application and Programming Interface) und weiteren Programmbibliotheken." Ein Compiler gehört nicht dazu. |
| An Ausdrücke dürfen keine Zuweisungen erfolgen. | FALSE | Da zum Beispiel x[0] = 1 |
| Die Java-Laufzeitumgebung beinhaltet Compiler, Klassenbibliotheken und die (JVM) Java Virtual Machine. | FALSE | Wikipedia: "Allgemein besteht die Laufzeitumgebung aus der Java Virtual Machine (Java VM), die für die Ausführung der Java-Anwendungen verantwortlich ist, einer Programmierschnittstelle (API, für Application and Programming Interface) und weiteren Programmbibliotheken." Ein Compiler gehört nicht dazu. |
| An Ausdrücke dürfen keine Zuweisungen erfolgen. | FALSE | Da zum Beispiel x[0] = 1 |
| Methoden mit Signatur int (int) werden mit call-by-reference aufgerufen. | FALSE | Sämtliche Java Methoden werden mit call-by-value aufgerufen. Eine gute Erklärung zu den Unterschieden finden Sie hier. |
| (false ? false : true) == (false ? true : false) | FALSE | (false ? false : true) == (false ? true : false) -> true == false -> false |
"""
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment