description="Select which category the forum should be listed "
                     "under. A forum can exist in multiple categories, "
                     "although using only one category is recommended.",
         description_msgid="help_category",
         condition="object/getCategories",
         label="Category",
         label_msgid="label_category",
         i18n_domain="ploneboard",
       )
 ),
 IntegerField('maxAttachments',
     write_permission=ManageForum,
     default=1,
     widget=IntegerWidget(
          description="Select the maximum number of attachments per comment.",
          description_msgid="help_maxattachments",
          label="Maximum number of attachments",
          label_msgid="label_maxattachments",
          i18n_domain="ploneboard",
     )
 ),
 IntegerField('maxAttachmentSize',
     write_permission=ManageForum,
     vocabulary=AttachmentSizes,
     default=100,
     widget=SelectionWidget(
          description="Select the maximum size for attachments.",
          description_msgid="help_maxattachmentsize",
          label="Maximum attachment size",
          label_msgid="label_maxattachmentsize",
          i18n_domain="ploneboard",
Ejemplo n.º 2
0
class QuizResult(ATFolder):
    """Keeps together all the questions results for a specific student from a quiz in a specific lecture."""
   
    
    
    schema = ATFolderSchema.copy() + Schema((
        
        StringField('title',
                required=True,
                searchable=0,
                default='Quiz result',
                widget=StringWidget(
                    label='Title',
                    description='The main title of the tutorial.',
                    i18n_domain='plone'),
               
            ),
        BooleanField('openquest',
                     default=0,
                      widget=BooleanWidget(visible={'edit':'invisible', 'view':'invisible'}, ),),
        BooleanField('haveanswer',
                     default=0,
                      widget=BooleanWidget(visible={'edit':'invisible', 'view':'invisible'}, ),
                  ),
                     
        ImageField('CurrentQuestionImage',
                   #original_size=(600,600),
                   #max_size=(600,600),
                   sizes={ 'mini' : (80,80),
                           'normal' : (200,200),
                            'big' : (100,100),
                            'maxi' : (500,500),
                           },
                   widget=ImageWidget(label='quis question image',
                                      description='Image for the current question, displayed to the right of main text of the slide. Possible formats for uploaded images are: png, gif and jpeg.', 
                                      #macro='tutorwebimage',
                             # condition ='object/isImageFormat',
                                       )),
        ReferenceField('StudentQuestions',
                    #vocabulary="getAvailableCourses",
                    widget=ReferenceWidget(
                           label="quiz question",
                           description='A question student has been asked',
                           destination=".",
                           #destination_types=("QuestionResult",),
                           #visible={'edit':'invisible'},
                           
                           ),
                       multiValued=True,
                       relationship='hasQuestion',
                       allowed_types= ("InvisibleQuestion",),
                        
                   ),  

        ReferenceField('CurrentQuestion',
                    #vocabulary="getAvailableCourses",
                    widget=ReferenceWidget(
                           label="quiz question which is open",
                           description='A question student is being asked',
                           destination=".",
                           #destination_types=("QuestionResult",),
                           #visible={'edit':'invisible'},
                           
                           ),
                       multiValued=False,
                       relationship='hasOpenQuiz',
                       allowed_types= ("InvisibleQuestion",),
                        
                   ),  
        ComputedField('grade',
                  expression='context.computeGrade()',
                  widget=StringWidget(visible={'edit':'invisible','view':'invisible' },),
          
            ),
        IntegerField('totalattempts',
                     default='0',
                     widget=IntegerWidget(description='Number of times students has submitted a questions to quiz.', 
                                         visible={'edit':'invisible','view':'invisible'}, ),
                  ),
         IntegerField('correctattempts',
                        default='0',
                     widget=IntegerWidget(description='Number of times students has submitted a questions to quiz.', 
                                         visible={'edit':'invisible', 'view':'invisible'}, ),
                  ),
         FloatField('totscore',
                     default=0.0,
                     widget=IntegerWidget(description='total score so far.', 
                                       visible={'edit':'invisible','view':'invisible' },   ),
                  ),
           StringField('lasteightgrades',
                       default='[]',
                     widget=StringWidget(description='Number of times students has submitted a questions to quiz.', 
                                         visible={'edit':'invisible','view':'invisible' }, ),),
         StringField('studentRandId',
                       default='',
                     widget=StringWidget(description='random generated id to identify student.', 
                                         visible={'edit':'invisible','view':'invisible' }, ),
        ),
        StringField('studentId',
                       default='',
                     widget=StringWidget(description='login id of student.', 
                                         visible={'edit':'invisible','view':'invisible' }, ),                   
       ),

          #StringField('chosenquestid',
          #             default='',
          #           widget=StringWidget(description='Number of times students has submitted a questions to quiz.', 
          #                               visible={'view':'invisible', 'edit':'invisible'}, ),
          #        ),

       #StringField('chosenquestpath',
       #                default='',
       #              widget=StringWidget(description='Number of times students has submitted a questions to quiz.', 
        #                                 visible={'view': 'invisible', 'edit':'invisible'}, ),
         #         ),
       
     ))
    __implements__ = (ATFolder.__implements__)
    
    global_allow = False
    meta_type = 'QuizResult'          # zope type name
    portal_type = meta_type          # plone type name
    archetype_name = 'QuizResult' # friendly type name
    #_at_rename_after_creation = True  #automatically create id
    security = ClassSecurityInfo()
    
    # ATT: Make sure this work when create from twmigrate.py
    changed = True
    studentgrade = atapi.ATFieldProperty('grade')
    totalscore = atapi.ATFieldProperty('totscore')
    scoresofar = []
    # REMEMBER check if reversed or not when displayed????????
    lasteight = atapi.ATFieldProperty('lasteightgrades')
    quizattempts = atapi.ATFieldProperty('totalattempts')
    correctquizattempts = atapi.ATFieldProperty('correctattempts')
    chosenquestionid = atapi.ATFieldProperty('chosenquestid')
    chosenquestionpath = atapi.ATFieldProperty('chosenquestpath')
    #openquestion = atapi.ATFieldProperty('openquest')
    
    def __init__(self, oid=None, **kwargs):
        self.changed = True
        ATFolder.__init__(self, oid, **kwargs)
    
    # Must add:

    # getVocabulary is now in Lecture.py
    # returns the answers
    # getSelectedItem() in Lecture.py
    # questionIsInline in Lecture.py
    # isCorrect(item) in Lecture.py
    #
    # get chosen question already here
    #   then must transformR(True)
    #   then transformquizquestion
    #   getQuestionData()
    #   inlineAnswer()
    #  getQuestImg and getQuestionImageTag
    #
    def getQuestionResultForQuestion(self, question):
        qresults = question.getFolderContents(contentFilter={"portal_type": "QuestionResult"})
        return qresults[0].getObject()
    def getVocabulary(self):
        """return the possible answers formatted as vocabulary"""
        question = self.getCurrentQuestion()
        if (question):
            qr = self.getQuestionResultForQuestion(question)
            suggestedAnswerIds = (qr.getSuggestedAnswer())
            idl = DisplayList()
            ans = question.getAnswerDisplay().values()
       
            for id in suggestedAnswerIds:
                idl.add(id, ans[int(id)])
            return Vocabulary(idl, self, None)
        else:
            '''bad error no open question'''
            return ''
        
    def isCorrect(self, item):
        question = self.getCurrentQuestion()
        if (question):
            answers = question.getAnswerList()
            for row in answers:
                if (row['answerid'] == str(item)):
                    if (row['correct'] == '1'):
                        return True
            return False
        else:
            return False
    def startQuiz(self):
        '''student has asked for a question in quiz'''
        parent = aq_parent(self)
        lec = aq_parent(parent)
        if (DEBUG):
            tmpout = tempfile.mkdtemp()
            tex_fd, tex_absname = tempfile.mkstemp(dir=tmpout, suffix='.startQuiz')
            os.write(tex_fd, 'Starting selection of quiz question\n')
        
        hasq = self.openQuiz()
        msg = []
        msg.append(True)
        # taken care of that - set no answer and written to log
        # close that question
        if (hasq):
            msg.append('question replaced')
        else:
            msg.append('A question has been saved to quiz')
        msg.append(self.Creator())
        #parent = aq_parent(self)
        if (DEBUG):
            usable_question = lec.getQuizQuestion(tex_fd, True)
        else:
            usable_question = lec.getQuizQuestion()
        if (usable_question[0] == -1):
            '''no questions available'''
            msg[0] = False
            msg[1] = 'Sorry but no questions available in Lecture ' + usable_question[1] + '. Please contact your instructor if you believe you have found an error in the system, including the given error message'
            return msg
        elif(usable_question[0] == False):
            '''False could not create result for student'''
            msg[0] = False
            msg[1] = 'Fatal error could not start quiz in Lecture ' + usable_question[1] + '. Please contact your instructor if you believe you have found an error in the system, including the error message'
            return msg
        elif (usable_question[0] == -2):
            '''no answers set for the question'''
            msg[0] = False
            msg[1] = 'Sorry but no answers have been set for the selected question: ' + usable_question[2] + ' located in ' + usable_question[3] + '. Please try again or contact your instructor if you believe you have found and error in the system, including this message'
            return msg
        elif (usable_question[0] == -3):
            '''no answer set as correct in question'''
            msg[0] = False
            msg[1] = 'Sorry but no correct answer has been set to the selected question: ' + usable_question[2] + ' located in ' + usable_question[3] + '. Please try again or contact your instructor if you believe you have found an error in the system, including this error message'
            return msg
                
        else:
            '''have a valid question'''
            origquest = usable_question[0]
            if (DEBUG):
                os.write(tex_fd, '###########################\n')
                os.write(tex_fd, 'question used in quiz\n')
                os.write(tex_fd, str(origquest.getId()) + '\n')
                os.write(tex_fd, str(origquest.getRawQuestion()) + '\n')
        
            # set as invisble question with questionresult
            newq = self.createQuestion()
            qr = newq.createQuestionResult()
            # this info is repeated, but leave for now
            # FIXME
            if (len(self.getStudentRandId()) > 0):
                qr.setStudentId(self.getStudentRandId())
            else:
                # find from other location
                quiz = aq_parent(self)
                lec = aq_parent(quiz)
                tut = aq_parent(lec)
                dep = aq_parent(tut)
                mysite = aq_parent(dep)
                studentlistobj = mysite.getFolderContents(contentFilter={"portal_type": "StudentList"})
                if (len(studentlistobj) > 0):
                    studentlist = studentlistobj[0].getObject()
                    studentlist.addStudent(self.Creator())
                    randid = studentlist.getStudentIdNumber(self.Creator())
                    self.setStudentRandId(randid)
                    qr.setStudentId(randid)
            qr.setLecPath(lec.getPhysicalPath())
            # have created a quiz question with corresponding questuionresults
            # now set information from original question to quiz question
            # I probably don't need all the info but lets start by that
            questiontext = origquest.getRawQuestion()
            texttype = origquest.question.getContentType()
            mutated = origquest.getAnswerList()
            answertype = origquest.getAnswerFormat()
            newq.setQuestionText(questiontext, mimetype=texttype)
            newq.setAnswerList(mutated)
            newq.setAnswerFormat(answertype)
        
            # if its r or r/latex questions then need to be updated
            if (texttype == 'text/r' or texttype == 'text/r-latex'):
                newq.initializeObject()
               
            else:    
                newq.ans = origquest.ans
                newq.NOTAinQuestion = origquest.NOTAinQuestion
                newq.inlineanswer = origquest.inlineanswer
                newq.transformrquestion = origquest.transformrquestion
                newq.setQuizQuestion(origquest.getRawQuizQuestion(), mimetype=origquest.quizQuestion.getContentType())
                # add the image if any
                # ATT
                # asuming r-images do not contain image
                # would be generated within the r code itself?
                # HMMMMM
                img = origquest.getQuestionImage()
                newq.setQuestionImage(img)
            # add image url if any
            imgurl = origquest.getImageUrl()
            if (len(imgurl) > 0):
                newq.setImageUrl(imgurl)
            newq.numcorrect = origquest.numcorrect
            newq.numaskedfor = origquest.numaskedfor
            # need additionally to set:
            # quisQuestion
            
            
            newq.setQuizQuestionExplanation(origquest.getRawQuizQuestionExplanation(), mimetype='text/html')
           
           
            newq.setOriginalQuestion(origquest)
            
            # instead of using original question
            # use the invisible question
            suggestedanswers = newq.makeNewTest()
            grid = newq.getWrappedField('AnswerList')
            correctAnswerIds = []
            rowcorrect = grid.search(newq, correct='1')
            for row in rowcorrect:
                correctAnswerIds.append(row['answerid'])
            
            qr.setNewQuestion(suggestedanswers, correctAnswerIds, origquest.getPhysicalPath(), origquest.UID())
            
            
            if (len(suggestedanswers) > 0):
                '''set the first element in value as selected
                answer, anything will do'''
                qr.setSelectedAnswer(suggestedanswers[0])
                 
            else:
                '''what to do bad error'''
                msg[0] == False
                msg[1] = 'Fatal error'
                return msg
            qr.reindexObject()
            newq.reindexObject()
            self.reindexObject()
            if (DEBUG):
                os.write(tex_fd, str(newq.getId()) + '\n')
                os.write(tex_fd, str(newq.getRawQuestion()) + '\n')
                os.close(tex_fd)
            
            return msg
        
    def setTotalscore(self, val):
        self.setTotscore(val)
        #self.totalscore = val
    def setLastEightList(self, val):
        tmp = []
        for s in val:
            tmp.append(int(s))
        self.scoresofar = tmp
        tmpstr0 = str(val)
        tmpstr1 = tmpstr0.replace(',', '')
        self.setLasteightgrades(tmpstr1)
    def setLastEight(self, val):
        # value is a string
       
        tmpstr0 = val.replace(',', '')
        tmpstr1 = tmpstr0.replace('[', '')
        tmpstr2 = tmpstr1.replace(']','')
        scorelist = tmpstr2.split()
       
        tmp = []
        for s in scorelist:
            if (len(s) > 0):
                tmp.append(int(s))
        self.scoresofar = tmp
        self.setLasteightgrades(tmpstr0)
    def setScoresofar(self, val):
        self.scoresofar = val
    def getCreator(self):
        return self.Creator()
    def getSelectedAnswerToQuestion(self, question):
        #qr =  self.getStudentQuestionResult() 
        qr = self.getQuestionResultForQuestion(question)
        value = qr.getSelectedAnswer()
        #value = qr.getCandidateAnswer()
       
        answerdisplay = question.getAnswerDisplay()
        #index = int(value[0])
       
        return answerdisplay.getValue(value)
    def getSelectedItem(self):
        question = self.getCurrentQuestion()
        qr = self.getQuestionResultForQuestion(question)
        return qr.getSelectedAnswer()
    def questionIsInline(self):
        question = self.getCurrentQuestion()
        if (question > 0):
            return question.inlineAnswer()
        else:
            return False
    def getCandidateAnswerInTest(self):
        
        question = self.getCurrentQuestion()
        if (question):
            qr = self.getQuestionResultForQuestion(question)
            return (qr.getCandidateAnswer())
    security.declareProtected(PERMISSION_STUDENT, 'getOriginalQuestion')
    def getOriginalQuestion(self, quest):
        return quest.getOriginalQuestion()
        
    security.declareProtected(PERMISSION_STUDENT, 'getChosenQuestion')
    def getChosenQuestion(self):
        # always assume we are dealing with the last question
        question = self.getCurrentQuestion()
        if (question):
            return question
        else:
            return False
       
       
    def computeGrade(self):
        return float(self.getTotscore())
    def getSuggestedAnswerInTest(self):
        qr = self.getQuestionResultForQuestion(question)
        return (qr.getSuggestedAnswer())
    def setSelectedAnswerInTest(self, value):
        question = self.getCurrentQuestion()
        if (question):
            qr = self.getQuestionResultForQuestion(question)
            qr.setSelectedAnswer(value)
            qr.reindexObject()
    def unsetCandidateAnswerToQuestion(self):
        #qr =  self.getStudentQuestionResult()
        #qresults = self.getFolderContents(contentFilter={"portal_type": "QuestionResult"})
        #qr = qresults[0].getObject()
        question = self.getCurrentQuestion()
        if (question):
            qr = self.getQuestionResultForQuestion(question)
            qr.unsetCandidateAnswer()
            qr.reindexObject()
    def setCandidateAnswerToQuestion(self, value):
        question = self.getCurrentQuestion()
        if (question):
            qr = self.getQuestionResultForQuestion(question)               
            qr.gotAnswer()
            origquestion = question.getOriginalQuestion()
            qr.setCandidateAnswer([value], origquestion)
            qr.writetolog()
            correctans = qr.getCorrectAnswer()
            l = qr.getSuggestedans().split('\t')
            v = l[int(value)-1]
            if v in correctans:
                # this can lead ot database conflict error   
                origquestion.numcorrect = origquestion.numcorrect + 1
                correct = 1
            else:
                correct = 0
                #qr.gotAnswer()
            self.setScore(correct)
            qr.reindexObject()
    def computeAverageGrade(self):
        '''return average grade of student'''
        # compute the average grade of the student for this lecture
        # Average grade is at the moment computed according to points given
        # for the last eight answers:
        # Correct answer gives +1 points
        # Wrong answer gives -0.5 points
        # no answers given or all answers incorrect, grade starts at -0.5
        # Highest average grade is +1, all answers correct       
        # r = number correct answers of last m= 8 answers
        # average grade = ((-0.5)*(m-r)+r)/m
        # later more complex methods of computing grades need to be specified.
    
        numcorrect = 0
        for i in self.scoresofar:
            if float(i) > 0.0:
                numcorrect = numcorrect + 1
        # average grade is computed from the last 8 answers
        m = 8.0
        return ((-0.5)*(m-float(numcorrect))+float(numcorrect))/m
    def computeGrade1(self, remove):
        #tmpout = tempfile.mkdtemp()
        #tex_fd, tex_absname = tempfile.mkstemp(dir=tmpout, suffix='.computegradae1')
        #os.write(tex_fd, 'computegrade1\n')

        #tmp1 = self.getTotscore()
        #tmp = float(tmp1)
        #if (remove == 0):
        #    tmp = tmp + 0.5
        #else:
        #    tmp = tmp - 1.0
        #lastscore = self.scoresofar[0]
        #if (lastscore == 0):
        #    tmp = tmp - 0.5
        #else:
        #    tmp = tmp + 1.0
        
        total = 0.0
        for i in self.scoresofar:
            if float(i) == 0.0:
                total = total - 0.5
            else:
                total = total + 1
        self.setTotscore(total)
        
        #questions = self.getStudentQuestions()
        #portal_catalog = getToolByName(self, 'portal_catalog')
        ##questions = self.portal_catalog.searchResults(
        ##    portal_type = "InvisibleQuestion",
        ##    sort_on="Date",
        ##    path='/'.join(self.getPhysicalPath()),
        ##    )
        ##total = 0.0
        ##self.scoresofar = []
        ##for q in questions:
         ##   qr = self.getQuestionResultForQuestion(q.getObject())
         ##   if (qr.candidateAnswer == qr.correct):
          ##      total = total + 1.0
           ##     self.scoresofar.insert(0,1)
          ##  else:
          ##      total = total - 0.5
          ##      self.scoresofar.insert(0,0)
        ##self.setLasteightgrades(str(self.scoresofar))    
        ##self.setTotscore(total)
        self.reindexObject()
        #os.write(tex_fd, str(self.scoresofar) + '\n')
        #os.write(tex_fd, str(total) + '\n')
        #os.write(tex_fd, str(self.getPhysicalPath()) + '\n')
        #bla = '/'.join(self.getPhysicalPath())
        #os.write(tex_fd, str(bla) + '\n')
        #os.write(tex_fd, str(len(questions)) + '\n')
        
        return self.getLasteightgrades()    
    def getLastPoint(self):
        if (len(self.scoresofar) > 0):
            return self.scoresofar[0]
        else:
            return None
    security.declarePublic('setScore')
    def setScore(self, s):
        numinscore = 8
        if (len(self.scoresofar) == numinscore):
            tmp = self.scoresofar[numinscore-1]
            self.scoresofar = self.scoresofar[:numinscore-1]
            #self.scoresofar = self.scoresofar + [s]
            self.scoresofar.insert(0, s)
            self.setLasteightgrades(str(self.scoresofar))
            self.computeGrade1(tmp)
            #self.setLasteightgrades(str(self.scoresofar))
        else:
            tmp = float(self.getTotscore())
            if (s is 0):
                tmp = tmp - 0.5
            else:
                tmp = tmp + 1.0
            self.setTotscore(tmp)
            #tmp = 0           
            #self.computeGrade1(tmp)
            #self.scoresofar = self.scoresofar + [s]
            self.scoresofar.insert(0, s)
            self.setLasteightgrades(str(self.scoresofar))
            #self.computeGrade1(tmp)
        temp = self.getTotalattempts()
        temp = temp + 1
        self.setTotalattempts(temp)
        if (s is not 0):
            temp = self.getCorrectattempts()
            temp = temp + 1
            self.setCorrectattempts(temp)
        self.reindexObject()
    def closedQuiz(self):
        msg = []                                  
        question = self.getCurrentQuestion()
        if (question):
            qr = self.getQuestionResultForQuestion(question)
            if (not qr.hasSubmittedQuestion()):
                '''this could only happen if double click on button'''
                # what to do, student want to submit the same answer twice
                # no don't allow that
                msg.append(True)
                msg.append('Already answered')
                return msg
            else:
                msg.append(False)
                msg.append('Your answer has been saved.') 
                return msg
    def openQuiz(self):
        #qr = self.getStudentQuestionResult()
        # get the last question
        question = self.getCurrentQuestion()
        if (question):
            qr = self.getQuestionResultForQuestion(question)
            if (qr.hasSubmittedQuestion()):       
                #Set this question as false
                # For the moment the result is not restored
                # should print out results for wrong question
                 
                #self.setCandidateAnswerToQuestion('no answer')
                value = 'no answer'
                qr.setCandidateAnswer([value], question.getOriginalQuestion())
                correctans = qr.getCorrectAnswer()
                if value in correctans:
                    origquestion = question.getOriginalQuestion()
                    # this can lead to database conflict error
                    # WHAT TO DO????
                    #qobj = question[0].getObject()
                    origquestion.numcorrect = origquestion.numcorrect + 1
                    correct = 1
                else:
                    correct = 0
                qr.gotAnswer()
                self.setScore(correct)
                qr.reindexObject()
            #quizquestionstring = qr.getQuizInfo()
                self.writetolog(qr)       
                return True
            else:
                return False
        else:
            '''no question set yet'''
            return False
    security.declareProtected(PERMISSION_STUDENT, 'writetolog')
    def writetolog(self, qr):
        # FIXME !!!!
        # add code to check if dir exists and then create..
        logdir = productdir + '/log'
        if (not (os.path.exists(logdir))):
            os.mkdir(logdir)
        f = open(logdir+'/questionandanswer.txt','a')
        #qr = self.getStudentQuestionResult()
        #qresults = self.getFolderContents(contentFilter={"portal_type": "QuestionResult"})
        #qr = qresults[0].getObject()
        text = qr.getQuizInfo()
        text = text + str(datetime.now()) + "\n"
        f.write(text)
        f.close()
        #os.system('echo ' + text + ' >> /tmp/twquiz/questionandanswer.txt')
    
    def setNewQuestionInTest(self, suggestedanswer, correctids, questpath, qid):
        
        #notify(NewQuizQuestionEvent(self, suggestedanswer, correctids, questpath, qid))
        question = self.getCurrentQuestion()
        if (question):
            qr = self.getQuestionResultForQuestion(question)
        #qresults = self.getFolderContents(contentFilter={"portal_type": "QuestionResult"})
        #qr = qresults[0].getObject()
        #self.manage_delObjects(qresults)
        ##randid = qr.getStudid()
        ##lecpath = qr.getLecturepath()
        ##ids = self.objectIds() # Plone 3 or older
        #ids = folder.keys()      # Plone 4 or newer
        
        #ids = []
        ##if len(ids) > 0:
            #manage_delObject will mutate the list
            # so we cannot give it tuple returned by objectIds()
         ##   ids = list(ids)
         ##   self.manage_delObjects(ids)
        ##qr = self.createQuestionResult()
        ##qr.setStudentId(self.Creator())
        
        #parent = aq_parent(self)
        #lecpath = parent.getPhyisicalPath()
        ##qr.setLecturepath(lecpath)
        ##self.setStudentQuestionResult(qr)
        
        ##transaction.begin()

            qr.setNewQuestion(suggestedanswer, correctids, questpath, qid)
        ##qr._p_changed = True
        ##self._p_changed = True
        ##transaction.commit()
        #portal_catalog = getToolByName(self, 'portal_catalog')
        #students = portal_catalog.unrestrictedSearchResults({'portal_type' : 'StudentList'})
        #if (len(students) > 0):
        #    numlists = str(len(students))
            
        #    objid = students[0].getObject()
            #objid.addStudent(candidateId)
        #    randid = objid.getStudentIdNumber(self.Creator())
            
        ##qr.setStudentId(randid)
            qr.reindexObject()
    # This method is only called once after object creation.
    #security.declarePrivate('at_post_create_script')
    #def at_post_create_script(self):
    #    self.tryWorkflowAction("publish", ignoreErrors=True)
        
    def at_post_edit_script(self):
        '''function called after edit in the main edit view of the tutorial.'''
    #    self.changed = True
   
        #qresults = self.getFolderContents(contentFilter={"portal_type": "QuestionResult"})
        #if (len(qresults) > 0):
        #    qr = qresults[0].getObject()
        #    self.setStudentQuestionResult(qr) 
    #security.declarePrivate('tryWorkflowAction')
    #def tryWorkflowAction(self, action, ignoreErrors=False, comment=None):
    #    wtool = self.portal_workflow
    #    wf = wtool.getWorkflowsFor(self)[0]
    #    if wf.isActionSupported(self, action):
    #        if comment is None:
    #            #userId = getSecurityManager().getUser().getId()
    #            comment = 'State changed' 
    #        wtool.doActionFor(self, action, comment=comment)
    #    elif not ignoreErrors:
    #        raise TypeError('Unsupported workflow action %s for object %s.'
    #                        % (repr(action), repr(self)))
    #def getError(self):
    #    self.portal_factory.doCr()
    #def createQuestionResult(self):
    #    """Create a new questionresult object for student and initialize it."""
    #    typeName = 'QuestionResult'
    #    id=self.generateUniqueId(typeName)
    #    if self.portal_factory.getFactoryTypes().has_key(typeName):
    #        o = self.restrictedTraverse('portal_factory/' + typeName + '/' + id)
    #    else:
    #        newId = self.invokeFactory(id=id, type_name=typeName)
    #        if newId is None or newId == '':
    #            newId = id
    #        o=getattr(self, newId, None)
    
    #    if o is None:
    #        raise Exception
    #    o = self.portal_factory.doCreate(o, id)
    #    o.setTitle('Question result')
    #    o.reindexObject()
    #    return o
    def removeQuestion(self):
        portal_catalog = getToolByName(self, 'portal_catalog')
        questions = self.portal_catalog.searchResults(
            portal_type = "InvisibleQuestion",
            sort_on="Date",
            path='/'.join(self.getPhysicalPath()),
            )

        
        if (len(questions) > 7):
            '''should removes the oldest one'''
            self.manage_delObjects([questions[0].getId])

    def createQuestion(self):
        """Create a new questionresult object for student and initialize it."""
        # if neede delete a question
        # only keep 8 questons going
        typeName = 'InvisibleQuestion'
        self.removeQuestion()
        id=self.generateUniqueId(typeName)
        if self.portal_factory.getFactoryTypes().has_key(typeName):
            o = self.restrictedTraverse('portal_factory/' + typeName + '/' + id)
        else:
            newId = self.invokeFactory(id=id, type_name=typeName)
            if newId is None or newId == '':
                newId = id
            o=getattr(self, newId, None)
    
        if o is None:
            raise Exception
        o = self.portal_factory.doCreate(o, id)
        #o.setTitle('Question result')
        
        invquest = self.getStudentQuestions()
        invquest.append(o)
        self.setStudentQuestions(invquest)
        self.setCurrentQuestion(o)
        
        return o   
Ejemplo n.º 3
0
class ECQPointsQuestion(ECQBaseQuestion):
    """ A question that can in some way be graded. The candidate's points 
        or the rating he/she gave, can be retieved via the 
        'getCandidatePoints()' method.
    """

    schema = ECQBaseQuestion.schema.copy() + Schema(
        (
            IntegerField(
                'points',  # See 'description' property of the widget.
                accessor='getPointsPrivate',
                required=True,
                validators=(
                    'isPositiveInt',
                    'clearPointsCache',
                ),
                read_permission=PERMISSION_INTERROGATOR,
                widget=IntegerWidget(
                    label='Points',
                    label_msgid='points_label',
                    description=
                    'The number of points assigned to this question.',
                    description_msgid='points_tool_tip',
                    i18n_domain=I18N_DOMAIN),
                #read_permission=PERMISSION_STUDENT,
                #languageIndependent=True,
            ),
            BooleanField(
                'tutorGraded',
                accessor='isTutorGraded',
                default=False,
                #searchable=False,
                widget=BooleanWidget(
                    label='Tutor-Graded',
                    label_msgid='tutor_graded_label',
                    description=
                    'If answers to this question are graded manually, mark this checkbox.',
                    description_msgid='tutor_graded_tool_tip',
                    i18n_domain=I18N_DOMAIN),
                read_permission=PERMISSION_STUDENT,
                validators=('clearPointsCache', ),
                languageIndependent=True,
            ),
        ), )

    security = ClassSecurityInfo()

    security.declareProtected(PERMISSION_STUDENT, 'getPoints')

    def getPoints(self, *args, **kwargs):
        return self.getPointsPrivate(*args, **kwargs)

    security.declarePrivate('computeCandidatePoints')

    def computeCandidatePoints(self, result):
        """ Return how many points the candidate got for this question.

            @param result The result object of the candidate whose
            points you want to know.

            If a custom evaluation script has been uploaded it will be
            invoked. Otherwise a default method will be used.
        """
        parent = getParent(self)
        customScript = parent.getEvaluationScript(self.portal_type)
        answer = self.getCandidateAnswer(result)
        if not customScript:  # default
            return None
        else:  # use custom script
            return evalFunString(customScript, CUSTOM_EVALUATION_FUNCTION_NAME,
                                 [self, result, answer])

    def getCandidatePoints(self, result):
        if self.isTutorGraded():
            return result.getTutorPoints(self)
        else:
            # Check if we have a tutor-given or a cached value
            retVal = result.getCachedQuestionPoints(self)
            if retVal is None:
                retVal = self.computeCandidatePoints(result)
                result.setCachedQuestionPoints(self, retVal)
            return retVal
Ejemplo n.º 4
0
         label=_(u"Vocabulary"),
         description=_(u'Vocabulary to use to render widget items'),
     )),
 StringField('catalog',
             schemata="default",
             vocabulary_factory='eea.faceted.vocabularies.UseCatalog',
             widget=SelectionWidget(
                 format='select',
                 label=_(u'Catalog'),
                 description=_(u"Get unique values from catalog "
                               u"as an alternative for vocabulary"),
             )),
 IntegerField('maxitems',
              schemata="display",
              default=0,
              widget=IntegerWidget(
                  label=_(u"Maximum items"),
                  description=_(u'Number of items visible in widget'),
              )),
 BooleanField('sortreversed',
              schemata="display",
              widget=BooleanWidget(
                  label=_(u"Reverse options"),
                  description=_(u"Sort options reversed"),
              )),
 LinesField('default',
            schemata="default",
            widget=LinesWidget(
                label=_(u'Default value'),
                description=_(u'Default items (one per line)'),
                i18n_domain="eea")),
Ejemplo n.º 5
0
from eea.facetednavigation import EEAMessageFactory as _
from Products.Archetypes.public import Schema
from Products.Archetypes.public import IntegerField
from Products.Archetypes.public import IntegerWidget

from eea.facetednavigation.widgets import ViewPageTemplateFile
from eea.facetednavigation.widgets.widget import Widget as AbstractWidget
from eea.facetednavigation import EEAMessageFactory as _
import logging

logger = logging.getLogger('collective.bibliocustomviews.widgets.resultsrange')

EditSchema = Schema((
    IntegerField('step',
                 schemata="default",
                 default=500,
                 widget=IntegerWidget(label=_(u'Step'),
                                      description=_(u'Results range step'),
                                      i18n_domain="eea")),
    IntegerField('end',
                 schemata="default",
                 default=2000,
                 widget=IntegerWidget(label=_(u'End'),
                                      description=_(u'Last range start value'),
                                      i18n_domain="eea")),
    IntegerField('default',
                 schemata="default",
                 default=0,
                 widget=IntegerWidget(
                     label=_(u'Default value'),
                     description=_(u'Default range start value'),
                     i18n_domain="eea")),
Ejemplo n.º 6
0
         description=_(u'Vocabulary to use to render widget items'),
         i18n_domain="eea")),
 StringField('catalog',
             schemata="default",
             vocabulary_factory='eea.faceted.vocabularies.UseCatalog',
             widget=SelectionWidget(
                 format='select',
                 label=_(u'Catalog'),
                 description=_(
                     u'Get unique values from catalog as an alternative '
                     u'for vocabulary'),
                 i18n_domain="eea")),
 IntegerField('maxitems',
              schemata="display",
              default=50,
              widget=IntegerWidget(
                  label=_(u'Maximum items'),
                  description=_(u'Number of items visible in widget'),
                  i18n_domain="eea")),
 IntegerField('maxchars',
              schemata="display",
              default=0,
              widget=IntegerWidget(
                  label=_(u'Maximum characters'),
                  description=_(
                      u'Cut long phrases to provided number of characters'),
                  i18n_domain="eea")),
 StringField('colormin',
             schemata="display",
             default="A1BE7E",
             widget=StringWidget(
Ejemplo n.º 7
0
class ECQResult(ATCTContent, HistoryAwareMixin):
    """A quiz result."""
    """ This class contains all the candidate-specific information for
        an ECQuiz.  They are:

        questionResults:

          A dictionary that contains all the information concerning a
          single question, e. g. the suggested answer, the answer
          given by the candidate, the grade.

          The keys are the UIDs of the question.
                                   
        questionContainerIds:

          A list of the IDs of the 'ECQAbstractGroup'
          instances that the candidate saw.

        questionUIDs:

          A list of IDs of the questions that the candidate saw in
          their quiz.  Unfortunately 'questionResults.keys()' cannot
          be used since it does not preserve the order of the UIDs.
                                   
        timeStart:

          The time when the candidate first saw the quiz.
        
        timeFinish:

          The time when the candidate submitted their quiz.
    """

    schema = ATContentTypeSchema.copy() + Schema((
        ObjectField(
            'questionResults',
            read_permission=PERMISSION_RESULT_READ,
            default={},
        ),
        ObjectField(
            'possiblePointsCache',
            read_permission=PERMISSION_RESULT_READ,
            default={},
        ),
        ObjectField(
            'candidatePointsCache',
            read_permission=PERMISSION_RESULT_READ,
            default={},
        ),
        ObjectField(
            'questionContainerIds',
            read_permission=PERMISSION_RESULT_READ,
            default=[],
        ),
        ObjectField(
            'questionUIDs',
            read_permission=PERMISSION_RESULT_READ,
            default=[],
        ),
        DateTimeField(
            'timeStart',
            read_permission=PERMISSION_RESULT_READ,
        ),
        DateTimeField(
            'timeFinish',
            read_permission=PERMISSION_RESULT_READ,
            default=None,
        ),
        IntegerField(
            'currentPageNum',
            read_permission=PERMISSION_RESULT_READ,
            write_permission=PERMISSION_RESULT_WRITE,
            default=0,
        ),
    ), )

    # Don't list this type in the portal navigation.
    navigation_exclude = True

    security = ClassSecurityInfo()

    security.declarePrivate('getQR')

    def getQR(self, caller, question, dontThrow=False):
        questionUID = question.UID()
        qrs = self.getQuestionResults()
        retVal = qrs.get(questionUID, None)
        if (retVal is not None) or dontThrow:
            return retVal
        else:
            txt = "%s() called for questionUID not in self.questionUIDs\n" \
                  "questionUID: %s\n" \
                  "self.questionUIDs: %s" \
                  % (caller, repr(questionUID), repr(self.getQuestionUIDs()))
            log(txt)
            raise Exception(txt)

    security.declarePrivate('storeQR')

    def storeQR(self, question, result):
        qrs = self.getQuestionResults()
        qrs[question.UID()] = result
        # Instead of saving "qrs" directly, save a copy of it,
        # "dict(qrs)".  If we don't do that, there is a chance that
        # Zope will return an old, cached value the next time
        # "self.getQuestionResults()" is called because it *thinks*
        # the cached dictionary is the same as the stored one because
        # the memory location didn't change.
        self.setQuestionResults(dict(qrs))

    security.declarePrivate('setSuggestedAnswer')

    def setSuggestedAnswer(self, question, suggestedAnswer):
        """ Saves the suggested answer values to a question the
            candidate was asked.
            
            @param suggestedAnswer The value or list of values
            of the answer suggested to the candidate.
                                        
            @param question The question that the answer belongs to.
                              
            @param questionContainerId The ID of the question
            container that contains the question.
        """
        # The list 'questionContainerIds' is neccessary because
        # 'self.questionResults.keys()' does not return the
        # questionUIDs in the order they were added.
        questionContainerId = getParent(question).getId()
        questionUID = question.UID()
        questionContainerIds = self.getQuestionContainerIds()
        if questionContainerId not in questionContainerIds:
            self.setQuestionContainerIds(questionContainerIds +
                                         [questionContainerId])
        questionUIDs = self.getQuestionUIDs()
        if questionUID not in questionUIDs:
            self.setQuestionUIDs(questionUIDs + [questionUID])
        qr = QuestionResult(suggestedAnswer)
        self.storeQR(question, qr)

    security.declareProtected(PERMISSION_RESULT_READ, 'getSuggestedAnswer')

    def getSuggestedAnswer(self, question):
        """ Returns the suggested answer values for a question the
            candidate was asked.  With the standard question and
            answer types this will be a list of IDs of answer objects.
        """
        qr = self.getQR("getAnswer", question)
        return qr.getSuggestedAnswer()

    security.declareProtected(PERMISSION_RESULT_READ, 'getCandidateAnswer')

    def getCandidateAnswer(self, question):
        """ Returns the candidate's answer to the question.  If this
        question was not part of their quiz, an exception will be
        raised.
        """
        qr = self.getQR("getCandidateAnswer", question)
        return qr.getCandidateAnswer()

    security.declareProtected(PERMISSION_RESULT_WRITE, 'setCandidateAnswer')

    def setCandidateAnswer(self, question, answerValue):
        """ Saves the candidate's answer to a question.
            
            @param answerValue The value or list of values of the
            answer(s) the candidate gave. With the standard question
            and answer types this will be the ID (list of IDs) of the
            answer(s) the candidate selected.
        """
        qr = self.getQR("setCandidateAnswer", question)
        qr.setCandidateAnswer(answerValue)
        self.storeQR(question, qr)

    security.declareProtected(PERMISSION_RESULT_WRITE, 'unsetCandidateAnswer')

    def unsetCandidateAnswer(self, question):
        """ Removes the candidate's answer to a question.
            
            @param answerValue The value or list of values of the
            belongs to.
        """
        qr = self.getQR("unsetCandidateAnswer", question)
        qr.unsetCandidateAnswer()
        self.storeQR(question, qr)

    ## Points caching: start

    # Points for an individual question
    security.declareProtected(PERMISSION_RESULT_READ,
                              'getCachedQuestionPoints')

    def getCachedQuestionPoints(self, question):
        """
        """
        qr = self.getQR("getCachedQuestionPoints", question)
        return qr.cachedPoints

    security.declareProtected(PERMISSION_RESULT_WRITE,
                              'setCachedQuestionPoints')

    def setCachedQuestionPoints(self, question, value):
        """
        """
        qr = self.getQR("setCachedQuestionPoints", question)
        qr.cachedPoints = value
        self.storeQR(question, qr)

    # Tutor-assigned points for an individual question
    security.declareProtected(PERMISSION_GRADE, 'setTutorPoints')

    def getTutorPoints(self, question):
        """
        """
        qr = self.getQR("getTutorPoints", question)
        return qr.tutorPoints

    security.declareProtected(PERMISSION_GRADE, 'setTutorPoints')

    def setTutorPoints(self, question, value):
        """
        """
        qr = self.getQR("setTutorPoints", question)
        qr.tutorPoints = value
        self.storeQR(question, qr)

        # clear related cache info
        test = getParent(question)
        if test.portal_type == ECQGroup.portal_type:
            questionGroup = test
            test = getParent(questionGroup)
        else:
            questionGroup = None

        self.setCachedCandidatePoints(test, None)
        #log("%s: CachedCandidatePoints: %s" % (str(self), str(test)))
        if questionGroup:
            self.setCachedCandidatePoints(questionGroup, None)
            #log("%s: CachedCandidatePoints: %s" % (str(self),
            #                                         str(questionGroup)))
        #log("")

    security.declareProtected(PERMISSION_GRADE, 'unsetTutorPoints')

    def unsetTutorPoints(self, question):
        """
        """
        self.setTutorPoints(question, None)  # this also clears any
        # related caches
        # Retract to "pending" because the result can't be "graded" if
        # some grades are missing
        userId = self.portal_membership.getAuthenticatedMember().getId()
        comment = "Retracted by %s: tutor grades were deleted" % userId
        self.tryWorkflowAction('retract_pending',
                               ignoreErrors=True,
                               comment=comment)

    # Possible points for a question group
    security.declareProtected(PERMISSION_RESULT_READ,
                              'getCachedPossiblePoints')

    def getCachedPossiblePoints(self, questionGroup):
        """
        """
        cache = self.getPossiblePointsCache()
        return cache.get(questionGroup.UID(), None)

    security.declareProtected(PERMISSION_RESULT_WRITE,
                              'setCachedPossiblePoints')

    def setCachedPossiblePoints(self, questionGroup, value):
        """
        """
        cache = self.getPossiblePointsCache()
        cache[questionGroup.UID()] = value
        self.setPossiblePointsCache(dict(cache))

    # Achieved points for a question group
    security.declareProtected(PERMISSION_RESULT_READ,
                              'getCachedCandidatePoints')

    def getCachedCandidatePoints(self, questionGroup):
        """
        """
        cache = self.getCandidatePointsCache()
        return cache.get(questionGroup.UID(), None)

    security.declareProtected(PERMISSION_RESULT_WRITE,
                              'setCachedCandidatePoints')

    def setCachedCandidatePoints(self, questionGroup, value):
        """
        """
        cache = self.getCandidatePointsCache()
        cache[questionGroup.UID()] = value
        self.setCandidatePointsCache(dict(cache))

    # Delete all cached points
    security.declarePrivate('unsetAllCachedPoints')

    def unsetAllCachedPoints(self):
        # Delete cached points for the questions
        qrs = self.getQuestionResults()
        for qr in qrs.values():
            qr.cachedPoints = None
        self.setQuestionResults(dict(qrs))

        # Delete the caches for possible and candidate points in a
        # question group
        self.setPossiblePointsCache({})
        self.setCandidatePointsCache({})
        #log("%s: deleted all cached points" % (str(self)))

    # Clear all cached points related to the question [question],
    # i. e. clear cache for possible and achieved (candidate) points
    # for the question and the question group and the test that
    # contain this question
    security.declarePrivate('unsetCachedQuestionPoints')

    def unsetCachedQuestionPoints(self, question):
        """
        """
        if self.getQR("", question, dontThrow=True) is not None:
            test = getParent(question)
            if test.portal_type == ECQGroup.portal_type:
                questionGroup = test
                test = getParent(questionGroup)
            else:
                questionGroup = None

            self.setCachedQuestionPoints(question, None)
            #log("%s: CachedQuestionPoints: %s" % (str(self), str(question)))

            self.setCachedPossiblePoints(test, None)
            #log("%s: CachedPossiblePoints: %s" % (str(self), str(test)))
            self.setCachedCandidatePoints(test, None)
            #log("%s: CachedCandidatePoints: %s" % (str(self), str(test)))
            if questionGroup:
                self.setCachedPossiblePoints(questionGroup, None)
                #log("%s: CachedPossiblePoints: %s" % (str(self),
                #                                        str(questionGroup)))
                self.setCachedCandidatePoints(questionGroup, None)
                #log("%s: CachedCandidatePoints: %s" % (str(self),
                #                                         str(questionGroup)))
            #log("")

    ## Points caching: end

    security.declareProtected(PERMISSION_RESULT_READ, 'haveCandidateAnswer')

    def haveCandidateAnswer(self, question):
        qr = self.getQR("haveCandidateAnswer", question)
        return qr.haveCandidateAnswer()

    security.declareProtected(PERMISSION_RESULT_WRITE, 'startWatch')

    def startWatch(self, question):
        qr = self.getQR("startWatch", question)
        if not qr.isWatchRunning():
            qr.addTimeStart(datetime.now())
            #log("startWatch: %s" % str(question))
            self.storeQR(question, qr)
            makeTransactionUnundoable()

    security.declareProtected(PERMISSION_RESULT_WRITE, 'stopWatch')

    def stopWatch(self, question):
        qr = self.getQR("stopWatch", question)
        if qr.isWatchRunning():
            #log("stopWatch: %s" % str(question))
            qr.addTimeFinish(datetime.now())
            self.storeQR(question, qr)

    security.declareProtected(PERMISSION_RESULT_READ, 'isWatchRunning')

    def isWatchRunning(self, question):
        qr = self.getQR("isWatchRunning", question)
        return qr.isWatchRunning()

    security.declareProtected(PERMISSION_RESULT_READ, 'getTimeSpent')

    def getTimeSpent(self, question):
        """@return  A Python timedelta object."""
        qr = self.getQR("getTimeSpent", question)
        return qr.getTimeSpent()

    security.declareProtected(PERMISSION_RESULT_READ, 'getSetCount')

    def getSetCount(self, question):
        """@return The number of times the candidate changed his
        answer."""
        qr = self.getQR("getTimeSpent", question)
        return qr.getSetCount()

    security.declarePublic('getWorkflowState')

    def getWorkflowState(self):
        """Determine the Plone workflow state."""
        wtool = self.portal_workflow
        wf = wtool.getWorkflowsFor(self)[0]
        return wf.getInfoFor(self, 'review_state', '')

    security.declarePublic('hasState')

    def hasState(self, state):
        return self.getWorkflowState() == state

    security.declarePrivate('tryWorkflowAction')

    def tryWorkflowAction(self, action, ignoreErrors=False, comment=None):
        wtool = self.portal_workflow
        wf = wtool.getWorkflowsFor(self)[0]
        if wf.isActionSupported(self, action):
            if comment is None:
                userId = getSecurityManager().getUser().getId()
                comment = 'State changed by ' + userId
            wtool.doActionFor(self, action, comment=comment)
        elif not ignoreErrors:
            raise TypeError('Unsupported workflow action %s for object %s.' %
                            (repr(action), repr(self)))

    security.declarePublic('isGradable')

    def isGradable(self):
        mcTest = getParent(self)
        return mcTest.isTutorGraded(self) and \
               (self.getWorkflowState() in ("pending", "graded",))

    security.declareProtected(PERMISSION_RESULT_WRITE, 'submit')

    def submit(self):
        self.setTimeFinish(DateTime())
        mcTest = getParent(self)
        results = mcTest.contentValues(filter={
            'Creator': self.Creator(),
            'portal_type': self.portal_type,
        })
        for res in results:
            # determine workflow action: submit for self and supersede
            # for all the others
            if res == self:
                if mcTest.isTutorGraded(self):
                    action = 'submit_pending'
                else:
                    action = 'submit_graded'
                commentAction = 'Submitted'
            else:
                action = 'supersede'
                commentAction = 'Superseded'
            # execute the action
            comment = '%s by %s' % (commentAction, self.Creator())
            res.tryWorkflowAction(action, ignoreErrors=True, comment=comment)

    security.declarePublic('isNewer')

    def isNewer(self, other):
        return self.getTimeStart() > other.getTimeStart()

    security.declarePublic('isMoreFinal')

    def isMoreFinal(self, other):
        STATES = [
            'unsubmitted',
            'superseded',
            'pending',
            'graded',
            #'invalid',
        ]
        indexes = [STATES.index(o.getWorkflowState()) for o in self, other]
        return indexes[0] > indexes[1]

    security.declarePrivate('getViewerNames')

    def getViewerNames(self):
        """
        Get the names of the users and/or groups which have the local
        role ROLE_RESULT_VIEWER.  This allows reviewers to quickly
        check who may view an assignment.
        
        @return list of user and/or group names
        """
        principalIds = self.users_with_local_role(ROLE_RESULT_VIEWER)
        names = []

        for id in principalIds:
            if self.portal_groups.getGroupById(id):
                names.append(
                    self.portal_groups.getGroupById(id).getGroupName())
            else:
                names.append(self.ecq_tool.getFullNameById(id))

        return names

    security.declarePublic('getIndicators')

    def getIndicators(self):
        """
        Returns a list of dictionaries which contain information necessary
        to display the indicator icons.
        """
        retVal = []

        user = self.portal_membership.getAuthenticatedMember()
        isOwner = user.has_role(['Owner', 'Reviewer', 'Manager'], self)
        isGrader = self.userIsGrader(user)

        viewers = self.getViewerNames()

        if viewers:
            if isOwner:
                retVal.append({
                    'src': 'ec_shared.png',
                    'alt': 'Released',
                    'alt_msgid': 'label_released',
                    'title': '; '.join(viewers),
                })
            elif isGrader:
                retVal.append({
                    'src': 'ec_shared.png',
                    'alt': 'Released',
                    'alt_msgid': 'label_released',
                    'title':
                    'These quiz results have been released for viewing.',
                    'title_msgid': 'tooltip_released_icon',
                })


#         if self.feedback:
#             feedback = str(self.feedback)
#             title = re.sub('[\r\n]+', ' ', feedback)[0:76]

#             retVal.append({'icon':'comment.png',
#                            'alt':'Feedback',
#                            'alt_msgid':'label_feedback',
#                            'title':title,
#                            })

#         if isGrader and hasattr(self, 'remarks') and self.remarks:
#             remarks = str(self.remarks)
#             title = re.sub('[\r\n]+', ' ', remarks)[0:76]

#             retVal.append({'icon':'ecab_remarks.png',
#                            'alt':'Remarks',
#                            'alt_msgid':'label_remarks',
#                            'title':title,
#                            })
        return retVal

    security.declarePublic('translateIndicators')

    def translateIndicators(self, indicators):
        # Translate [alt] and [title]
        for d in indicators:
            for k_msgid, k_msg in ((
                    'alt_msgid',
                    'alt',
            ), (
                    'title_msgid',
                    'title',
            )):
                msgid = d.get(k_msgid, None)
                if msgid is not None:
                    msg = d[k_msg]
                    d[k_msg] = self.translate(msgid=k_msg,
                                              domain=I18N_DOMAIN,
                                              default=msg)
                    d.pop(k_msgid)

        return indicators
Ejemplo n.º 8
0
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart

from ZODB.POSException import ConflictError

from Products.XPointContactManagement.config import PROJECTNAME

XPointAddressBookSchema = ATFolderSchema.copy() + Schema((

    # the unique sequence will serve contact, contact group, and contact
    # metadata.
    IntegerField(
        'xpcm_unique_sequence',
        default=0,
        # hide for view mode.
        widget=IntegerWidget(
            label='Unique Sequence',
            description=
            'This sequence will generate unique ids for this address book',
        ),
    ), ))

# Plone 3 will re-organize all fields' shemata by using this method.
finalizeATCTSchema(XPointAddressBookSchema)

# customizing the schema: set visible and location of fields.


# here comes the class.
class XPointAddressBook(ATFolder):
    """XPointAddressBook will be the folder for contact information.
    """
Ejemplo n.º 9
0
class ECQExtendedTextQuestion(ECQPointsQuestion):
    """A question that allows the candidate to write a text answer."""

    schema = ECQPointsQuestion.schema.copy() + Schema((
        TextField(
            'answerTemplate', # See 'description' property
                              # of the widget.
            searchable=True,
            required=False,
            allowable_content_types=('text/plain',
                                     #'text/structured',
                                     #'text/restructured',
                                     #'text/html',
                                     ),
            default_output_type='text/plain',
            widget=TextAreaWidget(
                label='Answer Template',
                label_msgid='answer_template_label',
                description="You can provide a template for the "
                "candidate's answer.",
                description_msgid='answer_template_tool_tip',
                i18n_domain=I18N_DOMAIN,
                rows=10,
                ),
            validators=('isXML',),
            read_permission=PERMISSION_STUDENT,
            ),
        
        IntegerField('expectedLength',
                required=False,
                default=50,
                validators=('isPositiveInt',),
                widget=IntegerWidget(
                    label='Expected Length',
                    label_msgid='expected_length_label',
                    description="You can set the number of words you "
                    "expect the candidate's answer to have.",
                    description_msgid='expected_length_tool_tip',
                    i18n_domain=I18N_DOMAIN),
                read_permission=PERMISSION_STUDENT,
            ),
        ),)
    # This type of question is always tutor-graded
    schema.delField('tutorGraded')
    # Make "points" appear *after* the "answerTemplate"
    schema.moveField('points', 1)
    schema.moveField('points', 1)
        
    allowed_content_types = ()
    filter_content_types = True # Otherwise allowed_content_types == ()
                                # means 'allow everything'
    
    meta_type = 'ECQExtendedTextQuestion'     # zope type name
    portal_type = meta_type                   # plone type name
    archetype_name = 'Extended Text Question' # friendly type name

    # Use the portal_factory for this type.  The portal_factory tool
    # allows users to initiate the creation objects in a such a way
    # that if they do not complete an edit form, no object is created
    # in the ZODB.
    #
    # This attribute is evaluated by the Extensions/Install.py script.
    use_portal_factory = True

    typeDescription = "A question that allows the candidate to write " \
                      "a text answer."
    typeDescMsgId = 'description_edit_extextquestion'

    security = ClassSecurityInfo()

    security.declarePublic('isTutorGraded')
    def isTutorGraded(self, *args, **kwargs):
        return True
Ejemplo n.º 10
0
import logging
from Products.Archetypes.public import Schema
from Products.Archetypes.public import IntegerField
from Products.Archetypes.public import IntegerWidget

from eea.facetednavigation.widgets import ViewPageTemplateFile
from eea.facetednavigation.widgets.widget import Widget as AbstractWidget
from eea.facetednavigation import EEAMessageFactory as _

logger = logging.getLogger('eea.facetednavigation.widgets.resultsperpage')

EditSchema = Schema((
    IntegerField('start',
                 schemata="display",
                 default=0,
                 widget=IntegerWidget(
                     label=_(u'Start'),
                     description=_(u'Results per page starting value'),
                     i18n_domain="eea")),
    IntegerField('end',
                 schemata="display",
                 default=50,
                 widget=IntegerWidget(
                     label=_(u'End'),
                     description=_(u'Results per page ending value'),
                     i18n_domain="eea")),
    IntegerField('step',
                 schemata="display",
                 default=5,
                 widget=IntegerWidget(label=_(u'Step'),
                                      description=_(u'Results per page step'),
Ejemplo n.º 11
0
class ECQSelectionQuestion(ECQBaseQuestion):
    """ A question that allows the candidate to select one or more of the 
        predefined answers contained in the question (ECQBaseQuestion is
        derived from 'BaseFolder').
    """

    schema = ECQBaseQuestion.schema + Schema(
        (
            BooleanField(
                'allowMultipleSelection',
                # If 'allowMultipleSelection' is True, this is a
                # multiple answer question, i.e. one where more than
                # one answer can be true. Otherwise it is a multiple
                # choice question, i.e. exactly only one answer is
                # correct.  The question_view template is designed to
                # support this. When 'allowMultipleSelection' is True,
                # radio buttons will be generated.  If not, check
                # boxes will be shown.  See also 'description'
                # property of the widget.
                accessor='isAllowMultipleSelection',
                default=1,
                searchable=False,
                widget=BooleanWidget(
                    label='Allow Multiple Selection',
                    label_msgid='allow_multiple_selection_label',
                    description=
                    'If the selection of multiple answers should be possible, mark this checkbox.',
                    description_msgid='allow_multiple_selection_tool_tip',
                    i18n_domain=I18N_DOMAIN),
                read_permission=PERMISSION_STUDENT,
                languageIndependent=True,
            ),
            BooleanField(
                "randomOrder",  # See 'description' property
                # of the widget.
                accessor='isRandomOrder',
                required=False,
                default=1,
                read_permission=PERMISSION_INTERROGATOR,
                widget=BooleanWidget(
                    label='Randomize Answer Order',
                    label_msgid='randomize_answer_order_label',
                    description='Check this box if you want the answers '
                    'to this question to appear in a different, random '
                    'order for each candidate. Otherwise the '
                    'same order as in the "contents"-view will '
                    'be used.',
                    description_msgid='randomize_answer_order_tool_tip',
                    i18n_domain=I18N_DOMAIN),
                #read_permission=PERMISSION_STUDENT,
                languageIndependent=True,
            ),
            IntegerField(
                "numberOfRandomAnswers",  # See 'description'
                # property of the
                # widget.
                default=-1,
                read_permission=PERMISSION_INTERROGATOR,
                widget=IntegerWidget(
                    label='Number of Random Answers',
                    label_msgid='number_of_random_answers_label',
                    description='The number of answers which are randomly '
                    'selected when a new quiz is generated for a candidate. '
                    '(This only works if "Randomize Answer Order" '
                    'is checked.)  A value <= 0 means that all answers '
                    'will be used.',
                    description_msgid='number_of_random_answers_tool_tip',
                    i18n_domain=I18N_DOMAIN),
                #read_permission=PERMISSION_STUDENT,
                languageIndependent=True,
            ),
        ), )

    security = ClassSecurityInfo()

    security.declarePrivate('makeNewTest')

    def makeNewTest(self, candidateResult, suMode):
        """generate a new quiz"""
        allAnswers = self.contentValues()
        if self.isRandomOrder() and (not suMode):
            # use random order
            numRnd = min(len(allAnswers), self.getNumberOfRandomAnswers())
            if numRnd > 0:
                # Separate the correct answers
                correctAnswers = [a for a in allAnswers if a.isCorrect()]
                # Determine how many correct answers and how many
                # other answers to show
                maxNumCorrect = min(len(correctAnswers), numRnd)
                numCorrect = random.randint(1, maxNumCorrect)
                numOther = numRnd - numCorrect
                # Get the randomized correct answers
                rndCorrectAnswers = random.sample(correctAnswers, numCorrect)
                # Now choose numOther-many answers out of the ones
                # that are not in rndCorrectAnswers
                otherAnswers = [
                    a for a in allAnswers if a not in rndCorrectAnswers
                ]
                rndOtherAnswers = random.sample(otherAnswers, numOther)

                suggestedAnswers = rndCorrectAnswers + rndOtherAnswers
            else:
                suggestedAnswers = allAnswers
            # Randomize the answers
            suggestedAnswers = random.sample(suggestedAnswers,
                                             len(suggestedAnswers))
        else:
            # Use the order in the "contents"-view
            suggestedAnswers = allAnswers
        suggestedAnswerIds = [answer.getId() for answer in suggestedAnswers]

        # Store the new suggested answer ids in the results object
        candidateResult.setSuggestedAnswer(self, suggestedAnswerIds)

    security.declareProtected(PERMISSION_STUDENT, 'getSuggestedAnswerIds')

    def getSuggestedAnswerIds(self, result):
        """Return a list with the IDs of the answer objects that were
        presented to the candidate.
        
        @param result The candidate's result object.
        """
        return result.getSuggestedAnswer(self)

    security.declareProtected(PERMISSION_STUDENT, 'getSuggestedAnswers')

    def getSuggestedAnswers(self, result):
        """Return a list with the actual answer objects that were
        presented to the candidate with ID candidateId.
        
        @param result The candidate's result object.
        """

        allAnswers = self.contentValues()
        suggestedAnswerIds = result.getSuggestedAnswer(self)
        retVal = filterById(suggestedAnswerIds, allAnswers)

        return retVal
Ejemplo n.º 12
0
     required=True,
     searchable=False,
     languageIndependent=True,
     storage=AnnotationStorage(),
     widget=DecimalWidget(
         description=_(u''),
         label=_(u'Risk Rate'),
     ),
     default=0.0,
 ),
 IntegerField(
     name='min_delivery_days',
     required=True,
     searchable=False,
     languageIndependent=True,
     storage=AnnotationStorage(),
     widget=IntegerWidget(
         label=_(u'Minimum Delivery Days'),
         size='2',
         maxlength='2',
     ),
 ),
 IntegerField(
     name='max_delivery_days',
     required=True,
     searchable=False,
     languageIndependent=True,
     storage=AnnotationStorage(),
     widget=IntegerWidget(
         label=_(u'Maximum Delivery Days'),
         size='2',
         maxlength='2',
Ejemplo n.º 13
0
         #visible={'view':'invisible','edit':'hidden'},
         cols=40,
         rows=3),
 ),
 TextField(
     'sent_trackback_url',
     searchable=False,
     default_output_type='text/plain',
 ),
 IntegerField(
     'allow_comment',
     searchable=0,
     default=2,
     widget=SelectionWidget(
         label='Comment status',
         label_msgid='label_allow_comment',
         description_msgid='help_allow_comment',
         i18n_domain='plone',
     ),
     vocabulary=IntDisplayList(comment_status),
     schemata='cbentry_extented_fields',
 ),
 IntegerField(
     'receive_trackback',
     searchable=0,
     default=2,
     widget=SelectionWidget(
         label='Trackback status',
         label_msgid='label_receive_trackback',
         description_msgid='help_receive_trackback',
         i18n_domain='plone',
Ejemplo n.º 14
0
     widget=SelectionWidget(
         label=_(u'Cart ID Numbering Method'),
         description=_(
             u'Select Incremental or Random for Cart ID Numbering.'),
     ),
     vocabulary=('Incremental', 'Random'),
     enforceVocabulary=True,
     default='Incremental',
 ),
 IntegerField(
     name='next_incremental_cart_id',
     required=False,
     searchable=False,
     languageIndependent=True,
     storage=AnnotationStorage(),
     widget=IntegerWidget(
         label=_(u'Next Incremental Cart ID'),
         description=
         _(u'If Incrementanl Cart ID is seleceted, give interger number here.'
           ),
     ),
     default=1,
 ),
 IntegerField(
     name='random_digits_cart_id',
     required=False,
     searchable=False,
     languageIndependent=True,
     storage=AnnotationStorage(),
     widget=IntegerWidget(
         label=_(u'Random Digits Cart ID'),
         description=_(
Ejemplo n.º 15
0
        ),

        # Progress Status in percentage. 0% - 100%
        FloatField(
            'xppm_story_progress_percent',
            searchable=False,
            required=False,
            default=0.0,
        ),

        # estimated hours for this task.
        IntegerField(
            'xppm_story_estimated_hours',
            searchable=False,
            required=False,
            widget=IntegerWidget(
                label='Estimated Hours',
                descrpiton='Put here the estimated hours for this task',
            ),
            schemata='Manage',
        ),

        # used hours for this task.
        FloatField(
            'xppm_story_used_hours',
            searchable=False,
            required=False,
            default=0.0,
        ),

        # owner of this task.??? select from membership.
        # getToolByName(self, 'portal_membership')
Ejemplo n.º 16
0
    (ACQUIRE, 'Use setting from parent folder', 'ratings_aquire_parent'),
    (DISABLED, 'Disable', 'ratings_disable'),
    (ENABLED, 'Enable', 'ratings_enable'),
))

RatingsFolderMixinSchema = Schema((
    IntegerField('enableRatings',
                 default=ACQUIRE,
                 vocabulary=enableDisplayList,
                 accesor='getEnableRatings',
                 edit_accessor='getEnableRatings',
                 mutator='setEnableRatings',
                 write_permissions='Manage properties',
                 schemata='Ratings',
                 languageIndependent=True,
                 widget=SelectionWidget(
                     label='Enable ratings',
                     visible={
                         'edit': 'visible',
                         'view': 'hidden'
                     },
                     label_msgid='label_enable_ratings',
                     description='Enable raings under this folder',
                     description_msgid='description_enable_ratings',
                     i18n_domain='at_ratings')),
    IntegerField('enableCountings',
                 default=ACQUIRE,
                 vocabulary=enableDisplayList,
                 accesor='getEnableCountings',
                 edit_accessor='getEnableCountings',
                 mutator='setEnableCountings',
Ejemplo n.º 17
0
                     "HTML formatting is allowed.")
             ),
 ),
 StringField('Unit',
             schemata="Description",
             widget=StringWidget(
                 label=_("Unit"),
                 description=_(
                     "The measurement units for this analysis service' results, "
                     "e.g. mg/l, ppm, dB, mV, etc."),
             ),
 ),
 IntegerField('Precision',
              schemata="Analysis",
              widget=IntegerWidget(
                  label=_("Precision as number of decimals"),
                  description=_(
                      "Define the number of decimals to be used for this result."),
              ),
 ),
 IntegerField('ExponentialFormatPrecision',
              schemata="Analysis",
              default = 7,
              widget=IntegerWidget(
                  label=_("Exponential format precision"),
                  description=_(
                      "Define the precision when converting values to exponent notation."),
              ),
 ),
 IntegerField('ExponentialFormatPrecision',
              schemata="Analysis",
              default = 7,
Ejemplo n.º 18
0
                label='90% Completion Deadline',
                description=
                'Specify the date when this task should be completed at less 90%',
                starting_year=2007,
                show_hm=False,
            ),
        ),

        # Progress Status in percentage. 0% - 100%
        IntegerField(
            'xptask_progress_percent',
            index='FieldIndex:schema',
            searchable=False,
            required=True,
            default=0,
            # set the range from 0 to 100
            vocabulary=IntDisplayList([(i, i) for i in range(0, 101)]),
            widget=SelectionWidget(
                label='Progress Status',
                descrpiton='Progress status in percentage 0% - 100%',
                format='select',
            ),
        ),

        # estimated hours for this task.
        IntegerField(
            'xptask_estimated_hours',
            index='FieldIndex:schema',
            searchable=False,
            required=False,
            widget=IntegerWidget(
                label='Estimated Hours',
Ejemplo n.º 19
0
 ),
 UIDReferenceField("Supervisor",
                   required=0,
                   allowed_types=("LabContact", ),
                   vocabulary="_getLabContacts",
                   write_permission=ManageBika,
                   accessor="getSupervisorUID",
                   widget=SelectionWidget(
                       format="select",
                       label=_("Supervisor"),
                       description=_("Supervisor of the Lab"))),
 IntegerField(
     "Confidence",
     schemata="Accreditation",
     widget=IntegerWidget(
         label=_("Confidence Level %"),
         description=_("This value is reported at the bottom of all "
                       "published results"),
     ),
 ),
 BooleanField(
     "LaboratoryAccredited",
     default=False,
     schemata="Accreditation",
     write_permission=ManageBika,
     widget=BooleanWidget(
         label=_("Laboratory Accredited"),
         description=_("Check this box if your laboratory is accredited"),
     ),
 ),
 StringField(
Ejemplo n.º 20
0
            searchable = False,
            required = True,
            default = ('Expense', 'Income'),
            widget = LinesWidget(
                label = 'Transaction Types',
                description = 'Please specify the transaction types, one per line',
                cols = 40,
                ),
            ),

        # the unique sequence will serve
        IntegerField(
            'bk_unique_sequence',
            default = 0,
            # hide for view mode.
            widget = IntegerWidget(
                label = 'Unique Sequence',
                description = 'This sequence will generate unique ids for all artifacts in this folder.',
                ),
            ),

        # this is a field to save the transaction categories.
        # TODO: this field should be invisable!
        LinesField(
            'bk_transaction_categories',
            accessor = 'transactionCategories',
            searchable = False,
            required = True,
            default = ('Income:ConsultingIncome', 'Income:ServiceIncome', 
                'Expense:Gas', 'Expense:Parking', 'Expense:Lunch',
                'Expense:Internet', 'Expense:OfficeSupply'
Ejemplo n.º 21
0
                    description='',
                    label_msgid='label_long_description',
                    description_msgid='help_long_description',
                    i18n_domain='plone',
                    cols=60,rows=5),
        ),

    #Entry listing
    IntegerField('top_entry_count_setting',
        searchable=0,
        default=1,
        widget=SelectionWidget(label='Entries per page',
                    description='',
                    label_msgid='label_top_entry_count_setting',
                    description_msgid='help_top_entry_count_setting',
                    i18n_domain='plone',
                    ),
        vocabulary=IntDisplayList((
                    (1, 'In days', 'label_show_entry_in_days'),
                    (2, 'In entry count', 'label_show_entry_in_count'),
                    )),
        schemata='cbsettings_display',
        ),

    IntegerField('top_entry_count',
        searchable=0,
        default = zconf.coreblog2.top_entry_count_default,
        widget=IntegerWidget(label='Entries count',
                    description='',
                    label_msgid='label_top_entry_count',
                    description_msgid='help_top_entry_count',
Ejemplo n.º 22
0
                        u'Get unique values from catalog as an alternative '
                        u'for vocabulary'),
                    i18n_domain="eea")),
    BooleanField('hidealloption',
                 schemata="default",
                 default=False,
                 widget=BooleanWidget(
                     label=_(u"Hide 'All' option"),
                     description=_(
                         u'If this checkbox is checked, hides the All '
                         u'option'),
                     i18n_domain="eea")),
    IntegerField('maxitems',
                 schemata="display",
                 default=0,
                 widget=IntegerWidget(
                     label=_(u'Maximum items'),
                     description=_(u'Number of items visible in widget'),
                     i18n_domain="eea")),
    BooleanField('sortreversed',
                 schemata="display",
                 widget=BooleanWidget(label=_(u'Reverse options'),
                                      description=_(u'Sort options reversed'),
                                      i18n_domain="eea")),
    StringField('default',
                schemata="default",
                widget=StringWidget(size=25,
                                    label=_(u'Default value'),
                                    description=_(u'Default selected item'),
                                    i18n_domain="eea")),
))
Ejemplo n.º 23
0
#                                                    INonStructuralFolder

from AccessControl import ClassSecurityInfo
from Products.CMFCore.permissions import View,ModifyPortalContent
from Products.CMFCore.utils import getToolByName

from zope.interface import implements
from actions_proxy import updateAliases, base_aliases

COREBlogCategorySchema = ATContentTypeSchema.copy() +  Schema((

    IntegerField('internal_id',
        searchable=False,
        isMetadata=True,
        mutator="setInternal_id",
        widget=IntegerWidget(label='Internal ID',
            description='',
            visible={'view':'invisible','edit':'hidden'},
            ),
        ),

    ImageField('category_image',
        widget=ImageWidget(label='Category image',
            description='',
            label_msgid='label_category_image',
            description_msgid='help_category_image',
            i18n_domain='plone',
            ),
        sizes={ 'icon':(16,16)},
        ),
Ejemplo n.º 24
0
#!/usr/bin/python
#$Id: PersonSQL.py,v 1.2 2004/06/07 20:08:48 andy Exp $
#Copyright: ClearWind Consulting Ltd
#License: http://www.clearwind.ca/license

from Products.Archetypes.public import Schema
from Products.Archetypes.public import IntegerField, StringField
from Products.Archetypes.public import IntegerWidget, StringField
from Products.Archetypes.SQLStorage import PostgreSQLStorage
from config import PROJECT_NAME

schema = BaseSchema + Schema((
    IntegerField(
        'age',
        validators=(("isInt", )),
        storage=SQLStorage(),
        widget=IntegerWidget(label="Your age"),
    ),
    StringField('email',
                validators=('isEmail', ),
                index="TextIndex",
                storage=SQLStorage(),
                widget=StringWidget(label='Email', )),
))


class PersonSQL(BaseContent):
    """Our person object"""
    schema = schema