Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ nosetests.xml
.idea
bower_componenets/
test/
.venv

runestone/build_info
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ itsdangerous==0.24
Jinja2==2.8
MarkupSafe==0.23
Paver==1.2.4
pkginfo==1.2.1
pkginfo==1.3.2
Pygments==2.1.3
pytz==2016.4
pytz==2016.6.1
six==1.10.0
snowballstemmer==1.2.1
Sphinx>=1.4.2
Sphinx>=1.4.5
sphinx-rtd-theme==0.1.8
sphinxcontrib-paverutils==1.7
SQLAlchemy>=1.0.13
Expand Down
4 changes: 4 additions & 0 deletions runestone/activecode/activecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from docutils.parsers.rst import Directive
from .textfield import *
from sqlalchemy import create_engine, Table, MetaData, select, delete
from runestone.server.componentdb import addQuestionToDB

try:
from html import escape # py3
Expand Down Expand Up @@ -158,6 +159,9 @@ class ActiveCode(Directive):
}

def run(self):

addQuestionToDB(self)

env = self.state.document.settings.env
# keep track of how many activecodes we have.... could be used to automatically make a unique id for them.
if not hasattr(env, 'activecodecounter'):
Expand Down
2 changes: 2 additions & 0 deletions runestone/assess/fitb.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .assessbase import *
import json
import random
from runestone.server.componentdb import addQuestionToDB



Expand Down Expand Up @@ -100,6 +101,7 @@ def run(self):
</p>
'''

addQuestionToDB(self)

self.options['divid'] = self.arguments[0]

Expand Down
3 changes: 2 additions & 1 deletion runestone/assess/multiplechoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .assessbase import *
import json
import random
from runestone.server.componentdb import addQuestionToDB


class MChoiceNode(nodes.General, nodes.Element):
Expand Down Expand Up @@ -154,7 +155,7 @@ def run(self):

</ul>
'''

addQuestionToDB(self)
super(MChoice,self).run()


Expand Down
3 changes: 3 additions & 0 deletions runestone/clickableArea/clickable.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive
from runestone.server.componentdb import addQuestionToDB

def setup(app):
app.add_directive('clickablearea',ClickableArea)
Expand Down Expand Up @@ -115,6 +116,8 @@ def run(self):
:incorrect: An array of the indices of the incorrect elements--same format as the correct elements.
--Content--
"""
addQuestionToDB(self)

self.assert_has_content()
self.options['divid'] = self.arguments[0]
if "iscode" in self.options:
Expand Down
4 changes: 3 additions & 1 deletion runestone/codelens/visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .pg_logger import exec_script_str_local
import json
import six

from runestone.server.componentdb import addQuestionToDB

def setup(app):
app.add_directive('codelens', Codelens)
Expand Down Expand Up @@ -180,6 +180,8 @@ class Codelens(Directive):

def run(self):

addQuestionToDB(self)

self.JS_VARNAME = ""
self.JS_VARVAL = ""

Expand Down
3 changes: 3 additions & 0 deletions runestone/dragndrop/dragndrop.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive
from runestone.server.componentdb import addQuestionToDB

def setup(app):
app.add_directive('dragndrop',DragNDrop)
Expand Down Expand Up @@ -135,6 +136,8 @@ def run(self):

The question goes here.
"""
addQuestionToDB(self)

self.options['divid'] = self.arguments[0]

if self.content:
Expand Down
3 changes: 3 additions & 0 deletions runestone/parsons/parsons.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive
from runestone.assess import Assessment
from runestone.server.componentdb import addQuestionToDB


def setup(app):
Expand Down Expand Up @@ -102,6 +103,8 @@ def findmax(alist):

"""

addQuestionToDB(self)

TEMPLATE = '''
<pre data-component="parsons" id="%(divid)s"%(maxdist)s%(order)s%(noindent)s%(language)s>
<span data-question>%(qnumber)s: %(instructions)s</span>%(code)s</pre>
Expand Down
3 changes: 3 additions & 0 deletions runestone/poll/poll.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive
from runestone.server.componentdb import addQuestionToDB



def setup(app):
Expand Down Expand Up @@ -118,6 +120,7 @@ def run(self):
:option_3: Option 3
...etc...(Up to 10 options in mode 2)
"""
addQuestionToDB(self)

self.options['divid'] = self.arguments[0]
if self.content:
Expand Down
88 changes: 88 additions & 0 deletions runestone/server/componentdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Copyright (C) 2016 Bradley N. Miller
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import print_function

from datetime import datetime

__author__ = 'bmiller'

import os
from sqlalchemy import create_engine, Table, MetaData, select, delete, update


def logSource(self):
sourcelog = self.state.document.settings.env.config.html_context.get('dsource', None)
if sourcelog:
with open(sourcelog, 'a') as sl:
sl.write("--------{}--------\n".format(self.arguments[0]))
sl.write(".. {}:: {}\n".format(self.name, " ".join(self.arguments)))
for k, v in self.options.items():
sl.write(" :{}: {}\n".format(k, v))
sl.write(" \n")
sl.write(" " + " \n".join(self.content))
sl.write("\n")


def addQuestionToDB(self):
if all(name in os.environ for name in ['DBHOST', 'DBPASS', 'DBUSER', 'DBNAME']):
dburl = 'postgresql://{DBUSER}:{DBPASS}@{DBHOST}/{DBNAME}'.format(**os.environ)
else:
dburl = None

if dburl:
sl = ""
sl += ".. {}:: {}\n".format(self.name, " ".join(self.arguments))
for k, v in self.options.items():
sl += " :{}: {}\n".format(k, v)
sl += " \n"
sl += " " + " \n".join(self.content)
sl += "\n"

basecourse = self.state.document.settings.env.config.html_context.get('basecourse', "unknown")
last_changed = datetime.now()

engine = create_engine(dburl)
meta = MetaData()
questions = Table('questions', meta, autoload=True, autoload_with=engine)
if 'difficulty' in self.options:
difficulty = self.options['difficulty']
else:
difficulty = 3

if 'author' in self.options:
author = self.options['author']
else:
author = os.environ.get('USER','Brad Miller')

srcpath, line = self.state_machine.get_source_and_line()
subchapter = os.path.basename(srcpath).replace('.rst','')
chapter = srcpath.split('/')[-2]

sel = select([questions]).where(questions.c.name == self.arguments[0])
res = engine.execute(sel).first()
if res:
if res['question'] != sl:
stmt = questions.update().where(questions.c.id == res['id']).values(question = sl, timestamp=last_changed)
engine.execute(stmt)
else:
ins = questions.insert().values(base_course=basecourse, name=self.arguments[0],
question=sl, timestamp=last_changed, is_private='F',
question_type=self.name, subchapter=subchapter,
author=author,difficulty=difficulty,chapter=chapter)
engine.execute(ins)



3 changes: 3 additions & 0 deletions runestone/shortanswer/shortanswer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive
from runestone.assess import Assessment
from runestone.server.componentdb import addQuestionToDB

def setup(app):
app.add_directive('shortanswer', JournalDirective)
Expand Down Expand Up @@ -67,6 +68,8 @@ class JournalDirective(Assessment):
def run(self):
# Raise an error if the directive does not have contents.

addQuestionToDB(self)

self.assert_has_content()

self.options['optional'] = 'data-optional' if 'optional' in self.options else ''
Expand Down
4 changes: 3 additions & 1 deletion runestone/video/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive

from runestone.server.componentdb import addQuestionToDB

def setup(app):
app.add_directive('video',Video)
Expand Down Expand Up @@ -101,6 +101,8 @@ def run(self):
:param self:
:return:
"""
addQuestionToDB(self)

mimeMap = {'mov':'mp4','webm':'webm', 'm4v':'m4v'}

sources = [SOURCE % (directives.uri(line),mimeMap[line[line.rindex(".")+1:]]) for line in self.content]
Expand Down