class QuestionSelectionParameters(BaseQuestionSelectionParameters): """Container for parameres used when selection a question in a quiz.""" _at_rename_after_creation = True schema = BaseQuestionSelectionParametersSchema.copy() + Schema(( FloatField("historical_selection_probability", required=False, default='-1.0', # # -1.0 <= value < 1.000001 validators = ('validRange',), widget=DecimalWidget(description='Probability of selecting questions in a quiz from previous lectures. Possible values:\n' '-1.0: Historical selection probability obtained from values set in parent Tutorial.\n' '1.0: All questions from previous lectures and current are used as a selection pool.' 'h: For h between 0 and 1, select from pool with probability h vs current lecture only with probability 1-h.' '0.0: Only select questions from the current lecture.', ),), ReferenceField('BaseSelectionParameters', required = 1, widget=ReferenceWidget( label="Default parameters used when selecting questions", description='Object containing default values for choosing questions.', destination=".", destination_types=("BaseQuestionSelectionParameters",), ), multiValued=False, relationship='DefaultValues', allowed_types= ("BaseQuestionSelectionParameters",), ), )) security = ClassSecurityInfo() security.declarePrivate('tryWorkflowAction') def tryWorkflowAction(self, action, ignoreErrors=False, comment=None): """change the action on the lecture""" #wtool = getToolByName(self, 'portal_workflow') 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 findHistorical_selection_probability(self): if (self.getField('historical_selection_probability').get(self) >= 0.0): return self.getField('historical_selection_probability').get(self) else: baseparams = self.getBaseSelectionParameters() if (baseparams): return baseparams.getHistorical_selection_probability() else: return 1.0
class NewsletterReference(BaseContent, PropertyManager): portal_type = meta_type = 'NewsletterReference' archetype_name = 'Newsletter Reference' #this name appears in the 'add' box security = ClassSecurityInfo() schema=BaseSchema + Schema(( TextField('description', default='', searchable=1, isMetadata=1, accessor="Description", widget=TextAreaWidget(label='Description', description='An administrative summary of the content', label_msgid='label_description', description_msgid='help_description', i18n_domain="plone") ), ReferenceField('references', languageIndependent=1, required=0, allowed_types=(), multiValued=1, relationship='references', widget=ReferenceBrowserWidget(label='References', description='Select one or more remote objects', label_msgid='label_references', description_msgid='help_references', i18n_domain='plonegazette', allow_search=1, allow_browse=1, show_indexes=0, ), ), )) # Make sure we get title-to-id generation when an object is created _at_rename_after_creation = True security.declarePublic('getObjects') def getObjects(self): """ """ return self.getReferences() # uncommant lines below when you need factory_type_information={ 'allowed_content_types':[], 'global_allow' : 0, 'content_icon':'NewsletterReference.gif', 'immediate_view':'newsletterreference_view', 'filter_content_types' : 0 } actions=({ 'id' : 'view', 'name' : 'View', 'category' : 'object', 'action' : 'string:${object_url}/NewsletterReference_view', 'permissions' : ('View',) },)
# Copyright 2018-2019 by it's authors. # Some rights reserved, see README and LICENSE. from AccessControl import ClassSecurityInfo from Products.Archetypes.public import ReferenceField, Schema, registerType from bika.lims.content.analysis import Analysis from bika.lims.config import PROJECTNAME from bika.lims.content.analysis import schema as analysis_schema from bika.lims.interfaces import IRejectAnalysis from zope.interface import implements schema = analysis_schema + Schema(( # The analysis that was originally rejected ReferenceField( 'Analysis', allowed_types=('Analysis', ), relationship='RejectAnalysisAnalysis', ), )) class RejectAnalysis(Analysis): implements(IRejectAnalysis) security = ClassSecurityInfo() schema = schema @security.public def getSample(self): return self.aq_parent
from Products.membrane.at.interfaces import IUserAuthProvider from Products.membrane.at.interfaces import IUserPropertiesProvider from Products.membrane.at.interfaces import IUserRoles from Products.membrane.config import PROJECTNAME from Products.membrane.config import TOOLNAME from Products.membrane.interfaces import group as group_ifaces from Products.membrane.interfaces import user as user_ifaces from zope.interface import implementer GROUP_RELATIONSHIP = 'participatesInProject' group = BaseSchema.copy() + Schema(( ReferenceField(name='manager', relationship='managesProject', allowed_types=( 'Member', 'TestMember', ), vocabulary='listUsers', languageIndependent=1), ReferenceField( name="members", relationship=GROUP_RELATIONSHIP, multiValued=1, languageIndependent=1, allowed_types=( 'Member', 'TestMember', ), vocabulary='listUsers', ), LinesField(
from Products.Archetypes.public import (BaseFolder, ComputedField, ComputedWidget, DisplayList, ReferenceField, ReferenceWidget, Schema, StringField, StringWidget, TextAreaWidget, TextField) from Products.CMFPlone.utils import safe_unicode from bika.lims import bikaMessageFactory as _ from bika.lims.browser.widgets import ScheduleInputWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.interfaces import ICancellable from zope.interface import implements schema = BikaSchema.copy() + Schema(( ReferenceField("Instrument", allowed_types=("Instrument", ), relationship="InstrumentScheduledTaskInstrument", widget=StringWidget(visible=False, )), ComputedField( "InstrumentUID", expression= "context.getInstrument() and context.getInstrument().UID() or None", widget=ComputedWidget(visible=False, ), ), StringField( "Type", vocabulary="getTaskTypes", widget=ReferenceWidget( checkbox_bound=0, label=_("Task type", "Type"), ), ),
""" from AccessControl import ClassSecurityInfo from Products.ATExtensions.ateapi import RecordsField from Products.Archetypes import atapi from Products.Archetypes.public import ReferenceField, FileField, \ StringField, Schema, BaseFolder from plone.app.blob.field import BlobField from Products.Archetypes.references import HoldingReference from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema schema = BikaSchema.copy() + Schema(( ReferenceField( 'AnalysisRequest', allowed_types=('AnalysisRequest', ), relationship='ReportAnalysisRequest', referenceClass=HoldingReference, required=1, ), BlobField('Pdf', ), StringField('Html', ), StringField('SMS', ), RecordsField( 'Recipients', type='recipients', subfields=('UID', 'Username', 'Fullname', 'EmailAddress', 'PublicationModes'), ), )) schema['id'].required = False
LinkInnerContentProxySchema = BaseInnerContentProxySchema.copy() + Schema(( ComputedField( 'remoteUrl', primary=True, expression="""context.getPrimaryValue('')""", widget=ComputedWidget( label='Remote url', label_msgid='label_remote_url', i18n_domain='plonearticle', ), ), ReferenceField( 'referencedContent', relationship='article_link', widget=ReferenceBrowserWidget( label='Referenced link', label_msgid='label_referenced_link', i18n_domain='plonearticle', ), ), StringField( 'attachedLink', widget=StringWidget( label='Link', label_msgid='label_link', i18n_domain='plonearticle', ), ), ))
class Course(ATFolder): """ A Course belongs to a specific Department although it can contain tutorials from any Department. A course has a specific code which is used together with the Department code to uniquely identify the Course. Students can be enrolled in a Course. A course is implemented as a folder which can contain additional files corresponding to relevant Literature and has references to the tutorials which belong to it. It also implements a list of students which have enrolled in the course. Only registered users of the tutor-web can enroll in a course. It is implemented as an ATFolder as well as interfaces, ICourse and IOrderedTutorWebContent. """ schema = ATFolderSchema.copy() + Schema(( StringField( 'title', required=True, searchable=0, default='Course', widget=StringWidget( label='Title', descriptio='Course title', ), ), ReferenceField( 'Tutorials', widget=ReferenceBrowserWidget( label="Tutorials", description='Tutorials which belong to the course', destination=".", destination_types=("Tutorial", ), allow_sorting=1, ), multiValued=True, relationship='hasTutorial', allowed_types=("Tutorial", ), ), StringField( 'Students', vocabulary='getAvailableStudents', widget=InAndOutWidget( label='Students', description='Students enrolled in the course.', ), ), StringField( 'Code', widget=StringWidget( label='Numberic Course Code', description= 'Specify a numberid code which is used to identify the course. For example: 101, 202', ), required=1, validators=('isSameCourseCode', ), ), ComputedField( 'numTutorials', expression='context.computeNumTutorials()', widget=StringWidget(modes=('view', )), ), )) __implements__ = (ATFolder.__implements__) implements(ICourse, IOrderedTutorWebContent) global_allow = True meta_type = 'Course' # zope type name portal_type = meta_type # plone type name archetype_name = 'Course' # friendly type name _at_rename_after_creation = True security = ClassSecurityInfo() def publishAll(self, typeofobject=None, originalobj=None): """publich content""" self.tryWorkflowAction("publish", ignoreErrors=True) def computeGrades(self, userId): """return the grade for a student based on userId""" # FIXME, what is userId is not a alid id??? tutorials = self.getTutorials() numtutorials = len(tutorials) points = 0.0 for tut in tutorials: points = points + tut.computeGrades(userId) if (numtutorials > 0): return float(points / numtutorials) else: return 0.0 def addUser(self): """enroll the logged in user""" pm = self.portal_membership memberId = pm.getAuthenticatedMember().getId() member = pm.getMemberById(memberId) userfull = member.getProperty('fullname') pair = [] pair.append((userfull, memberId)) # should check if already enrolled studs = self.getStudents() if (type(studs) == type('itsastring')): l = [] l.append(studs) l.append(memberId) self.getField('Students').set(self, l) else: studs.append(memberId) self.getField('Students').set(self, studs) def getEnrolledStudents(self): """return all enrolled students""" stud = self.getStudents() if (type(stud) == type('itsastring')): l = [] l.append(stud) return l else: return self.getStudents() def getAvailableStudents(self): """return all registered members of the tutor-web""" # FIXME this could be far too big a list to be return in one go # needs to return only partly pm = self.portal_membership pair = [] for memberId in pm.listMemberIds(): member = pm.getMemberById(memberId) userfull = member.getProperty('fullname') pair.append((memberId, userfull)) return DisplayList(pair) def getAvailableStudents2(self): """return all registered users of the tutor-web""" pm = self.portal_membership results = pm.listMembers() pair = [] for r in results: pair.append((r.UID, r.Title)) return DisplayList(pair) def getAvailableStudents1(self): """return all registered members of the tutor-web""" memb = self.portal_membership portal_users = getToolByName(self, "acl_users") membership = getToolByName(self, 'portal_membership') #Beware if hundreds of students this is very expensive! # need to use search tool results = membership.listMembers() numstuds = str(len(results)) for r in results: r1 = r.getUser() userid = r1.getId() userfull1 = membership.getMemberById(userid) userfull = userfull1.getProperty('fullname') pair = [] for c in results: r = c.getUser() pair.append((r.getUserName(), r.getId())) return DisplayList(pair) def portalUrl(self): """Return the url of the site which the course belongs to """ portal = getToolByName(self, 'portal_url').getPortalObject() return portal def isLoggedOn(self): """True of user has logged in to the tutor-web else Fase""" mtool = getToolByName(self, 'portal_membership') if mtool.isAnonymousUser(): return False else: return True def getCourseCode(self): return self.getCode() security.declarePrivate('initializeObject') def initializeObject(self): """Called after course has been created for the first time, publish course and reorder department objects""" self.tryWorkflowAction("publish", ignoreErrors=True) parent = aq_parent(self) try: parent.orderObjects("id") parent.plone_utils.reindexOnReorder(parent) except: raise 'Failed to create course ' + self.getTitle( ) + ' not able to reorder courses' security.declarePrivate('tryWorkflowAction') def tryWorkflowAction(self, action, ignoreErrors=False, comment=None): """try to change actions for course""" 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 canSeeQuestions(self): """if current user has the role of a manager, editor, owner or belongs to the group: teacher then return True else False""" try: user = getSecurityManager().getUser() groups = user.getGroups() if (user.has_role('Manager')): return True elif (user.has_role('Editor')): return True elif (user.has_role('Owner')): return True elif ('teacher' in groups): return True else: return False except: '''could not establish who user is''' return False def generateNewId(self): """Suggest an id for this object based on Department code and Course code. This id is used when automatically renaming an object after creation. """ parent = aq_parent(self) title = (parent.getCode() + self.getCode()).strip() # Can't work w/o a title if not title: return None # Don't do anything without the plone.i18n package if not URL_NORMALIZER: return None if not isinstance(title, unicode): charset = self.getCharset() title = unicode(title, charset) request = getattr(self, 'REQUEST', None) if request is not None: return IUserPreferredURLNormalizer(request).normalize(title) return queryUtility(IURLNormalizer).normalize(title) security.declareProtected(View, 'computeNumTutorials') def computeNumTutorials(self): """find number of tutorials which belong to this course""" refs = self.getRawTutorials() return len(refs) def updateSlideMaterial(self): """Update all slides for every tutorial/lecture belonging to the course.""" tuts = self.getTutorials() for tut in tuts: tmp = tut.updateSlideMaterial() def getFullName(self, userid): """Return the full name of a user based on given id""" # FIXME what if id is not valid??? if PLONE_VERSION == 3: ecq_tool = getToolByName(self, 'ecq_tool') return ecq_tool.getFullNameById(userid) else: parent = aq_parent(self) return parent.getFullName(userid)
visible={ "edit": "visible", "view": "visible", }, ), ), ReferenceField( "DefaultCategories", schemata="Preferences", required=0, multiValued=1, allowed_types=("AnalysisCategory", ), relationship="ClientDefaultCategories", widget=ReferenceWidget( label=_("Default categories"), description=_( "Always expand the selected categories in client views"), showOn=True, catalog_name=SETUP_CATALOG, base_query=dict( is_active=True, sort_on="sortable_title", sort_order="ascending", ), ), ), ReferenceField( "RestrictedCategories", schemata="Preferences", required=0, multiValued=1, validators=("restrictedcategoriesvalidator", ),
label=_("Sampling Frequency"), description= _("If a sample is taken periodically at this sample point, enter frequency here, e.g. weekly" ), ), ), ReferenceField( 'SampleTypes', required=0, multiValued=1, allowed_types=('SampleType', ), relationship='SamplePointSampleType', widget=BikaReferenceWidget( label=_("Sample Types"), description=_("The list of sample types that can be collected " "at this sample point. If no sample types are " "selected, then all sample types are available."), catalog_name='bika_setup_catalog', base_query={ "is_active": True, "sort_on": "sortable_title", "sort_order": "ascending" }, showOn=True, ), ), BooleanField( 'Composite', default=False, widget=BooleanWidget( label=_("Composite"), description=
from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.interfaces import IDeactivable from bika.lims.interfaces import IDepartment Manager = ReferenceField( 'Manager', required=1, allowed_types=('LabContact',), referenceClass=HoldingReference, relationship="DepartmentLabContact", widget=ReferenceWidget( label=_("Manager"), description=_( "Select a manager from the available personnel configured under " "the 'lab contacts' setup item. Departmental managers are " "referenced on analysis results reports containing analyses by " "their department."), showOn=True, catalog_name=SETUP_CATALOG, base_query=dict( is_active=True, sort_on="sortable_title", sort_order="ascending", ), ), ) schema = BikaSchema.copy() + Schema(( Manager, ))
from Products.Archetypes.public import BaseFolder from Products.Archetypes.public import FileWidget from Products.Archetypes.public import ReferenceField from Products.Archetypes.public import Schema from Products.Archetypes.public import registerType from Products.ATExtensions.ateapi import DateTimeField from Products.ATExtensions.ateapi import DateTimeWidget from Products.CMFPlone.utils import safe_unicode from zope.interface import implements schema = BikaSchema.copy() + Schema(( BlobFileField("InvoicePDF", widget=FileWidget(label=_("Invoice PDF"), )), ReferenceField( "Client", required=1, vocabulary_display_path_bound=sys.maxsize, allowed_types=("Client", ), relationship="ClientInvoice", ), ReferenceField( "AnalysisRequest", required=1, vocabulary_display_path_bound=sys.maxsize, allowed_types=("AnalysisRequest", ), relationship="AnalysisRequestInvoice", ), ReferenceField( "SupplyOrder", required=1, vocabulary_display_path_bound=sys.maxsize, allowed_types=("SupplyOrder", ),
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
ImageInnerContentProxySchema = BaseInnerContentProxySchema.copy() + Schema(( ComputedField( 'image', primary=True, expression="""context.getPrimaryValue('image', 'attachedImage', '')""", widget=ComputedWidget( label='Image', label_msgid='label_image', i18n_domain='plonearticle', ), ), ReferenceField( 'referencedContent', relationship='article_image', keepReferencesOnCopy=True, widget=ReferenceBrowserWidget( label='Referenced image', label_msgid='label_referenced_image', i18n_domain='plonearticle', ), ), ImageField( 'attachedImage', attached_content=True, widget=ImageWidget( label='Attached image', label_msgid='label_attached_image', i18n_domain='plonearticle', ), ), ))
from Products.Archetypes.public import registerType from Products.Archetypes.public import Schema from Products.CMFCore.utils import getToolByName from Products.membrane.config import PROJECTNAME from Products.membrane.config import TOOLNAME from Products.membrane.interfaces import user as user_ifaces from Products.membrane.interfaces.group import IGroup from Products.membrane.utils import getFilteredValidRolesForPortal from zope.interface import implementer SimpleSchema = BaseSchema + Schema(( ReferenceField( name='manager', relationship='managesProject', allowed_types=('SimpleMember', ), vocabulary='listUsers', languageIndependent=1, widget=ReferenceWidget(label='Group manager', description='The manager of this project.'), ), ReferenceField( name="members", relationship='participatesInProject', multiValued=1, languageIndependent=1, allowed_types=('SimpleMember', ), vocabulary='listUsers', widget=ReferenceWidget( label='Associated group members', description='''\ Members of this group that are really from other groups''',
class Class(ATFolder): """ A Course belongs to a specific Department although it can contain tutorials from any Department. A course has a specific code which is used together with the Department code to uniquely identify the Course. Students can be enrolled in a Course. A course is implemented as a folder which can contain additional files corresponding to relevant Literature and has references to the tutorials which belong to it. It also implements a list of students which have enrolled in the course. Only registered users of the tutor-web can enroll in a course. It is implemented as an ATFolder as well as interfaces, ICourse and IOrderedTutorWebContent. """ schema = ATFolderSchema.copy() + Schema(( StringField( 'title', required=True, searchable=0, default='Class name', widget=StringWidget( label='Title', description='Class name', ), validators=('isSameClassName', ), ), StringField( 'classDatabaseId', widget=StringWidget( label="Database Id", visible={ 'edit': 'invisible', 'view': 'invisible' }, ), ), ReferenceField( 'Tutorials', widget=ReferenceBrowserWidget( label="Tutorials", description='Tutorials which belong to the class', destination=".", destination_types=("Tutorial", ), allow_sorting=1, ), #allow_sorting=1, multiValued=True, relationship='hasTutorial', allowed_types=("Tutorial", ), ), StringField( 'Students', vocabulary='getAvailableStudents', widget=InAndOutWidget( label='Students', description='Students enrolled in the course.', visible={ 'edit': 'invisible', 'view': 'invisible' }, ), ), StringField( 'Instructor', #vocabulary='getAvailableStudents', default='', widget=StringWidget( label='Instructor', description='Instructor of the class.', ), ), StringField( 'ContactInformation', #vocabulary='getAvailableStudents', default='', widget=StringWidget( label='Contact Information', description='How to contact instructor of the class.', ), ), ComputedField( 'numTutorials', expression='context.computeNumTutorials()', widget=StringWidget(modes=('view', )), ), )) __implements__ = (ATFolder.__implements__) implements(IClass) global_allow = True meta_type = 'Class' # zope type name portal_type = meta_type # plone type name archetype_name = 'Class' # friendly type name _at_rename_after_creation = True security = ClassSecurityInfo() def publishAll(self, typeofobject=None, originalobj=None): """publich content""" self.tryWorkflowAction("publish", ignoreErrors=True) def computeGrades(self, userId): """return the grade for a student based on userId""" # FIXME, what is userId is not a valid id??? tutorials = self.getTutorials() numtutorials = len(tutorials) points = 0.0 for tut in tutorials: points = points + tut.computeGrades(userId) if (numtutorials > 0): return float(points / numtutorials) else: return 0.0 def addUser(self): """enroll the logged in user""" pm = self.portal_membership memberId = pm.getAuthenticatedMember().getId() member = pm.getMemberById(memberId) userfull = member.getProperty('fullname') pair = [] pair.append((userfull, memberId)) # should check if already enrolled studs = self.getStudents() if (memberId in studs): return userfull + "already enrolled in " + self.getTitle() if (type(studs) == type('itsastring')): l = [] l.append(studs) l.append(memberId) self.getField('Students').set(self, l) else: studs.append(memberId) self.getField('Students').set(self, studs) updated = self.updateDatabase(member, memberId) if updated: tit = self.getTitle() if not isinstance(tit, unicode): charset = self.getCharset() tit = unicode(tit, charset) return userfull + " has been enrolled in " + tit else: return "could not update database" ##return "bla" def updateDatabase(self, member, candidateId): #start by checking if student already registered in tutorweb # has been allocated a random number, if not register # then add to database if needed. portal_catalog = getToolByName(self, 'portal_catalog') students = portal_catalog.unrestrictedSearchResults( {'portal_type': 'StudentList'}) if (len(students) > 0): numlists = str(len(students)) objid = self.unrestrictedTraverse(str(students[0].getPath()), None) ranid = objid.addStudent(candidateId) studlocator = getUtility(IStudentLocator) studentinfo = studlocator.student_by_randomnumber(ranid) if (not studentinfo): '''student has not been added database''' email = 'not known' firstname = '' familyname = '' loginname = '' #membership = self.portal_membership #member = membership.getAuthenticatedMember() if member: loginname = member.getUserName() email = member.getProperty('email') fullname = member.getProperty('fullname') tempname = fullname.split() if (len(tempname) > 1): familyname = tempname[1] firstname = tempname[0] elif (len(tempname) == 1): familyname = fullname #NB: Code is being migrated to tutorweb.quiz #student = StudentInformation(candidateId, ranid, firstname, familyname, email) #student.addToDataBase() # now find the student just added studentinfo = studlocator.student_by_randomnumber(ranid) # now find classinfo classlocator = getUtility(IClassLocator) # should check if databaseid is not empty string classinfo = classlocator.class_by_id(int( self.getClassDatabaseId())) #check if have date start = self.getEffectiveDate() stop = self.getExpirationDate() # maybe should set default values in initialize try: '''check if start has been set''' i = len(start) except: start = 0 try: '''check if stop has been set''' i = len(stop) except: stop = 0 #NB: Code is being migrated to tutorweb.quizdb #registration = ClassRegistrationInformation(studentinfo, classinfo, start, stop) #registration.addToDataBase() return True else: return False def getEnrolledStudents(self): """return all enrolled students""" stud = self.getStudents() if (type(stud) == type('itsastring')): l = [] l.append(stud) sortedlist = l.sort() return sortedlist else: sortedlist = self.getStudents().sort() return self.getStudents().sort() def getInstructors(self): """return all instructors""" stud = self.getInstructor() if (type(stud) == type('itsastring')): l = [] l.append(stud) return l else: return stud def getAvailableStudents(self): """return all registered members of the tutor-web""" # FIXME this could be far too big a list to be return in one go # needs to return only partly pm = self.portal_membership pair = [] for memberId in pm.listMemberIds(): member = pm.getMemberById(memberId) userfull = member.getProperty('fullname') pair.append((memberId, userfull)) return DisplayList(pair) def getAvailableStudents2(self): """return all registered users of the tutor-web""" pm = self.portal_membership results = pm.listMembers() pair = [] for r in results: pair.append((r.UID, r.Title)) return DisplayList(pair) def getAvailableStudents1(self): """return all registered members of the tutor-web""" memb = self.portal_membership portal_users = getToolByName(self, "acl_users") membership = getToolByName(self, 'portal_membership') #Beware if hundreds of students this is very expensive! # need to use search tool results = membership.listMembers() numstuds = str(len(results)) for r in results: r1 = r.getUser() userid = r1.getId() userfull1 = membership.getMemberById(userid) userfull = userfull1.getProperty('fullname') pair = [] for c in results: r = c.getUser() pair.append((r.getUserName(), r.getId())) return DisplayList(pair) def portalUrl(self): """Return the url of the site which the class belongs to """ portal = getToolByName(self, 'portal_url').getPortalObject() return portal def isLoggedOn(self): """True of user has logged in to the tutor-web else Fase""" mtool = getToolByName(self, 'portal_membership') if mtool.isAnonymousUser(): return False else: return True security.declarePrivate('initializeObject') def initializeObject(self): """Called after class has been created for the first time.""" self.tryWorkflowAction("publish", ignoreErrors=True) '''add school to database when school is created''' # get correctschoolinformation parent = aq_parent(self) #schoollocator = getUtility(ISchoolLocator) #schoolinformation = schoollocator.school_by_id(int(parent.getDatabaseId())) # set char set might have for example icelandic letters in title tit = self.getTitle() if not isinstance(tit, unicode): charset = self.getCharset() tit = unicode(tit, charset) self.setTitle(tit) email = self.getContactInformation() if not isinstance(email, unicode): charset = self.getCharset() email = unicode(email, charset) self.setTitle(email) # create class and add to database #NB: This is knobbled for now, as code migrates to tutorweb.quizdb #myclass = ClassInformation(schoolinformation, tit, email) #myclass.addToDataBase() #add database id #self.setClassDatabaseId(str(myclass.class_id)) parent = aq_parent(self) try: parent.orderObjects("id") parent.plone_utils.reindexOnReorder(parent) except: raise 'Failed to create class ' + self.getTitle( ) + ' not able to reorder classes' def editedObject(self, objtype=None): '''if class name changed, change also in database''' # Need to make sure that class name is unique before # looking for class by name - have added a validator # first get handle on the school from sql # well if copy/paste school then the title will not change #classlocator = getUtility(IClassLocator) #classlocator.updateName(self.getClassDatabaseId(), self.getTitle(), self.getContactInformation()) tit = self.getTitle() if not isinstance(tit, unicode): charset = self.getCharset() tit = unicode(tit, charset) self.setTitle(tit) # set char set email = self.getContactInformation() if not isinstance(email, unicode): charset = self.getCharset() email = unicode(email, charset) self.setContactInformation(email) classlocator = getUtility(IClassLocator) classlocator.updateName(self.getClassDatabaseId(), tit, email) security.declarePrivate('tryWorkflowAction') def tryWorkflowAction(self, action, ignoreErrors=False, comment=None): """try to change actions for class""" 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 canSeeQuestions(self): """if current user has the role of a manager, editor, owner or belongs to the group: teacher then return True else False""" try: user = getSecurityManager().getUser() groups = user.getGroups() if (user.has_role('Manager')): return True elif (user.has_role('Editor')): return True elif (user.has_role('Owner')): return True elif ('teacher' in groups): return True else: return False except: '''could not establish who user is''' return False security.declareProtected(View, 'computeNumTutorials') def computeNumTutorials(self): """find number of tutorials which belong to this class""" refs = self.getRawTutorials() return len(refs) def updateSlideMaterial(self): """Update all slides for every tutorial/lecture belonging to the class.""" tuts = self.getTutorials() for tut in tuts: tmp = tut.updateSlideMaterial() def getFullName(self, userid): """Return the full name of a user based on given id""" # FIXME what if id is not valid??? if PLONE_VERSION == 3: ecq_tool = getToolByName(self, 'ecq_tool') return ecq_tool.getFullNameById(userid) else: parent = aq_parent(self) return parent.getFullName(userid)
from zope.interface import implements schema = Contact.schema.copy() + Schema(( StringField( 'DoctorID', required=1, searchable=True, widget=StringWidget(label=_('Doctor ID'), ), ), ReferenceField( 'PrimaryReferrer', vocabulary='get_clients_vocabulary', allowed_types=('Client', ), relationship='DoctorClient', required=0, widget=SelectionWidget( format='select', description=_('Associate the doctor to a client. ' 'This doctor will not be accessible from ' 'other clients.'), label=_('Client'), ), ), )) class Doctor(Contact): implements(IDoctor) security = ClassSecurityInfo() displayContentsTab = False schema = schema
from Products.Archetypes.public import Schema from Products.Archetypes.public import StringField from Products.Archetypes.public import registerType from Products.CMFPlone.utils import safe_unicode from bika.lims.browser.fields import DurationField from bika.lims.browser.fields import UIDReferenceField from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.interfaces import ISamplePartition from zope.interface import implements schema = BikaSchema.copy() + Schema(( ReferenceField( 'Container', allowed_types=('Container', ), relationship='SamplePartitionContainer', required=1, multiValued=0, ), ReferenceField( 'Preservation', allowed_types=('Preservation', ), relationship='SamplePartitionPreservation', required=0, multiValued=0, ), BooleanField('Separate', default=False), UIDReferenceField( 'Analyses', allowed_types=('Analysis', ), required=0,
schema = BikaSchema.copy() + Schema(( # Methods associated to the Reflex rule # In the first place the user has to choose from a drop-down list the # method which the rules for the analysis service will be bind to. After # selecting the method, the system will display another list in order to # choose the analysis service to add the rules when using the selected # method. ReferenceField( 'Method', required=1, multiValued=0, vocabulary_display_path_bound=sys.maxint, vocabulary='_getAvailableMethodsDisplayList', allowed_types=('Method',), relationship='ReflexRuleMethod', referenceClass=HoldingReference, widget=SelectionWidget( label=_("Methods"), format='select', description=_( "Select the method which the rules for the analysis " "service will be bound to."), ) ), ReflexRuleField('ReflexRules',), )) schema['description'].widget.visible = True schema['description'].widget.label = _("Description") schema['description'].widget.description = _("")
ReferenceField( 'PrimaryReferrer', allowed_types=('Client', ), relationship='DoctorClient', required=1, widget=ReferenceWidget( label=_("Client"), size=30, catalog_name="portal_catalog", base_query={ "is_active": True, "sort_limit": 30, "sort_on": "sortable_title", "sort_order": "ascending" }, colModel=[{ "columnName": "Title", "label": _("Title"), "width": "30", "align": "left" }, { "columnName": "getProvince", "label": _("Province"), "width": "30", "align": "left" }, { "columnName": "getDistrict", "label": _("District"), "width": "30", "align": "left" }], showOn=True, ), ),
description=_( "Specify the size of the Worksheet, e.g. corresponding to a " "specific instrument's tray size. " "Then select an Analysis 'type' per Worksheet position." "Where QC samples are selected, also select which Reference " "Sample should be used." "If a duplicate analysis is selected, indicate which sample " "position it should be a duplicate of"), )), ReferenceField( "Service", schemata="Analyses", required=0, multiValued=1, allowed_types=("AnalysisService", ), relationship="WorksheetTemplateAnalysisService", referenceClass=HoldingReference, widget=ServicesWidget( label=_("Analysis Service"), description=_( "Select which Analyses should be included on the Worksheet"), )), ReferenceField( "RestrictToMethod", schemata="Description", required=0, vocabulary_display_path_bound=sys.maxint, vocabulary="_getMethodsVoc", allowed_types=("Method", ), relationship="WorksheetTemplateMethod", referenceClass=HoldingReference,
default_output_type='text/x-html-safe', allowable_content_types=('text/html', 'text/plain'), accessor='getText', read_permission=ViewBoard, write_permission=EditComment, widget=RichWidget(description="Enter comment body.", description_msgid="help_text", label="Text", label_msgid="label_text", i18n_domain='ploneboard', rows=5, helper_css=('ploneboard.css', ))), ReferenceField( name='reply_to', accessor='inReplyTo', # Suboptimal accessor naming here... edit_accessor='inReplyToUID', mutator='setInReplyTo', relationship=REPLY_RELATIONSHIP, widget=ReferenceWidget(visible=False), ), BooleanField( 'displayAttachments', mode="w", default=True, languageIndependent=0, widget=AttachmentsManagerWidget(label=_("label_displayAttachments", default=u"Attachments"), expanded=True), ), BooleanField( 'displayImages', mode="w",
"Default Emails to CC all published Samples for this client"), visible={ "edit": "visible", "view": "visible", }, ), ), ReferenceField( "DefaultCategories", schemata="Preferences", required=0, multiValued=1, vocabulary="getAnalysisCategories", vocabulary_display_path_bound=sys.maxint, allowed_types=("AnalysisCategory",), relationship="ClientDefaultCategories", widget=ReferenceWidget( checkbox_bound=0, label=_("Default categories"), description=_( "Always expand the selected categories in client views"), ), ), ReferenceField( "RestrictedCategories", schemata="Preferences", required=0, multiValued=1, vocabulary="getAnalysisCategories", validators=("restrictedcategoriesvalidator",),
visible=False, label=_("Batch ID"), )), ReferenceField( 'Client', required=0, allowed_types=('Client', ), relationship='BatchClient', widget=ReferenceWidget( label=_("Client"), size=30, visible=True, base_query={'review_state': 'active'}, showOn=True, colModel=[{ 'columnName': 'UID', 'hidden': True }, { 'columnName': 'Title', 'width': '60', 'label': _('Title') }, { 'columnName': 'ClientID', 'width': '20', 'label': _('Client ID') }], ), ), StringField('ClientBatchID', required=0, widget=StringWidget(label=_("Client Batch ID"))),
# Instruments associated to the AS # List of instruments capable to perform the Analysis Service. The # Instruments selected here are displayed in the Analysis Request # Add view, closer to this Analysis Service if selected. # - If InstrumentEntry not checked, hide and unset # - If InstrumentEntry checked, set the first selected and show ReferenceField('Instruments', schemata="Method", required=0, multiValued=1, vocabulary_display_path_bound=sys.maxint, vocabulary='_getAvailableInstrumentsDisplayList', allowed_types=('Instrument',), relationship='AnalysisServiceInstruments', referenceClass=HoldingReference, widget=MultiSelectionWidget( label=_("Instruments"), description=_("More than one instrument can do an " "Analysis Service. The instruments " "selected here are displayed in the " "Analysis Request creation view for its " "selection when this Analysis Service is " "selected."), ) ), # Default instrument to be used. # Gets populated with the instruments selected in the multiselection # box above. # Behavior controlled by js depending on ManualEntry/Instruments: # - Populate dynamically with selected Instruments # - If InstrumentEntry checked, set first selected instrument
searchable=True, widget=StringWidget(label=_('Client Reference'), ), ) Contact = ReferenceField( 'Contact', allowed_types=('Contact', ), relationship='SampleImportContact', default_method='getContactUIDForUser', referenceClass=HoldingReference, vocabulary_display_path_bound=sys.maxint, widget=ReferenceWidget( label=_('Primary Contact'), size=20, visible=True, base_query={'is_active': True}, showOn=True, popup_width='300px', colModel=[{ 'columnName': 'UID', 'hidden': True }, { 'columnName': 'Fullname', 'width': '100', 'label': _('Name') }], ), ) Batch = ReferenceField( 'Batch', allowed_types=('Batch', ),
'SamplingFrequency', vocabulary_display_path_bound=sys.maxint, widget=DurationWidget( label=_("Sampling Frequency"), description= _("If a sample is taken periodically at this sample point, enter frequency here, e.g. weekly" ), ), ), ReferenceField( 'SampleTypes', required=0, multiValued=1, allowed_types=('SampleType', ), vocabulary='SampleTypesVocabulary', relationship='SamplePointSampleType', widget=BikaReferenceWidget( label=_("Sample Types"), description=_("The list of sample types that can be collected " "at this sample point. If no sample types are " "selected, then all sample types are available."), ), ), BooleanField( 'Composite', default=False, widget=BooleanWidget( label=_("Composite"), description= _("Check this box if the samples taken at this point are 'composite' " "and put together from more than one sub sample, e.g. several surface " "samples from a dam mixed together to be a representative sample for the dam. "
from bika.lims.browser.widgets import ReferenceWidget as BikaReferenceWidget from bika.lims.config import PROJECTNAME from bika.lims.content.bikaschema import BikaSchema from bika.lims.interfaces import ICancellable from bika.lims.interfaces import ISupplyOrder schema = BikaSchema.copy() + Schema(( ReferenceField( 'Contact', required=1, vocabulary_display_path_bound=sys.maxsize, allowed_types=('Contact',), referenceClass=HoldingReference, relationship='SupplyOrderContact', widget=BikaReferenceWidget( render_own_label=True, showOn=True, colModel=[ {'columnName': 'UID', 'hidden': True}, {'columnName': 'Fullname', 'width': '50', 'label': _('Name')}, {'columnName': 'EmailAddress', 'width': '50', 'label': _('Email Address')}, ], ), ), StringField('OrderNumber', required=1, searchable=True, widget=StringWidget( label=_("Order Number"), ), ),
from Products.CMFCore.utils import getToolByName from zope.interface import implements schema = BikaSchema.copy() + Schema(( ReferenceField( "SamplePoint", vocabulary_display_path_bound=sys.maxint, allowed_types=("SamplePoint", ), relationship="ARTemplateSamplePoint", referenceClass=HoldingReference, accessor="getSamplePoint", edit_accessor="getSamplePoint", mutator="setSamplePoint", widget=ReferenceWidget( label=_("Sample Point"), description=_("Location where sample is collected"), visible={ "edit": "visible", "view": "visible", "add": "visible", "secondary": "invisible", }, catalog_name="bika_setup_catalog", base_query={"is_active": True}, showOn=True, ), ), ComputedField( "SamplePointUID", expression= "context.Schema()['SamplePoint'].get(context) and context.Schema()['SamplePoint'].get(context).UID() or ''",
'use_schedule_note', default=False, searchable=False, widget=BooleanWidget( label='Include a schedule note?', description= 'Check this box, and fill in the blank below, to include a special note regarding this event\'s scheduling.' ), ), ReferenceField( 'location', searchable=True, write_permission=ChangeEvents, relationship='Location', multiValued=False, widget=ReferenceBrowserWidget( description="", description_msgid="help_event_location", label="Event Location", label_msgid="label_event_location", i18n_domain="plone", ), ), TextField( 'text', required=False, searchable=True, widget=RichWidget( description="", description_msgid="help_event_announcement", label="Event Announcement", label_msgid="label_event_announcement",