2020__author__ = 'bmiller'
2121
2222import os
23+ from os import environ
24+ import re
2325from sqlalchemy import create_engine , Table , MetaData , select , and_
24- from . import get_dburl
26+ from sqlalchemy . orm . session import sessionmaker
2527from runestone .common .runestonedirective import RunestoneDirective
2628
29+ def get_dburl (outer = {}):
30+ """
31+ Return a nicely formatted database connection URL
32+ This function should not be used to configure a DAL db_uri for web2py that will already
33+ be configured in settings.
34+
35+ :param outer: pass locals from the calling environment
36+ :return: string
37+ """
38+ # outer may contain the locals from the calling function
39+ # nonlocal env, settings # Python 3 only
40+
41+ if 'WEB2PY_CONFIG' in environ :
42+ w2py_config = environ ['WEB2PY_CONFIG' ]
43+ if w2py_config == 'development' :
44+ return environ ['DEV_DBURL' ]
45+
46+ if w2py_config == 'production' :
47+ return environ ['DBURL' ]
48+
49+ if w2py_config == 'test' :
50+ return environ ['TEST_DBURL' ]
51+
52+ if 'options' in outer :
53+ return outer ['options' ].build .template_args ['dburl' ]
54+
55+ if 'env' in outer :
56+ return outer ['env' ].config .html_context ['dburl' ]
57+
58+ if 'env' in globals ():
59+ return globals ()['env' ].config .html_context ['dburl' ]
60+
61+ ret = None
62+ if 'settings' in outer :
63+ ret = outer ['settings' ].database_uri
64+
65+ if 'settings' in globals ():
66+ ret = globals ()['settings' ].database_uri .replace ('postgres:' ,'postgresql:' )
67+
68+ if ret :
69+ return re .sub (r'postgres:.*/' , 'postgresql:/' , ret )
70+
71+ raise RuntimeError ("Cannot configure a Database URL!" )
72+
73+
2774# create a global DB query engine to share for the rest of the file
2875try :
2976 dburl = get_dburl ()
3077 engine = create_engine (dburl , client_encoding = 'utf8' , convert_unicode = True )
78+ Session = sessionmaker ()
3179 engine .connect ()
80+ Session .configure (bind = engine )
81+ sess = Session ()
3282except Exception as e : # psycopg2.OperationalError
3383 dburl = None
3484 engine = None
3585 meta = None
86+ sess = None
87+ print (e )
3688 print ("Skipping all DB operations because environment variables not set up" )
3789else :
3890 # If no exceptions are raised, then set up the database.
4193 assignment_questions = Table ('assignment_questions' , meta , autoload = True , autoload_with = engine )
4294 courses = Table ('courses' , meta , autoload = True , autoload_with = engine )
4395
96+
97+ def setup (app ):
98+ app .connect ('env-before-read-docs' , reset_questions )
99+ app .connect ('build-finished' , finalize_updates )
100+
101+
102+ def reset_questions (app , env , docnames ):
103+ if sess :
104+ basecourse = env .config .html_context .get ('basecourse' )
105+ stmt = questions .update ().where (and_ (questions .c .base_course == basecourse ,
106+ questions .c .question_type != 'page' )).values (from_source = 'F' )
107+ sess .execute (stmt )
108+
109+ def finalize_updates (app , excpt ):
110+ if sess :
111+ if excpt is None :
112+ sess .commit ()
113+ else :
114+ sess .rollback ()
115+
116+
44117def logSource (self ):
45118 sourcelog = self .state .document .settings .env .config .html_context .get ('dsource' , None )
46119 if sourcelog :
@@ -87,23 +160,23 @@ def addQuestionToDB(self):
87160 id_ = self .options ['divid' ]
88161 sel = select ([questions ]).where (and_ (questions .c .name == id_ ,
89162 questions .c .base_course == basecourse ))
90- res = engine .execute (sel ).first ()
163+ res = sess .execute (sel ).first ()
91164 try :
92165 if res :
93- stmt = questions .update ().where (questions .c .id == res ['id' ]).values (question = self .block_text , timestamp = last_changed , is_private = 'F' , question_type = self .name , subchapter = self .subchapter , autograde = autograde , author = author ,difficulty = difficulty ,chapter = self .chapter , practice = practice , topic = topics )
94- engine .execute (stmt )
166+ stmt = questions .update ().where (questions .c .id == res ['id' ]).values (question = self .block_text , timestamp = last_changed , is_private = 'F' , question_type = self .name , subchapter = self .subchapter , autograde = autograde , author = author ,difficulty = difficulty ,chapter = self .chapter , practice = practice , topic = topics , from_source = 'T' )
167+ sess .execute (stmt )
95168 else :
96- ins = questions .insert ().values (base_course = basecourse , name = id_ , question = self .block_text , timestamp = last_changed , is_private = 'F' , question_type = self .name , subchapter = self .subchapter , autograde = autograde , author = author ,difficulty = difficulty ,chapter = self .chapter , practice = practice , topic = topics )
169+ ins = questions .insert ().values (base_course = basecourse , name = id_ , question = self .block_text , timestamp = last_changed , is_private = 'F' , question_type = self .name , subchapter = self .subchapter , autograde = autograde , author = author ,difficulty = difficulty ,chapter = self .chapter , practice = practice , topic = topics , from_source = 'T' )
97170
98- engine .execute (ins )
171+ sess .execute (ins )
99172 except UnicodeEncodeError :
100173 raise self .severe ("Bad character in directive {} in {}/{}. This will not be saved to the DB" .format (id_ , self .chapter , self .subchapter ))
101174
102175def getQuestionID (base_course , name ):
103176
104177 sel = select ([questions ]).where (and_ (questions .c .name == name ,
105178 questions .c .base_course == base_course ))
106- res = engine .execute (sel ).first ()
179+ res = sess .execute (sel ).first ()
107180 if res :
108181 return res ['id' ]
109182 else :
@@ -114,7 +187,7 @@ def getOrInsertQuestionForPage(base_course=None, name=None, is_private='F', ques
114187
115188 sel = select ([questions ]).where (and_ (questions .c .name == name ,
116189 questions .c .base_course == base_course ))
117- res = engine .execute (sel ).first ()
190+ res = sess .execute (sel ).first ()
118191
119192 if res :
120193 id = res ['id' ]
@@ -126,7 +199,7 @@ def getOrInsertQuestionForPage(base_course=None, name=None, is_private='F', ques
126199 author = author ,
127200 difficulty = difficulty ,
128201 chapter = chapter )
129- res = engine .execute (stmt )
202+ res = sess .execute (stmt )
130203 return id
131204 else :
132205 ins = questions .insert ().values (
@@ -139,14 +212,14 @@ def getOrInsertQuestionForPage(base_course=None, name=None, is_private='F', ques
139212 author = author ,
140213 difficulty = difficulty ,
141214 chapter = chapter )
142- res = engine .execute (ins )
215+ res = sess .execute (ins )
143216 return res .inserted_primary_key [0 ]
144217
145218def addAssignmentQuestionToDB (question_id , assignment_id , points , activities_required = 0 , autograde = None , which_to_grade = None , reading_assignment = None , sorting_priority = 0 ):
146219 # now insert or update the assignment_questions row
147220 sel = select ([assignment_questions ]).where (and_ (assignment_questions .c .assignment_id == assignment_id ,
148221 assignment_questions .c .question_id == question_id ))
149- res = engine .execute (sel ).first ()
222+ res = sess .execute (sel ).first ()
150223 vals = dict (
151224 assignment_id = assignment_id ,
152225 question_id = question_id ,
@@ -159,35 +232,35 @@ def addAssignmentQuestionToDB(question_id, assignment_id, points, activities_req
159232 if res :
160233 #update
161234 stmt = assignment_questions .update ().where (assignment_questions .c .id == res ['id' ]).values (** vals )
162- engine .execute (stmt )
235+ sess .execute (stmt )
163236 else :
164237 #insert
165238 ins = assignment_questions .insert ().values (** vals )
166- engine .execute (ins )
239+ sess .execute (ins )
167240
168241def getCourseID (coursename ):
169242 sel = select ([courses ]).where (courses .c .course_name == coursename )
170- res = engine .execute (sel ).first ()
243+ res = sess .execute (sel ).first ()
171244 return res ['id' ]
172245
173246def addAssignmentToDB (name = None , course_id = None , assignment_type_id = None , deadline = None , points = None ):
174247
175248 last_changed = datetime .now ()
176249 sel = select ([assignments ]).where (and_ (assignments .c .name == name ,
177250 assignments .c .course == course_id ))
178- res = engine .execute (sel ).first ()
251+ res = sess .execute (sel ).first ()
179252 if res :
180253 stmt = assignments .update ().where (assignments .c .id == res ['id' ]).values (
181254 assignment_type = assignment_type_id ,
182255 duedate = deadline ,
183256 points = points
184257 )
185- engine .execute (stmt )
258+ sess .execute (stmt )
186259 a_id = res ['id' ]
187260 # delete all existing AssignmentQuestions, so that you don't have any leftovers
188261 # this is safe because grades and comments are associated with div_ids and course_names, not assignment_questions rows.
189262 stmt2 = assignment_questions .delete ().where (assignment_questions .c .assignment_id == a_id )
190- engine .execute (stmt2 )
263+ sess .execute (stmt2 )
191264
192265 else :
193266 ins = assignments .insert ().values (
@@ -196,7 +269,7 @@ def addAssignmentToDB(name = None, course_id = None, assignment_type_id = None,
196269 assignment_type = assignment_type_id ,
197270 duedate = deadline ,
198271 points = points )
199- res = engine .execute (ins )
272+ res = sess .execute (ins )
200273 a_id = res .inserted_primary_key [0 ]
201274
202275 return a_id
@@ -206,12 +279,12 @@ def addHTMLToDB(divid, basecourse, htmlsrc, feedback=None):
206279 last_changed = datetime .now ()
207280 sel = select ([questions ]).where (and_ (questions .c .name == divid ,
208281 questions .c .base_course == basecourse ))
209- res = engine .execute (sel ).first ()
282+ res = sess .execute (sel ).first ()
210283 try :
211284 if res :
212285 if res ['htmlsrc' ] != htmlsrc or res ['feedback' ] != feedback :
213286 stmt = questions .update ().where (questions .c .id == res ['id' ]).values (htmlsrc = htmlsrc , feedback = feedback , timestamp = last_changed )
214- engine .execute (stmt )
287+ sess .execute (stmt )
215288 except UnicodeEncodeError :
216289 print ("Bad character in directive {}" .format (divid ))
217290 except :
@@ -220,7 +293,7 @@ def addHTMLToDB(divid, basecourse, htmlsrc, feedback=None):
220293def get_HTML_from_DB (divid , basecourse ):
221294 sel = select ([questions ]).where (and_ (questions .c .name == divid ,
222295 questions .c .base_course == basecourse ))
223- res = engine .execute (sel ).first ()
296+ res = sess .execute (sel ).first ()
224297 if res :
225298 return res ['htmlsrc' ]
226299 else :
0 commit comments