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',)
        },)
Example #3
0
# 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

Example #4
0
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"),
        ),
    ),
Example #6
0
"""
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',
        ),
    ),
))

Example #8
0
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)
Example #9
0
         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", ),
Example #10
0
         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=
Example #11
0
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,
))
Example #12
0
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", ),
Example #13
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   
Example #14
0
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',
            ),
        ),
    ))
Example #15
0
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''',
Example #16
0
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)
Example #17
0
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
Example #18
0
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,
Example #19
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 = _("")

Example #20
0
 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,
     ),
 ),
Example #21
0
         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",
Example #23
0
                "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",),
Example #24
0
         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"))),
Example #25
0
 # 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
Example #26
0
    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', ),
Example #27
0
     '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. "
Example #28
0
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"),
                    ),
                ),
Example #29
0
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",