def update(name, short, order): oErr = ErrHandle() module = None try: # Try get the module module = BriefModule.objects.filter(Q(name=name)|Q(short=short)).first() if module == None: module = BriefModule.objects.create(name=name, short=short, order=order) else: bNeedSaving= False # Possibly update if module.name != name: module.name = name bNeedSaving = True if module.short != short: module.short = short bNeedSaving = True if module.order != order: module.order = order bNeedSaving = True if bNeedSaving: module.save() except: msg = oErr.get_error_message() oErr.DoError("briefmodule/update") return module
def update(name, order, module): oErr = ErrHandle() obj = None try: # Try get the section obj = BriefSection.objects.filter(module=module, order=order).first() if obj == None: obj = BriefSection.objects.create(name=name, module=module, order=order) else: bNeedSaving= False # Possibly update if obj.name != name: obj.name = name bNeedSaving = True if obj.order != order: obj.order = order bNeedSaving = True if obj.module != module: obj.module = module bNeedSaving = True if bNeedSaving: obj.save() except: msg = oErr.get_error_message() oErr.DoError("briefsection/update") return obj
def get_todo_html(self): # Initialize obligatoriness counting cnt_obl_needed = 0 cnt_obl_done = 0 todo = "" project = self oErr = ErrHandle() try: # FIgure out what is really needed obl_needed = ['alw'] if project.ptype != "ini": obl_needed.append("fir") for question in BriefQuestion.objects.all().order_by("order"): if question.ntype in obl_needed: cnt_obl_needed += 1 # Check if question has been dealt with obj = AnswerQuestion.objects.filter(project=project, question=question).first() if obj != None and obj.content.strip() != "": cnt_obl_done += 1 if cnt_obl_needed > 0: if cnt_obl_done == cnt_obl_needed: # Everything done todo = "<span class='glyphicon glyphicon-flag' style='color: green;'></span>" else: cnt_color = "red" if cnt_obl_done == 0 else "orange" todo = "{}/{} <span class='glyphicon glyphicon-flag' style='color: {};'></span>".format( cnt_obl_done, cnt_obl_needed, cnt_color) except: msg = oErr.get_error_message() oErr.DoError("get_todo_html") # Return what we have figured out return todo
def generate(request): """Reset system.""" oErr = ErrHandle() oData = dict(status="fail") try: # Only allow POST command of the Su if request.is_ajax() and request.method == "POST" and \ user_is_authenticated(request) and \ user_is_superuser(request): # Get the parameters passed on qd = request.POST action = qd.get("action", "") if action == "random": # Remove previous data Result.objects.all().delete() # Make sure each woorduser is assigned to a qset for wusr in WoordUser.objects.all(): qset = wusr.woorduserqsets.first() if qset == None: qset = Qset.objects.filter(woorduser__isnull=True).first() qset.woorduser = wusr qset.save() # Generate random data choices = [1, 5] for choice in choices: # Iterate over all questions for this particular choice with transaction.atomic(): for idx, oQuestion in enumerate(Question.objects.filter(choice=choice).values('id')): que_id = oQuestion['id'] oErr.Status("choice = {}, q = {}".format(choice, idx+1)) # Iterate over all users for wusr in WoordUser.objects.all(): qset = wusr.woorduserqsets.first() judgment = random.randint(1,10) # 90% of the time dontknown is false dontknow = (random.randint(1,10) == 10) # Add the random result obj = Result.objects.create(question_id=que_id, user=wusr, judgment=judgment, dontknown=dontknow) # Signal that this result has been accomplished obj = QuestionSet.objects.filter(qset=qset, question_id=que_id).first() obj.set_status("done") # REturn positively oData['status'] = "ok" else: oData['msg'] = "Not authenticated" except: msg = oErr.get_error_message() oErr.DoError("question") oData['status'] = "error" oData['msg'] = msg mimetype = "application/json" data = json.dumps(oData) return HttpResponse(data, mimetype)
def update(section, order, content, help, rtype, entries): oErr = ErrHandle() obj = None try: # Try get the question obj = BriefQuestion.objects.filter(section=section, order=order).first() if obj == None: obj = BriefQuestion.objects.create(section=section, order=order, content=content, rtype=rtype, help=help) else: bNeedSaving= False # Possibly update if obj.content != content: obj.content = content bNeedSaving = True if obj.order != order: obj.order = order bNeedSaving = True if obj.help != help: obj.help = help bNeedSaving = True if obj.rtype != rtype: obj.rtype = rtype bNeedSaving = True if obj.section != section: obj.section = section bNeedSaving = True if bNeedSaving: obj.save() # What about [entries]? if len(entries) > 0: # there are entries to be processed! for idx, item in enumerate(entries): order = idx + 1 content = item[0] help = item[1] # Check if this entry already exists entry = obj.questionentries.filter(content=content).first() if entry == None: entry = BriefEntry.objects.create(content=content, order=order, help=help, question=obj) else: bNeedSaving= False # Possibly update if entry.help != help: entry.help = help bNeedSaving = True if entry.order != order: entry.order = order bNeedSaving = True if bNeedSaving: entry.save() except: msg = oErr.get_error_message() oErr.DoError("briefsection/update") return obj
def get_value(key): """Given a key, provide its value, or NONE if it does not exist""" oErr = ErrHandle() infoval = None try: obj = TsgInfo.objects.filter(infokey__iexact=key).first() if obj != None: infoval = obj.infoval except: msg = oErr.get_error_message() oErr.DoError("TsgInfo/get_value") return infoval
def add_handle(code, url, domain="21.11114", info=None): oErr = ErrHandle() obj = None try: # Check if the code is there already obj = TsgHandle.objects.filter(code=code).first() if obj == None: obj = TsgHandle(code=code, url=url, domain=domain) if info != None: obj.info = json.dumps(info) obj.save() except: msg = oErr.get_error_message() oErr.DoError("TsgInfo/add_handle") obj = None return obj
def convert(request): oErr = ErrHandle() data = {'status': 'ok'} re_latin = re.compile(r'(\@[a-zA-Z\-\#\'\.\,\s]+)') oTranslit = TranslitChe() options = dict(vowel="macron", switches="ipa", target="Phonemic", target_cyrillic="Vernacular") if request.method.lower() == "post": qd = request.POST original = qd.get("original") if original != None and original != "": # Transform using markdown md = markdown.markdown(original, extensions=['tables']) # Figure out and transliterate lCombi = [] previous = "" for item in re_latin.split(md): if len(item) > 0: if item[0:2] == "@#": # Make a phonemic transliteration sResult = oTranslit.do_lat2phm( previous.replace("d'", "d"), options) lCombi.append( "<br /><span class='{}'>{}</span>".format( options['target'], sResult)) elif item[0] == "@": # Keep this for the next time previous = item[1:].replace("d.", "d'") # Make cyrillic transliteration sResult = oTranslit.do_lat2cyr(previous, options) lCombi.append("<span class='{}'>{}</span>".format( options['target_cyrillic'], sResult)) else: # No transliteration lCombi.append(item) # Recombine the result transliteration = "".join(lCombi) # Adapt any table elements if needed transliteration = transliteration.replace( "<table>", "<table style='width: 100%;'>") transliteration = transliteration.replace("<td>", "<td valign='top'>") # Return the result data['msg'] = transliteration else: data['status'] = 'error' data['msg'] = 'Use POST' # Return this response return JsonResponse(data)
def after_save(self, form, instance): msg = "" bResult = True oErr = ErrHandle() try: # Process the form instances if getattr(form, 'cleaned_data') != None: cleaned_data = form.cleaned_data # Walk all the cleaned_data, processing the answers to the brief questions for k, v in cleaned_data.items(): if "bq-" in k: v = v.strip() arK = k.split("-") question_id = arK[1] # See if there already was an answer to this question answer = AnswerQuestion.objects.filter( project=instance, question_id=question_id).first() if answer == None: # Is this a new answer? if v != "": # Add this answer answer = AnswerQuestion.objects.create( project=instance, question_id=question_id, content=v) elif answer.content != v: # Update the answer that is already there answer.content = v answer.save() # Calculate the 'todo' stuff of the sections lst_back = [] for sec in BriefSection.objects.all(): todo = sec.get_todo_html(instance) if todo != "": todo_id = "todo_s_{}".format(sec.id) oSection = dict(id=todo_id, todo=todo) lst_back.append(oSection) self.lst_typeahead = lst_back except: msg = oErr.get_error_message() bResult = False return bResult, msg
def set_section(request): """Set the section for a particular user viewing a particular project brief""" oData = dict(status="fail") if request.is_ajax() and request.method == "POST": oErr = ErrHandle() try: qd = request.POST # Get the project id project_id = qd.get("project_id", "") module_no = qd.get("module_no", "") section_no = qd.get("section_no", "") # Validate project if project_id != "": project = Project.objects.filter(id=project_id).first() # Validate module/section if module_no != "" and section_no != "": location = dict( module=int(module_no), section=int(section_no), date=timezone.now().strftime("%Y-%m-%dT%H:%M:%S")) # Set this information in the project information project.info = json.dumps(location) project.save() # Also set a history note History.add_action(request.user.username, project, location) oData['status'] = "ok" else: oData['msg'] = "no module or section specified" else: oData['msg'] = "no project specified" except: msg = oErr.get_error_message() oData['msg'] = msg oErr.DoError("set_section") else: oData['msg'] = "Request is not ajax" mimetype = "application/json" data = json.dumps(oData) return HttpResponse(data, mimetype)
def user_is_ingroup(request, sGroup): # Is this user part of the indicated group? username = request.user.username user = User.objects.filter(username=username).first() # glist = user.groups.values_list('name', flat=True) # Only look at group if the user is known if user == None: glist = [] else: glist = [x.name for x in user.groups.all()] # Only needed for debugging if bDebug: ErrHandle().Status("User [{}] is in groups: {}".format(user, glist)) # Evaluate the list bIsInGroup = (sGroup in glist) return bIsInGroup
def reset(request): """Reset system.""" oErr = ErrHandle() oData = dict(status="fail") try: # Only allow POST command if request.is_ajax() and request.method == "POST" and user_is_authenticated(request) and \ (user_is_superuser(request) or user_is_ingroup(request, app_editor)): # Get the parameters passed on qd = request.POST action = qd.get("action", "") if action == "questions": # THis is a POST method, continue count = Question.objects.count() # Delete Question.objects.all().delete() # Prepare message oData['msg'] = "Questions deleted: {}".format(count) elif action == "stimuli": oData['msg'] = initialize_woord("stimuli") elif action == "randomize": oData['msg'] = initialize_woord(randomize = "reset") elif action == "users": # THis is a POST method, continue count = WoordUser.objects.count() user_id = [x['id'] for x in WoordUser.objects.all().values('id')] # Delete user results count_res = Result.objects.filter(user__id__in=user_id).count() Result.objects.filter(user__id__in=user_id).delete() # Delete users WoordUser.objects.all().delete() # Reset done status for QuestionSet objects with transaction.atomic(): for obj in QuestionSet.objects.filter(status="done"): obj.status = "created" obj.save() # Prepare message oData['msg'] = "Woord-Users deleted: {}".format(count) elif action == "init": oData['msg'] = initialize_woord() # REturn positively oData['status'] = "ok" else: oData['msg'] = "Not authenticated" except: msg = oErr.get_error_message() oErr.DoError("question") oData['status'] = "error" oData['msg'] = msg mimetype = "application/json" data = json.dumps(oData) return HttpResponse(data, mimetype)
def brief_load(request): """Load the project brief definition and adapt what is there""" oErr = ErrHandle() response = reverse('brief_home') brief_name = "pbrief_structure.json" brief_lst = [] try: if not user_is_superuser(request): return response # Figure out where the JSON is situated brief_file = os.path.abspath(os.path.join(WRITABLE_DIR, brief_name)) # Now read the brief as a json document with io.open(brief_file, "r", encoding="utf-8") as fp: brief_lst = json.load(fp) # 1 - Initialisations #modules = dict() # 2 - make keys lower case brief = [] for item in brief_lst: oNew = {} for k, v in item.items(): oNew[k.lower()] = v brief.append(oNew) # 3 - read brief elements for item in brief: # Get information from the item type = item.get("type") mod = item.get("module", "") sec = item.get("section", "") qid = item.get("questionid", "") rtype = item.get("response", "") help = item.get("help", "") contents = item.get("contents", "") entry = item.get("entry", "") entries = [] if entry != "": entries = entry # 3.a is this a heading? if type == "heading": # Heading for section or module? if mod != "" and sec == "": # Module item name = contents.strip() short = item['label'].strip() order = mod + 1 # Create or update the module module = BriefModule.update(name, short, order) elif mod != "" and sec != "": # section within a module mod += 1 #module = modules[mod] name = contents.strip() order = sec # Create or update the module section = BriefSection.update(name, order, module) elif type == "paragraph": # Get the right object obj = None if mod != "" and sec == "": obj = BriefModule.objects.filter(order=mod + 1).first() elif mod != "" and sec != "": obj = BriefSection.objects.filter(order=sec, module__order=mod + 1).first() if obj == None: # Create a section without name obj = BriefSection.objects.create(name="-", order=sec, module=module) # Add the paragraph to what is already there as intro intro = obj.intro if intro == None or intro == "": intro = contents else: intro = "{}\n{}".format(intro, contents) obj.intro = intro obj.save() elif type == "question" and sec != "": # Get the current section section = BriefSection.objects.filter(order=sec, module__order=mod + 1).first() if section == None: # Create a section without name section = BriefSection.objects.create(name="-", order=sec, module=module) order = qids[qid] rtype = rtype[0:5] # Get or create this question obj = BriefQuestion.update(section, order, contents, help, rtype, entries) except: msg = oErr.get_error_message() oErr.DoError("brief_load") return response
def get_data(self, prefix, dtype): oErr = ErrHandle() lCsv = [] data = None headers = ['Woord', 'Categorie', 'Concr/Spec'] try: # Add column headers for each respondent working_id = [x['woorduser__id'] for x in Qset.objects.filter(woorduser__isnull=False).order_by( "woorduser__id").values('woorduser__id').distinct()] for id in working_id: headers.append("user_{}".format(id)) # Action depends on dtype if dtype == "json": oBack = {} oBack['user_id'] = working_id lOutput = [] elif dtype in ['csv', 'xlsx']: # Start with the header oLine = "\t".join(headers) lCsv.append(oLine) oChoice = {} for obj in Choice.objects.all(): oChoice[obj.id] = obj.name # Work through the questions one by one for oQuestion in Question.objects.all().order_by( 'choice', 'stimulus__category', 'stimulus__woord').values( 'id', 'choice', 'stimulus__category', 'stimulus__woord'): question_id = oQuestion['id'] choice = oChoice[oQuestion['choice']] category = oQuestion['stimulus__category'] woord = oQuestion['stimulus__woord'] # Action depends on dtype if dtype == "json": oQ = dict(woord=woord, category=category, choice=choice) elif dtype in ['csv', 'xlsx']: # Start creating the line for the CSV line = [] line.append("{}".format(woord)) line.append("{}".format(category)) line.append("{}".format(choice)) # Get all results for this particular question lResults = Result.objects.filter(question_id=question_id).order_by("user__id").values( "user__id", "dontknown", "judgment") # Action depends on dtype if dtype == "json": lUserResults = [] oResults = {} for oResult in lResults: user_id = oResult['user__id'] dontknown = oResult['dontknown'] judgment = -1 if dontknown else oResult['judgment'] oResults[user_id] = judgment for user_id in working_id: judgment = -1 if not user_id in oResults else oResults[user_id] lUserResults.append(judgment) oQ['results'] = lUserResults lOutput.append(oQ) elif dtype in ['csv', 'xlsx']: # Create dictionary of these results oResults = {} for oResult in lResults: user_id = oResult['user__id'] dontknown = oResult['dontknown'] judgment = oResult['judgment'] oResults[user_id] = {'dontknown': dontknown, 'judgment': judgment} # Walk all users for user_id in working_id: res = -1 oRes = oResults.get(user_id) if oRes != None: if not oRes['dontknown']: res = oRes['judgment'] line.append("{}".format(res)) # Add this line to the total output sLine = "\t".join(line) lCsv.append(sLine) # Action depends on dtype if dtype == "json": oBack['userresults'] = lOutput data = json.dumps(oBack, indent=2) elif dtype in ['csv', 'xlsx']: # REturn the whole data = "\n".join(lCsv) except: msg = oErr.get_error_message() oErr.DoError("ResultDownload get_data") data = "" # Return the data return data
def question(request): """Check this user's existence and start with the questions""" lst_stage = [ {'status': 'created', 'next': 'explain_perm', 'title': 'Toestemming'}, {'status': 'explain_perm', 'next': 'explain_conc;optout', 'title': 'Concreetheid;Helaas', 'call': "permission"}, {'status': 'optout', 'next': 'optout', 'title': 'Helaas'}, {'status': 'explain_conc', 'next': 'que_conc', 'title': 'Vragen:1', 'call': "que_conc"}, {'status': 'que_conc', 'next': 'que_conc;explain_spec','title': 'Vragen:1;Specificiteit', 'call': "que_conc"}, {'status': 'explain_spec', 'next': 'que_spec', 'title': 'Vragen:2','call': "que_spec"}, {'status': 'que_spec', 'next': 'que_spec;lastdone', 'title': 'Vragen:2;Bedankt', 'call': "que_spec"}, {'status': 'lastdone', 'next': 'lastdone', 'title': 'Welkom'}, ] lst_status = [ {"status": "created", "title": "Woordbeoordelingen", "template": "index"}, {"status": "explain_perm", "title": "Toestemming"}, {"status": "optout", "title": "Helaas"}, {"status": "explain_conc", "title": "Concreetheid"}, {"status": "que_conc", 'next': 'que_conc;explain_spec','title': 'Vragen:1;Specificiteit', 'call': "que_conc"}, {"status": "explain_spec", "title": "Specificiteit"}, {"status": "que_spec", 'next': 'que_spec;lastdone', 'title': 'Vragen:2;Bedankt', 'call': "que_spec"}, {"status": "lastdone", "title": "Bedankt"}, {"status": "wrong", "title": "Oeps"}, ] oErr = ErrHandle() bUseSlider = False # See issue #152 bDoQuestions = False try: # First make sure that this is a HTTP request assert isinstance(request, HttpRequest) # Specify the template - if something goes wrong! template_name = 'woord/wrong.html' # Define the initial context context = {'title':'Oeps','year':datetime.now().year, 'availability': True, 'pfx': APP_PREFIX,'site_url': admin.site.site_url} # Get the parameters passed on qd = request.GET if request.method.lower() == "get" else request.POST username = qd.get("username", "") lResults = qd.get("results", None) consent = qd.get("consent", "") rechtstreeks = qd.get("rechtstreeks", "") # Check for valid user - and if it exists, get a link to that user woorduser = WoordUser.get_user(username) if username == "" or woorduser == None: # Username is either void, or this user is not a WOORD user return nlogin(request) if rechtstreeks == "": # Action depends on the status of the user for oStage in lst_stage: # Is this the stage we are at? if woorduser.status == oStage['status']: # Good - check for next and alt and title arNext = oStage.get("next", "").split(";") next = arNext[0] altnext = "" if len(arNext) == 1 else arNext[1] arTitle = oStage.get("title", "(no title)").split(";") title = arTitle[0] alttitle = "" if len(arTitle) == 1 else arTitle[1] # Define the initial context context = { 'title': title,'year':datetime.now().year, 'availability': True, 'woordusername': woorduser.name, 'pfx': APP_PREFIX,'site_url': admin.site.site_url} # And check for call type calltype = oStage.get("call", "") if calltype == "": # No further verification needed woorduser.set_status(next) # Specify the template template_name = "woord/{}.html".format(next) else: # Call the process verification context, template_name = do_process(woorduser, lResults, context, calltype, next, title, altnext, alttitle, consent) # Double check the feedback if template_name == "woord/.html": # This means we have probably finished template_name = "woord/lastdone.html" # Make sure to get out of this loop! break else: for oStage in lst_status: if rechtstreeks == oStage['status']: # Define the initial context context = { 'title': oStage['title'],'year':datetime.now().year, 'availability': True, 'woordusername': woorduser.name, 'pfx': APP_PREFIX,'site_url': admin.site.site_url} tname = oStage.get("template", "") if tname == "": tname = rechtstreeks template_name = "woord/{}.html".format(tname) # Make sure to change the status woorduser.set_status(rechtstreeks) # And check for call type calltype = oStage.get("call", "") if calltype != "": arNext = oStage.get("next", "").split(";") next = arNext[0] altnext = "" if len(arNext) == 1 else arNext[1] # We have a next definition... arTitle = oStage.get("title", "(no title)").split(";") title = arTitle[0] alttitle = "" if len(arTitle) == 1 else arTitle[1] # Call the process verification context, template_name = do_process(woorduser, lResults, context, calltype, next, title, altnext, alttitle, consent) # Make sure we add special group permission(s) add_app_access(request, context) except: msg = oErr.get_error_message() oErr.DoError("question") # Render and return the page return render(request, template_name, context)
def do_process(woorduser, lResults, context, calltype, next, title, altnext, alttitle, consent): """Process the questions of this woorduser""" def get_stimulus(obj): bOnlyWoord = True # Issue #150 # Transform a question_values object into a stimulus object oBack = {} woord = obj['question__stimulus__woord'] if bOnlyWoord: oBack['stimulus'] = woord else: category = obj['question__stimulus__category'] oBack['stimulus'] = "{} {}".format(woord, category) # Issue #150: only woord, not category oBack['left'] =obj['question__choice__left'] oBack['right']=obj['question__choice__right'] oBack['questionid'] = obj['question_id'] return oBack def get_results(sResult): """Convert the string into a proper list of objects""" lBack = [] if not sResult is None: lResult = sResult.split("\n") for item in lResult: if item != "" and item[0] == "{": lBack.append(json.loads(item)) return lBack oErr = ErrHandle() bUseSlider = False # See issue #152 template_name = "" try: # What calltype are we in? if calltype == "permission": # Make sure to ask again if unclear context['title'] = "Toestemming" template_name = "woord/{}.html".format("explain_perm") # Check whether the user gave permission if consent != None: nowdate = timezone.now().strftime("%c") if consent == "true": woorduser.set_status(next) woorduser.set_consent("User consented at: {}".format(nowdate)) context['title'] = title template_name = "woord/{}.html".format(next) elif consent == "false": woorduser.set_status(altnext) context['title'] = alttitle template_name = "woord/{}.html".format(altnext) woorduser.set_consent("User opted out at: {}".format(nowdate)) else: # We are processing questions # Get all the questions assigned to this user, but not yet done qset = Qset.objects.filter(woorduser=woorduser).first() if qset == None: # No set has yet been assigned to this user: assign one qset = Qset.objects.filter(woorduser__isnull=True).first() if qset == None: # No set is available anymore context['availability'] = False else: # Assign this set to the user qset.woorduser = woorduser qset.save() # Continue if all is well if not qset is None: # Process any questions handed over to me lst_result = get_results(lResults) lst_question = [] for item in lst_result: # Find out which question this is question = Question.objects.filter(id=item['questionid']).first() if not question is None: # Add the response to this question judgment = item['score'] dontknow = item['dontknow'] result = Result.objects.create( user=woorduser, question=question, judgment=judgment, dontknown=dontknow) # do *NOT* change the status of the question - others still need to respond!! #question.status = "done" #question.save() # Save the id lst_question.append(question.id) # Set the corresponding QuestionSet statuses to 'done' with transaction.atomic(): for qitem in QuestionSet.objects.filter(qset=qset, question__id__in=lst_question): # Make sure to change the status of the corresponding qset object qitem.status = "done" qitem.save() # Find the remaining questions: FOR THIS PARTICULAR CHOICE TYPE choice_id = 0 if calltype == "que_conc": # Restricting to Abstract/Concrete questions (id=1) choice_id = 1 else: # Restricting to specificity questions (id=5) choice_id = 5 # Get the questions for a particulare CHOICE type for this user # to which this user has no Result yet questions = QuestionSet.objects.filter( qset__woorduser=woorduser, status='created', question__choice_id=choice_id).order_by('order').values( 'question_id', 'question__stimulus__woord', 'question__stimulus__category', 'question__choice__left', 'question__choice__right') # Check if there were any questions left if questions.count() == 0: # These were the last questions woorduser.set_status(altnext) context['title'] = alttitle template_name = "woord/{}.html".format(altnext) else: # Go for the next batch of questions lst_stimulus = [get_stimulus(x) for x in questions[:10]] # Calculate the percentage of questions still needing to be answered total_num = qset.questions.filter(choice_id=choice_id).count() # done_count = qset.questions.filter(status="done", choice_id=choice_id).count() done_count = QuestionSet.objects.filter(qset=qset, status="done", question__choice_id=choice_id).count() percentage = done_count / total_num # Additional context information context['woordusername'] = woorduser.name context['lst_stimulus'] = lst_stimulus context['question_url'] = reverse('woord_question') context['percentage'] = percentage context['progr_done'] = done_count context['progr_total'] = total_num context['user_slider'] = bUseSlider woorduser.set_status(next) context['title'] = title template_name = "woord/{}.html".format(next) else: # Something has gone terribly wrong... woorduser.set_status("wrong") context['title'] = "Sorry" template_name = "woord/wrong.html" except: msg = oErr.get_error_message() oErr.DoError("do_questions") return context, template_name
def initialize_woord(additional=None, randomize=None): """Fill the application if this is needed Initial: only use stimuli.txt Issue #147: read stimuli2021.txt, omitting first line with column headers """ def get_stimulus(row): woord = "" cat = "" note = "" oBack = {} try: if len(row) == 3: woord = row[0] cat = row[1] note = row[2] oBack = dict(woord=woord, cat=cat, note=note) elif row != "": # parts = re.split(r'\s+', row) parts = re.split(r'\t', row) if len(parts) > 1: woord = parts[0] cat = parts[1] # parts[1].replace("(", "").replace(")", "") note = parts[2] oBack = dict(woord=woord, cat=cat, note=note) else: # Empty row iStop = 1 except: msg = oErr.get_error_message() oErr.DoError("get_stimulus") return oBack oErr = ErrHandle() bNeedRandomization = False msg = "no changes" bOrderStimuli = True # See issue #151: (valid) choices must be treated one by one for the user STIMULI_NAME = "stimuli2021.txt" # Was: stimuli.txt lhtml = [] try: # Figure out directory and file names woord_dir = os.path.abspath(os.path.join(WRITABLE_DIR, "../woord")) choices_file = os.path.abspath(os.path.join(woord_dir, "choices.txt")) stimuli_file = os.path.abspath(os.path.join(woord_dir, STIMULI_NAME)) if randomize != None and randomize == "reset": bNeedRandomization = True # Check on number of users if WoordUser.objects.count() <= 1: # Create 20 random users with transaction.atomic(): for number in range(NUMBER_OF_PARTICIPANTS): username = WoordUser.generate_new() WoordUser.objects.create(name=username) # Reset done status for QuestionSet objects with transaction.atomic(): for obj in QuestionSet.objects.filter(status="done"): obj.status = "created" obj.save() # Message lhtml.append("Created {} users".format(NUMBER_OF_PARTICIPANTS)) # Check on choices if Choice.objects.count() == 0: # Load choices with open(choices_file) as f: reader = csv.reader(f, dialect='excel', delimiter='\t') left, right = zip(*reader) # Make lists left_lst = list(left) right_lst = list(right) # Copy and create from these lists break_points = ['heel', 'niet'] with transaction.atomic(): for idx, left in enumerate(left_lst): right = right_lst[idx] name = left for bp in break_points: if bp in left: name = left.split(bp)[1].strip() break # Create object Choice.objects.create(name=name, left=left, right=right) lhtml.append("Created {} choices".format(len(left_lst))) # Check on stimuli oErr.Status("initialize_woord #1") if additional != None and additional == "stimuli": # THis is a POST method, continue count = Stimulus.objects.count() # Delete Stimulus.objects.all().delete() # Prepare message lhtml.append("Stimuli deleted: {}".format(count)) if Stimulus.objects.count() == 0: bNeedRandomization = True oErr.Status("initialize_woord #2") # Load the stimuli with open(stimuli_file) as f: reader = csv.reader(f, dialect='excel-tab') lst_stimuli = [get_stimulus(row) for row in reader] oErr.Status("initialize_woord #3") # Add the stimuli into the objects with transaction.atomic(): # Note: skip the first line containing column headers for oStimulus in lst_stimuli[1:]: woord = oStimulus['woord'] cat = oStimulus['cat'] note = oStimulus['note'] Stimulus.objects.create(woord=woord, category=cat, note=note) oErr.Status("initialize_woord #4") lhtml.append("Read from file {} stimuli".format(len(lst_stimuli))) # Otherwise in need of randomization? if Question.objects.count() == 0: bNeedRandomization = True # Do we need to randomize? if bNeedRandomization: # Remove previous questions Question.objects.all().delete() # Remove previous questions Qset.objects.all().delete() lhtml.append("Removed previous questions and qsets") # Combine stimuli and choices so that we have the full set if bOrderStimuli: # See issue #151 result_sets = [] with transaction.atomic(): # Iterate over the choices in the correct order for choice in Choice.objects.filter(valid=True).order_by("id"): # Stimuli for this result set result = [] for stimulus in Stimulus.objects.all(): obj = Question.objects.create(stimulus=stimulus, choice=choice) result.append(obj.id) # Add this set to the result_sets result_sets.append(result) lhtml.append("Created {} questions".format(Question.objects.count())) # Divide the shuffled questions over sets num_sets = NUMBER_OF_PARTICIPANTS + 10 for i in range(num_sets): # Show where we are oErr.Status("initialize_woord random set #{}".format(i)) # Create a Qset qset = Qset.objects.create() # Walk all the result sets order = 0 for result in result_sets: # Shuffle the question object id's random.shuffle(result) # Make the links for this shuffle with transaction.atomic(): for idx, question_id in enumerate(result): order = order + 1 QuestionSet.objects.create(qset=qset, question_id=question_id, order=order) lhtml.append("Created {} question sets".format(num_sets)) else: result = [] # Full randomization with transaction.atomic(): # Iterate over all stimuli (will be 5000) # 2021: these are now 1823 for stimulus in Stimulus.objects.all(): # And then over all choices (should be just 1) # 2021: this is now 2 for choice in Choice.objects.filter(valid=True): # This yields 10,000 objects obj = Question.objects.create(stimulus=stimulus, choice=choice) result.append(obj.id) lhtml.append("Created {} questions".format(Question.objects.count())) # Divide the shuffled questions over sets num_sets = NUMBER_OF_PARTICIPANTS + 10 for i in range(num_sets): # Show where we are oErr.Status("initialize_woord random set #{}".format(i)) # Shuffle the question object id's random.shuffle(result) # Create a Qset qset = Qset.objects.create() # Make the links for this shuffle with transaction.atomic(): for idx, question_id in enumerate(result): order = idx + 1 QuestionSet.objects.create(qset=qset, question_id=question_id, order=order) lhtml.append("Created {} question sets".format(num_sets)) # COmbine the message msg = "<br />".join(lhtml) except: msg = oErr.get_error_message() oErr.DoError("initialize_woord") return msg
def get_crpp_texts(sLng, sPart, sFormat, status): """Read the list of texts from the /crpp service (if available)""" oErr = ErrHandle() try: # Construct the object we pass along oTxtList = {'userid': "erwin", 'lng': sLng, 'ext': sFormat} # Possibly add 'dir' if sPart != None and sPart != "": oTxtList['dir'] = sPart # Set the correct URL url = CRPP_HOME + '/txtlist?' + json.dumps(oTxtList) # Default reply oBack = {} # Get the data from the CRPP api try: r = requests.get(url) except: # Getting an exception here probably means that the back-end is not reachable (down) oBack['status'] = 'error' oBack['code'] = "get_crpp_texts(): The back-end server (crpp) cannot be reached. Is it running? \n{} \nURL={}".format( get_exc_message(), url) return oBack # Action depends on what we receive if r.status_code == 200: # Convert to JSON reply = json.loads(r.text.replace("\t", " ")) # Get the [content] part (note: no final 's') oContent = reply['content'] # If all is well, then we receive just a jobid if "jobid" in oContent: sJobId = oContent['jobid'] # Now continue to ask for the status oTxtListStatus = {'userid': "erwin", 'jobid': sJobId} url = CRPP_HOME + '/statusxl?' + json.dumps(oTxtListStatus) bDone = False while not bDone: # Get the data from the CRPP api try: r = requests.get(url) except: error_info = sys.exc_info() iStop = True # Action depends on what we receive if r.status_code == 200: # Convert the reply to JSON reply = json.loads(r.text.replace("\t", " ")) # Get the [content] part (note: no final 's') oContent = reply['content'] # Get the status part oStatus = reply['status'] if oStatus['code'] == "error": # There is an error oBack['status'] = 'error' oBack['code'] = oContent['code'] + oContent['msg'] bDone = True # Need to store this status!!! status.set("crpp", oBack) elif oStatus['code'] == "finished": # The process is ready bDone = True # Get the textlist oTextList = oContent['textlist'] # Define the lists oBack['count'] = oTextList['texts'] oBack['subtype'] = oTextList['subtype'] oBack['genre'] = oTextList['genre'] oBack['paths'] = oTextList['paths'] oBack['txtlist'] = oTextList['list'] oBack['status'] = 'ok' # What we show in the end is not what needs to be returned oShow = dict(count=oTextList['texts'], subtype=oTextList['subtype'], paths=oTextList['paths']) oShow['status'] = 'ok' oShow['status.code'] = oStatus['code'] # Need to store this status!!! status.set("crpp", oShow) else: # Update the synchronisation object that contains all relevant information oBack['lng'] = sLng oBack['part'] = sPart oBack['format'] = sFormat oBack['count'] = oContent['total'] oBack['status.code'] = oStatus['code'] oBack['last.url'] = url status.set("crpp", oBack) # DEBUGGING sMsg = oStatus['code'] if 'msg' in oContent: sMsg += " " + oContent['msg'] if 'msg' in oStatus: sMsg += " " + oStatus['msg'] oErr.Status(sMsg) # Make sure we wait some time before making the next request period = 0.400 nexttime = time.time() + period bReady = False while not bReady: now = time.time() bReady = (now > nexttime) else: # There is an error oBack['status'] = 'error' oBack['code'] = r.status_code bDone = True else: oBack['status'] = 'error' oBack['code'] = "" else: oBack['status'] = 'error' oBack['code'] = r.status_code except: oBack['status'] = 'error' oBack['code'] = sys.exc_info()[1] # REturn what we have return oBack
def add_to_context(self, context, instance): # First execute the [BriefEdit] default context additions context = super(BriefMaster, self).add_to_context(context, instance) # Now we may continue here oErr = ErrHandle() try: # Look at the object_id context['object_id'] = "{}".format(instance.id) context['pname'] = instance.name ## Make sure we add special group permission(s) #add_app_access(self.request, context) # Default values module = 1 # Start with section #1 "Language" section = -1 # No section opened # Possibly get alternative values if instance.info != "" and instance.info[0] == "{": info = json.loads(instance.info) module = info.get('module', 1) section = info.get('section', -1) # We need to have the form object too qform = context['queForm'] lst_module = [] for mod in BriefModule.objects.all().order_by("order"): # Start an object for this module oModule = dict(module=mod) # Is this the opening section? if mod.order == module: oModule['show'] = True # Find out what sections there are in this module lst_section = [] for sec in mod.modulesections.all().order_by("order"): # Start section object oSection = dict(section=sec) # Is this the section to be shown? if section >= 0 and mod.order == module and sec.order == section: oSection['show'] = True # Find all the questions in this section lst_question = [] for question in sec.sectionquestions.all().order_by( "order"): # The main part of the question is the question itself oQuestion = dict(question=question) # The second part of the question is the field-name formfieldname = "bq-{}".format(question.id) if question.rtype == "entri": # This means that the 'formfield' should contain a table with add possibilities oQuestion['formfield'] = "" oQuestion[ 'entries'] = question.questionentries.all( ).order_by('order') # Get the existing answers answers = [] aq = AnswerQuestion.objects.filter( project=instance, question=question).first() if aq != None and aq != "" and aq[0] == "[": answers = json.loads(aq.content) oQuestion['answers'] = answers else: # The formfield is the normal form field oQuestion['formfield'] = qform[formfieldname] # Add question to list lst_question.append(oQuestion) # Add questions to section oSection['questions'] = lst_question # Calculate how many need to be done in this section oSection['todo'] = sec.get_todo_html(instance) # Add section lst_section.append(oSection) # Add sections to this module oModule['sections'] = lst_section # Add module lst_module.append(oModule) # THis is what we pass on context['modules'] = lst_module # Explicitly say what the mode is context[ 'mode'] = "view" if not context['is_app_editor'] else "edit" context['title'] = "{} brief".format(instance.name) context['downloadurl'] = reverse('brief_report', kwargs={'pk': instance.id}) except: msg = oErr.get_error_message() oErr.DoError("BriefMaster/add_to_context") # Return the context we have adapted return context